Skip to content

Commit

Permalink
Merge pull request #9 from iknow/static-cache-paths
Browse files Browse the repository at this point in the history
Static cache paths for individual caches
  • Loading branch information
chrisandreae authored Mar 28, 2024
2 parents 68de6e0 + f47a65e commit b2a8375
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 29 deletions.
59 changes: 46 additions & 13 deletions lib/iknow_cache.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'active_support/version'

class IknowCache
Config = Struct.new(:logger, :cache)

Expand All @@ -18,11 +20,11 @@ def cache(cache)
end

def self.configured?
! config.nil?
!config.nil?
end

def self.configure!(&block)
raise ArgumentError.new("Already configured!") if configured?
raise ArgumentError.new('Already configured!') if configured?

config = Config.new
ConfigWriter.new(config).instance_eval(&block)
Expand Down Expand Up @@ -69,8 +71,8 @@ def register_child_group(name, key_name, default_options: nil, static_version: 1
group
end

def register_cache(name, cache_options: nil)
c = Cache.new(self, name, cache_options)
def register_cache(name, static_version: nil, cache_options: nil)
c = Cache.new(self, name, static_version, cache_options)
@caches << c
c
end
Expand Down Expand Up @@ -193,12 +195,13 @@ def version_path_string(parent_path)
class Cache
DEBUG = false

attr_reader :name, :cache_options, :cache_group
attr_reader :name, :static_version, :cache_options, :cache_group

def initialize(cache_group, name, cache_options)
@cache_group = cache_group
@name = name
@cache_options = IknowCache.merge_options(cache_group.default_options, cache_options).try { |x| x.dup.freeze }
def initialize(cache_group, name, static_version, cache_options)
@cache_group = cache_group
@name = name
@static_version = static_version
@cache_options = IknowCache.merge_options(cache_group.default_options, cache_options).try { |x| x.dup.freeze }
end

def fetch(key, parent_path: nil, **options, &block)
Expand Down Expand Up @@ -232,6 +235,19 @@ def delete(key, parent_path: nil, **options)
IknowCache.cache.delete(p, IknowCache.merge_options(cache_options, options))
end

def fetch_multi(keys, write_options = nil)
results = read_multi(keys)

missing_keys = keys - results.keys
if missing_keys.present?
loaded_results = yield(missing_keys)
write_multi(loaded_results, write_options)
results.merge!(loaded_results)
end

results
end

def read_multi(keys)
return {} if keys.blank?

Expand All @@ -240,9 +256,7 @@ def read_multi(keys)

IknowCache.logger.debug("Cache Multi-Read: #{key_paths.values.inspect}") if DEBUG
raw = IknowCache.cache.read_multi(*key_paths.values)
vs = raw.each_with_object({}) do |(path, value), h|
h[path_keys[path]] = value
end
vs = raw.transform_keys { |path| path_keys[path] }
IknowCache.logger.debug("=> #{vs.inspect}") if DEBUG
vs
end
Expand All @@ -259,6 +273,23 @@ def write_multi(entries, options = nil)
end
end

if Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new('6.1')
def delete_multi(keys, **options)
return if keys.blank?

key_paths = path_multi(keys)

IknowCache.logger.debug("Cache Delete Multi: #{key_paths}") if DEBUG
IknowCache.cache.delete_multi(key_paths.values, IknowCache.merge_options(cache_options, options))
end
else
def delete_multi(keys, **options)
keys.each do |key|
delete(key, **options)
end
end
end

def key
cache_group.key
end
Expand All @@ -277,7 +308,9 @@ def path_multi(keys)
end

def path_string(group_path)
"#{group_path}/#{self.name}"
path = "#{group_path}/#{self.name}"
path = "#{path}/#{self.static_version}" if static_version
path
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/iknow_cache/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
class IknowCache
VERSION = '1.2.0'
VERSION = '1.2.1'
end
79 changes: 64 additions & 15 deletions test/iknow_cache_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'test_helper'

class IknowCache::Test < MiniTest::Test
class IknowCache::Test < Minitest::Test
def setup
IknowCache.cache.clear
@root = IknowCache::CacheGroup::ROOT_PATH
Expand Down Expand Up @@ -36,6 +36,12 @@ def test_cache_path_key
assert_equal("#{@root}/group/1/1/10/store", cache.send(:path, cache.key.new(10)))
end

def test_statically_versioned_cache_path
group = IknowCache.register_group(:group, :id)
cache = group.register_cache(:store, static_version: 100)
assert_equal("#{@root}/group/1/1/10/store/100", cache.send(:path, cache.key.new(10)))
end

def test_null_key
group = IknowCache.register_group(:group, :id)
ex = assert_raises(ArgumentError) do
Expand Down Expand Up @@ -68,7 +74,7 @@ def test_path_multi_hash
childgroup.path(parentid: 10, childid: 1)
childgroup.invalidate_cache_group(parentid: 10)

paths = childgroup.path_multi([{parentid: 10, childid: 20}, {parentid: 11, childid: 21}])
paths = childgroup.path_multi([{ parentid: 10, childid: 20 }, { parentid: 11, childid: 21 }])

expected = {
{ parentid: 10, childid: 20 } => "#{@root}/parentgroup/1/1/10/childgroup/1/2/20",
Expand Down Expand Up @@ -99,7 +105,6 @@ def test_path_multi_key
assert_equal(expected, paths)
end


def test_invalidate_group
group = IknowCache.register_group(:group, :id)
assert_equal("#{@root}/group/1/1/10", group.path(id: 10))
Expand All @@ -116,51 +121,95 @@ def test_invalidate_child_group
assert_equal("#{@root}/parentgroup/5/1/11/childgroup/6/1/20", childgroup.path(parentid: 11, childid: 20))
end


def test_access
group = IknowCache.register_group(:group, :id)
cache = group.register_cache(:store)
key = { id: 1 }

assert_nil(cache.read(key))

cache.write(key, "hello")
cache.write(key, 'hello')

assert_equal("hello", cache.read(key))
assert_equal('hello', cache.read(key))

assert_equal("hello", cache.fetch(key){ "goodbye" })
assert_equal('hello', cache.fetch(key) { 'goodbye' })

cache.delete(key)

assert_nil(cache.read(key))

assert_equal("goodbye", cache.fetch(key){ "goodbye" })
assert_equal('goodbye', cache.fetch(key) { 'goodbye' })
end

def test_access_multi
group = IknowCache.register_group(:group, :id)
cache = group.register_cache(:store)

data = {{id: 1} => "hello",
{id: 2} => "goodbye"}
data = {
{ id: 1 } => 'hello',
{ id: 2 } => 'goodbye',
}

cache.write_multi(data)

values = cache.read_multi(data.keys)
assert_equal(data, values)
end

def test_fetch_multi
group = IknowCache.register_group(:group, :id)
cache = group.register_cache(:store)

data = {
{ id: 1 } => 'hello',
{ id: 2 } => 'goodbye',
}

new_data = {
{ id: 3 } => 'added',
{ id: 4 } => 'extra',
}

all_data = data.merge(new_data)

cache.write_multi(data)

cache.fetch_multi(all_data.keys) do |missing_keys|
assert_equal(new_data.keys, missing_keys)
new_data
end

values = cache.read_multi(all_data.keys)
assert_equal(all_data, values)
end

def test_delete_multi
group = IknowCache.register_group(:group, :id)
cache = group.register_cache(:store)

data = {
{ id: 1 } => 'hello',
{ id: 2 } => 'goodbye',
}

cache.write_multi(data)
cache.delete_multi(data.keys)
values = cache.read_multi(data.keys)

assert_equal({}, values)
end

def test_delete_from_group
group = IknowCache.register_group(:group, :id)
cache = group.register_cache(:store)

cache.write({id: 1}, "hello")
cache.write({id: 2}, "goodbye")
cache.write({ id: 1 }, 'hello')
cache.write({ id: 2 }, 'goodbye')

group.delete_all({id: 1})
group.delete_all({ id: 1 })

assert_nil(cache.read({id: 1}))
assert_equal("goodbye", cache.read({id: 2}))
assert_nil(cache.read({ id: 1 }))
assert_equal('goodbye', cache.read({ id: 2 }))
end

def test_double_configre
Expand Down

0 comments on commit b2a8375

Please sign in to comment.