Class: Tina4::QueryCache
- Inherits:
-
Object
- Object
- Tina4::QueryCache
- Defined in:
- lib/tina4/cache.rb
Overview
In-memory TTL cache with tag-based invalidation.
Matches the Python / PHP / Node.js QueryCache API for cross-framework parity. Thread-safe via an internal Mutex.
Usage:
cache = Tina4::QueryCache.new(default_ttl: 60, max_size: 1000)
cache.set("key", "value", ttl: 30, tags: ["users"])
cache.get("key") # => "value"
cache.clear_tag("users")
Defined Under Namespace
Classes: CacheEntry
Class Method Summary collapse
-
.query_key(sql, params = nil) ⇒ String
Generate a stable cache key from a SQL query and params.
Instance Method Summary collapse
-
#clear ⇒ Object
Clear all entries from the cache.
-
#clear_tag(tag) ⇒ Integer
Clear all entries with a given tag.
-
#delete(key) ⇒ Boolean
Delete a key from the cache.
-
#get(key, default = nil) ⇒ Object?
Retrieve a cached value.
-
#has?(key) ⇒ Boolean
Check if a key exists and is not expired.
-
#initialize(default_ttl: 300, max_size: 1000) ⇒ QueryCache
constructor
A new instance of QueryCache.
-
#remember(key, ttl, &block) ⇒ Object
Fetch from cache, or compute and store.
-
#set(key, value, ttl: nil, tags: []) ⇒ Object
Store a value with optional TTL and tags.
-
#size ⇒ Integer
Current number of entries in the cache.
-
#sweep ⇒ Integer
Remove all expired entries.
Constructor Details
#initialize(default_ttl: 300, max_size: 1000) ⇒ QueryCache
Returns a new instance of QueryCache.
18 19 20 21 22 23 |
# File 'lib/tina4/cache.rb', line 18 def initialize(default_ttl: 300, max_size: 1000) @default_ttl = default_ttl @max_size = max_size @store = {} @mutex = Mutex.new end |
Class Method Details
.query_key(sql, params = nil) ⇒ String
Generate a stable cache key from a SQL query and params. Mirrors SQLTranslator.query_key for direct use on QueryCache.
149 150 151 152 |
# File 'lib/tina4/cache.rb', line 149 def self.query_key(sql, params = nil) raw = params ? "#{sql}|#{params.inspect}" : sql "query:#{Digest::SHA256.hexdigest(raw)}" end |
Instance Method Details
#clear ⇒ Object
Clear all entries from the cache.
93 94 95 |
# File 'lib/tina4/cache.rb', line 93 def clear @mutex.synchronize { @store.clear } end |
#clear_tag(tag) ⇒ Integer
Clear all entries with a given tag.
101 102 103 104 105 106 107 |
# File 'lib/tina4/cache.rb', line 101 def clear_tag(tag) @mutex.synchronize do keys_to_remove = @store.select { |_k, v| v..include?(tag) }.keys keys_to_remove.each { |k| @store.delete(k) } keys_to_remove.size end end |
#delete(key) ⇒ Boolean
Delete a key from the cache.
86 87 88 89 90 |
# File 'lib/tina4/cache.rb', line 86 def delete(key) @mutex.synchronize do !@store.delete(key).nil? end end |
#get(key, default = nil) ⇒ Object?
Retrieve a cached value. Returns nil if expired or missing.
50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/tina4/cache.rb', line 50 def get(key, default = nil) @mutex.synchronize do entry = @store[key] return default unless entry if Time.now.to_f > entry.expires_at @store.delete(key) return default end entry.value end end |
#has?(key) ⇒ Boolean
Check if a key exists and is not expired.
68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/tina4/cache.rb', line 68 def has?(key) @mutex.synchronize do entry = @store[key] return false unless entry if Time.now.to_f > entry.expires_at @store.delete(key) return false end true end end |
#remember(key, ttl, &block) ⇒ Object
Fetch from cache, or compute and store.
127 128 129 130 131 132 133 134 |
# File 'lib/tina4/cache.rb', line 127 def remember(key, ttl, &block) cached = get(key) return cached unless cached.nil? value = block.call set(key, value, ttl: ttl) value end |
#set(key, value, ttl: nil, tags: []) ⇒ Object
Store a value with optional TTL and tags.
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/tina4/cache.rb', line 31 def set(key, value, ttl: nil, tags: []) ttl ||= @default_ttl expires_at = Time.now.to_f + ttl @mutex.synchronize do # Evict oldest if at capacity if @store.size >= @max_size && !@store.key?(key) oldest_key = @store.keys.first @store.delete(oldest_key) end @store[key] = CacheEntry.new(value, expires_at, ) end end |
#size ⇒ Integer
Current number of entries in the cache.
139 140 141 |
# File 'lib/tina4/cache.rb', line 139 def size @mutex.synchronize { @store.size } end |
#sweep ⇒ Integer
Remove all expired entries.
112 113 114 115 116 117 118 119 |
# File 'lib/tina4/cache.rb', line 112 def sweep @mutex.synchronize do now = Time.now.to_f keys_to_remove = @store.select { |_k, v| now > v.expires_at }.keys keys_to_remove.each { |k| @store.delete(k) } keys_to_remove.size end end |