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: 50 * 1024 * 1024 # 50MB max size
)
# 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: 10 * 1024 * 1024) ⇒ 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: 10 * 1024 * 1024) ⇒ SqliteStore
Initialize the SQLite store.
55 56 57 58 59 60 61 62 63 64 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 55 def initialize(path, version, loog: Loog::NULL, maxsize: 10 * 1024 * 1024) 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 = maxsize end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
47 48 49 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 47 def path @path end |
Instance Method Details
#all ⇒ Array<Array>
Get all entries from the cache.
119 120 121 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 119 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.
109 110 111 112 113 114 115 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 109 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.
80 81 82 83 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 80 def delete(key) perform { _1.execute('DELETE FROM cache WHERE key = ?', [key]) } nil end |
#read(key) ⇒ Object?
Read a value from the cache.
69 70 71 72 73 74 75 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 69 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) JSON.parse(value) if value 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.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/fbe/middleware/sqlite_store.rb', line 91 def write(key, value) return if value.is_a?(Array) && value.any? do |vv| req = JSON.parse(vv[0]) req['url'].include?('?') || req['method'] != 'get' end value = JSON.dump(value) return if value.bytesize > 10_000 perform do |t| t.execute(" INSERT INTO cache(key, value, touched_at) VALUES(?1, ?2, ?3)\n ON CONFLICT(key) DO UPDATE SET value = ?2, touched_at = ?3\n SQL\n end\n nil\nend\n", [key, value, Time.now.utc.iso8601]) |