Class: Fbe::Middleware::SqliteStore
- Inherits:
-
Object
- Object
- Fbe::Middleware::SqliteStore
- Defined in:
- lib/fbe/middleware/sqlite_store.rb
Overview
Persisted SQLite store for Faraday::HttpCache
This class provides a persistent cache store backed by SQLite for use with Faraday::HttpCache middleware. It’s designed to cache HTTP responses from GitHub API calls to reduce API rate limit consumption and improve performance.
Key features:
-
Automatic version management to invalidate cache on version changes
-
Size-based cache eviction (configurable, defaults to 10MB)
-
Thread-safe SQLite transactions
-
JSON serialization for cached values
-
Filtering of non-cacheable requests (non-GET, URLs with query parameters)
Usage example:
store = Fbe::Middleware::SqliteStore.new(
'/path/to/cache.db',
'1.0.0',
loog: logger,
maxsize: '50Mb'
)
# Use with Faraday
Faraday.new do |builder|
builder.use Faraday::HttpCache, store: store
end
The store automatically manages the SQLite database schema and handles cleanup operations when the database grows too large. Old entries are deleted based on their last access time to maintain the configured size limit.
- Author
-
Yegor Bugayenko ([email protected])
- Copyright
-
Copyright © 2024-2025 Zerocracy
- License
-
MIT
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Instance Method Summary collapse
-
#all ⇒ Array<Array>
Get all entries from the cache.
-
#clear ⇒ void
Clear all entries from the cache.
-
#delete(key) ⇒ nil
Delete a key from the cache.
-
#initialize(path, version, loog: Loog::NULL, maxsize: '10Mb', maxvsize: '10Kb', ttl: nil) ⇒ SqliteStore
constructor
Initialize the SQLite store.
-
#read(key) ⇒ Object?
Read a value from the cache.
-
#write(key, value) ⇒ nil
Write a value to the cache.
Constructor Details
#initialize(path, version, loog: Loog::NULL, maxsize: '10Mb', maxvsize: '10Kb', ttl: nil) ⇒ SqliteStore
Initialize the SQLite store. or ttl is not nil or not Integer or not positive
59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 59 def initialize(path, version, loog: Loog::NULL, maxsize: '10Mb', maxvsize: '10Kb', ttl: nil) raise ArgumentError, 'Database path cannot be nil or empty' if path.nil? || path.empty? dir = File.dirname(path) raise ArgumentError, "Directory #{dir} does not exist" unless File.directory?(dir) raise ArgumentError, 'Version cannot be nil or empty' if version.nil? || version.empty? @path = File.absolute_path(path) @version = version @loog = loog @maxsize = Filesize.from(maxsize.to_s).to_i @maxvsize = Filesize.from(maxvsize.to_s).to_i raise ArgumentError, 'TTL can be nil or Integer > 0' if !ttl.nil? && !(ttl.is_a?(Integer) && ttl.positive?) @ttl = ttl end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
48 49 50 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 48 def path @path end |
Instance Method Details
#all ⇒ Array<Array>
Get all entries from the cache.
132 133 134 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 132 def all perform { _1.execute('SELECT key, value FROM cache') } end |
#clear ⇒ void
This method returns an undefined value.
Clear all entries from the cache.
122 123 124 125 126 127 128 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 122 def clear perform do |t| t.execute 'DELETE FROM cache;' t.execute "UPDATE meta SET value = ? WHERE key = 'version';", [@version] end @db.execute 'VACUUM;' end |
#delete(key) ⇒ nil
Delete a key from the cache.
93 94 95 96 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 93 def delete(key) perform { _1.execute('DELETE FROM cache WHERE key = ?', [key]) } nil end |
#read(key) ⇒ Object?
Read a value from the cache.
76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 76 def read(key) value = perform do |t| t.execute('UPDATE cache SET touched_at = ?2 WHERE key = ?1;', [key, Time.now.utc.iso8601]) t.execute('SELECT value FROM cache WHERE key = ? LIMIT 1;', [key]) end.dig(0, 0) return unless value begin JSON.parse(Zlib::Inflate.inflate(value)) rescue Zlib::Error => e @loog.info("Failed to decompress cached value for key: #{key}, error: #{e.}, the key will be deleted") delete(key) end end |
#write(key, value) ⇒ nil
Values larger than 10KB are not cached
Non-GET requests and URLs with query parameters are not cached
Write a value to the cache.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 104 def write(key, value) return if value.is_a?(Array) && value.any? do |vv| req = JSON.parse(vv[0]) req['method'] != 'get' end value = Zlib::Deflate.deflate(JSON.dump(value)) return if value.bytesize > @maxvsize perform do |t| t.execute(<<~SQL, [key, value, Time.now.utc.iso8601]) INSERT INTO cache(key, value, touched_at, created_at) VALUES(?1, ?2, ?3, ?3) ON CONFLICT(key) DO UPDATE SET value = ?2, touched_at = ?3, created_at = ?3 SQL end nil end |