Class: Tina4::CacheBackends::DatabaseBackend
- Inherits:
-
BaseBackend
- Object
- BaseBackend
- Tina4::CacheBackends::DatabaseBackend
- Defined in:
- lib/tina4/cache_backends/database_backend.rb
Overview
Database backend (parity with Python _DatabaseBackend) — stores entries in a tina4_cache table in any Tina4-supported database. Zero extra infrastructure; reuses the Database layer. Its own connection has query caching disabled to avoid recursion (a cache lookup must not itself try to cache through this same backend).
Instance Method Summary collapse
- #available? ⇒ Boolean
- #clear ⇒ Object
- #delete(key) ⇒ Object
- #get(key) ⇒ Object
-
#initialize(url: nil, max_entries: 1000) ⇒ DatabaseBackend
constructor
A new instance of DatabaseBackend.
- #name ⇒ Object
- #set(key, value, ttl) ⇒ Object
- #stats ⇒ Object
Constructor Details
#initialize(url: nil, max_entries: 1000) ⇒ DatabaseBackend
Returns a new instance of DatabaseBackend.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 14 def initialize(url: nil, max_entries: 1000) @max_entries = max_entries @hits = 0 @misses = 0 @db = nil @available = false # The database backend reads TINA4_CACHE_URL (interpreted as a SQL URL), # falling back to the app's own TINA4_DATABASE_URL — cache in the DB you # already run, no extra connection var needed. url ||= env_nonempty("TINA4_CACHE_URL") || env_nonempty("TINA4_DATABASE_URL") || "sqlite://data/tina4.db" # The cache's own DB connection must not itself cache (no recursion). prev_auto = ENV["TINA4_AUTO_CACHING"] prev_db = ENV["TINA4_DB_CACHE"] ENV["TINA4_AUTO_CACHING"] = "false" ENV["TINA4_DB_CACHE"] = "false" begin @db = Tina4::Database.new(url) @db.execute( "CREATE TABLE IF NOT EXISTS tina4_cache " \ "(cache_key VARCHAR(255) PRIMARY KEY, value TEXT, expires_at DOUBLE PRECISION)" ) @available = true rescue StandardError @available = false ensure restore_env("TINA4_AUTO_CACHING", prev_auto) restore_env("TINA4_DB_CACHE", prev_db) end end |
Instance Method Details
#available? ⇒ Boolean
48 49 50 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 48 def available? @available end |
#clear ⇒ Object
89 90 91 92 93 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 89 def clear @hits = 0 @misses = 0 @db.execute("DELETE FROM tina4_cache") end |
#delete(key) ⇒ Object
83 84 85 86 87 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 83 def delete(key) existed = !@db.fetch_one("SELECT 1 AS x FROM tina4_cache WHERE cache_key = ?", [key]).nil? @db.execute("DELETE FROM tina4_cache WHERE cache_key = ?", [key]) existed end |
#get(key) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 52 def get(key) row = @db.fetch_one("SELECT value, expires_at FROM tina4_cache WHERE cache_key = ?", [key]) unless row @misses += 1 return nil end exp = row["expires_at"] || row[:expires_at] if exp && exp.to_f > 0 && Time.now.to_f > exp.to_f @db.execute("DELETE FROM tina4_cache WHERE cache_key = ?", [key]) @misses += 1 return nil end @hits += 1 raw = row["value"] || row[:value] begin JSON.parse(raw) rescue JSON::ParserError, TypeError raw end end |
#name ⇒ Object
101 102 103 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 101 def name "database" end |
#set(key, value, ttl) ⇒ Object
73 74 75 76 77 78 79 80 81 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 73 def set(key, value, ttl) exp = ttl > 0 ? Time.now.to_f + ttl : 0 serialized = JSON.generate(value) @db.execute("DELETE FROM tina4_cache WHERE cache_key = ?", [key]) @db.execute( "INSERT INTO tina4_cache (cache_key, value, expires_at) VALUES (?, ?, ?)", [key, serialized, exp] ) end |
#stats ⇒ Object
95 96 97 98 99 |
# File 'lib/tina4/cache_backends/database_backend.rb', line 95 def stats row = @db.fetch_one("SELECT COUNT(*) AS c FROM tina4_cache") c = row ? (row["c"] || row[:c]) : 0 { hits: @hits, misses: @misses, size: c.to_i, backend: "database" } end |