cache-object 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1353358a8c97cf8dae4728bb24db9b369507b7ce
4
- data.tar.gz: 990bdcf05d78a4108349e951968f2000d036237c
3
+ metadata.gz: e8ed3e3acf8e4c9fe23e4a3d0f73b067e1570318
4
+ data.tar.gz: d7f3afcb8be6c0d3065c97e7a1e7f027c25621bf
5
5
  SHA512:
6
- metadata.gz: 990c15962eb6c8584c1be9472e568de3907c55cfe62f378312b4aba26b3558aaa04abfcc3b4ad7a263c18466974389772478849324ad42307b986935d974f9a2
7
- data.tar.gz: 4f987b2214a753daab449ff3572eaee7f61942ceeced694f7c7142d09c4cf868937c78ef3b055bd3c36ab5c990b251348dff26a1f905d0b8434e4005894724d7
6
+ metadata.gz: b77a6a97aa5e46e6d9d01e16f97fd1e9f724c7029fc21c230ffc622f7bb9b67545cb81407b7010063329f5a3f9b881d949aafc3f1aebdcb3b00ef867097fbdb1
7
+ data.tar.gz: a0418a92720e49b01648b7bc6730f6d56070d8919c5845e8e32292de0d51197405521053952382d5ccde59e7925382f1a75ef45decde9e96fc4736ba14a58fa0
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rake"
25
25
 
26
26
  spec.add_development_dependency "rspec", ">= 3.0"
27
+ spec.add_development_dependency "rspec-collection_matchers", ">= 1.0"
27
28
  spec.add_development_dependency "guard"
28
29
  spec.add_development_dependency "guard-rspec"
29
30
  spec.add_development_dependency "sqlite3"
@@ -3,6 +3,7 @@ require 'cache/object/config'
3
3
  require 'cache/object/active_record'
4
4
  require 'cache/object/adapter'
5
5
  require 'cache/object/key_generator'
6
+ require 'cache/object/multi_get'
6
7
 
7
8
  module Cache
8
9
  module Object
@@ -22,10 +22,6 @@ module Cache
22
22
  end
23
23
 
24
24
  def load_from_cache(attributes)
25
- attributes.each_pair do |key, value|
26
- attributes[key] = value
27
- end
28
-
29
25
  @attributes = self.class.initialize_attributes(attributes)
30
26
  @relation = nil
31
27
 
@@ -55,7 +51,6 @@ module Cache
55
51
  module ClassMethods
56
52
  def _load(args)
57
53
  attributes = Marshal.load(args)
58
-
59
54
  object = allocate
60
55
  object.load_from_cache(attributes)
61
56
  object
@@ -73,6 +68,10 @@ module Cache
73
68
  end
74
69
  end
75
70
 
71
+ def fetch_all(ids)
72
+ Cache::Object::MultiGet.new(self).fetch_all(ids)
73
+ end
74
+
76
75
  def object_cache_on(*attrs)
77
76
  self._object_cache_attr_mappings << attrs
78
77
  define_singleton_method("find_by_#{attrs.join('_and_')}") do |*args|
@@ -4,7 +4,7 @@ module Cache
4
4
  attr_reader :store
5
5
 
6
6
  def initialize(store)
7
- raise "Cache Store is nil" unless store
7
+ raise "Cache Store is nil, please initialize" unless store
8
8
  @store = store
9
9
  end
10
10
 
@@ -32,6 +32,10 @@ module Cache
32
32
  &block)
33
33
  end
34
34
 
35
+ def read_multi(args)
36
+ store.read_multi(*args)
37
+ end
38
+
35
39
  private
36
40
 
37
41
  def ttl
@@ -6,6 +6,8 @@ module Cache
6
6
  def initialize
7
7
  self.enabled = true
8
8
  self.ttl = 86400
9
+ self.adapter = nil
10
+ self.cache = nil
9
11
  end
10
12
 
11
13
  def adapter
@@ -9,9 +9,8 @@ module Cache
9
9
 
10
10
  def mapping_cache_keys
11
11
  mappings.map do |mapping|
12
- attributes = mapping.inject({}) do |memo, attr|
13
- memo[attr] = instance.send(attr)
14
- memo
12
+ attributes = {}.tap do |obj|
13
+ mapping.each { |attr| obj[attr] = instance.send(attr) }
15
14
  end
16
15
  KeyGenerator.key_for_mapping(instance.class.name, attributes)
17
16
  end
@@ -0,0 +1,36 @@
1
+ module Cache
2
+ module Object
3
+ class MultiGet
4
+ attr_reader :clazz
5
+
6
+ def initialize(clazz)
7
+ @clazz = clazz
8
+ end
9
+
10
+ def fetch_all(ids)
11
+ objs = cached_objects(ids)
12
+ remaining = missed_ids(ids, objs)
13
+ return objs if remaining.empty?
14
+ objs + load_from_db(remaining)
15
+ end
16
+
17
+ def load_from_db(ids)
18
+ primary_key = clazz.primary_key.to_sym
19
+ clazz.where(primary_key => ids).to_a.each(&:write_cache!)
20
+ end
21
+
22
+ def object_keys(ids)
23
+ ids.map { |id| Cache::Object::KeyGenerator.key_for_object(clazz.name, id) }
24
+ end
25
+
26
+ def cached_objects(ids)
27
+ keys = object_keys(ids)
28
+ Cache::Object.adapter.read_multi(keys).values
29
+ end
30
+
31
+ def missed_ids(ids, fetched_objects)
32
+ ids - fetched_objects.map(&:id)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,5 +1,5 @@
1
1
  module Cache
2
2
  module Object
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
5
5
  end
@@ -58,7 +58,6 @@ RSpec.describe Cache::Object::ActiveRecord do
58
58
  end
59
59
  end
60
60
 
61
-
62
61
  describe "caching methods" do
63
62
  describe "#write_cache" do
64
63
  it "calls write cache" do
@@ -68,7 +67,6 @@ RSpec.describe Cache::Object::ActiveRecord do
68
67
  end
69
68
  end
70
69
 
71
-
72
70
  describe "#expire_cache" do
73
71
  it "calls write cache" do
74
72
  expect(adapter_instance).to receive(:delete).with(an_instance_of(Cache::Object::InstanceDecorator))
@@ -108,6 +106,15 @@ RSpec.describe Cache::Object::ActiveRecord do
108
106
  end
109
107
  end
110
108
 
109
+ describe ".fetch_all" do
110
+ it "should call through to multi_get" do
111
+ multi_getter = double(fetch_all: true)
112
+ expect(Cache::Object::MultiGet).to receive(:new).with(clazz) { multi_getter }
113
+ expect(multi_getter).to receive(:fetch_all).with([1,2,4])
114
+ clazz.fetch_all([1, 2, 4])
115
+ end
116
+ end
117
+
111
118
  describe "object_cache_on" do
112
119
 
113
120
  it "creates_finder_methods" do
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Cache::Object::MultiGet do
4
+
5
+ let(:fake_clazz) { double(name: "MyObj", primary_key: :foo) }
6
+ let(:obj_arr) { 1.upto(3).map { |i| double(class: fake_clazz, id: i) } }
7
+ let(:multi_get) { Cache::Object::MultiGet.new(fake_clazz) }
8
+ let(:cache_store) { double("CacheStore", write: true) }
9
+ let(:adapter) { Cache::Object::Adapter.new(cache_store) }
10
+
11
+ describe "#object_keys" do
12
+ it "maps keys correctly" do
13
+ expect(multi_get.object_keys(1..3)).to eq(["MyObj-1", "MyObj-2", "MyObj-3"])
14
+ end
15
+ end
16
+
17
+ describe "#cached_objects" do
18
+ it "fetches all the mapped keys" do
19
+ expect(Cache::Object).to receive(:adapter) { adapter }
20
+ expect(adapter).to receive(:read_multi).with(["MyObj-1", "MyObj-2", "MyObj-3"]) { double(values: true) }
21
+ multi_get.cached_objects(1..3)
22
+ end
23
+ end
24
+
25
+ describe "#missed_ids" do
26
+ let(:initial_ids) { [1, 2, 3, 4, 5, 6] }
27
+ it "computes missed ids" do
28
+ expect(multi_get.missed_ids(initial_ids, obj_arr)).to eq([4, 5, 6])
29
+ end
30
+ end
31
+
32
+ describe "#load_remaining" do
33
+ it "performs missed queries" do
34
+ expect(fake_clazz).to receive(:where).with(:foo => [1, 2, 3]).once { [double(write_cache!: true)] }
35
+ multi_get.load_from_db([1, 2, 3])
36
+ end
37
+ end
38
+
39
+ describe "#fetch_all" do
40
+ describe "with all expected ids" do
41
+ it "never calls through to db" do
42
+ expect(multi_get).to receive(:cached_objects).with([1, 2, 3]) { obj_arr }
43
+ expect(multi_get).to receive(:load_from_db).never
44
+ multi_get.fetch_all([1, 2, 3])
45
+ end
46
+ end
47
+
48
+ describe "with a cache miss" do
49
+ it "calls through to db" do
50
+ expect(multi_get).to receive(:cached_objects).with([1, 2, 3]) { [ obj_arr[0] ]}
51
+ expect(multi_get).to receive(:load_from_db).with([2, 3]) { [obj_arr[1], obj_arr[2]] }
52
+ expect(multi_get.fetch_all([1, 2, 3])).to have(3).items
53
+ end
54
+ end
55
+ end
56
+
57
+ end
@@ -7,13 +7,15 @@ RSpec.describe "Caching" do
7
7
 
8
8
  before do
9
9
  CreateModelsForTest.migrate(:up)
10
+ cache = ::ActiveSupport::Cache::MemoryStore.new
10
11
  Cache::Object.configure do |c|
11
- c.cache = ::ActiveSupport::Cache::MemoryStore.new
12
+ c.cache = cache
12
13
  end
13
14
  end
14
15
 
15
16
  after do
16
17
  CreateModelsForTest.migrate(:down)
18
+ Cache::Object.instance_variable_set(:@configuration, nil)
17
19
  end
18
20
 
19
21
  let!(:user) { User.create(age: 13, name: "Bob") }
@@ -52,6 +54,30 @@ RSpec.describe "Caching" do
52
54
  end
53
55
  end
54
56
 
57
+ describe "#fetch_all" do
58
+ let!(:u1) { 1.upto(3).map { |i| User.create(age: 13, name: "name#{i}") } }
59
+ it "Should call db once for all in one read" do
60
+
61
+ expect {
62
+ User.fetch_all(u1.map(&:id))
63
+ }.to change { ActiveRecord::QueryCounter.query_count }.by(0)
64
+ end
65
+
66
+ it "Should call the db again after cache flush" do
67
+ Cache::Object.configuration.cache.clear
68
+
69
+ expect {
70
+ User.fetch_all(u1.map(&:id))
71
+ }.to change { ActiveRecord::QueryCounter.query_count }.by(1)
72
+
73
+ # Should hit cache
74
+ expect {
75
+ User.fetch_all(u1.map(&:id))
76
+ }.to change { ActiveRecord::QueryCounter.query_count }.by(0)
77
+ end
78
+ end
79
+
80
+
55
81
  describe "when user id destroyed" do
56
82
  it "tries to run a query" do
57
83
  user.destroy
@@ -74,4 +100,6 @@ RSpec.describe "Caching" do
74
100
  }.to change { ActiveRecord::QueryCounter.query_count }.by(1)
75
101
  end
76
102
  end
103
+
104
+
77
105
  end
@@ -1,15 +1,17 @@
1
1
  require 'cache/object'
2
+ require 'rspec/collection_matchers'
2
3
  RSpec.configure do |config|
3
4
 
4
- config.before do
5
+ config.before(:each) do
5
6
  Cache::Object.instance_variable_set(:@configuration, nil)
7
+ Cache::Object.instance_variable_set(:@adapter, nil)
6
8
  end
7
9
 
8
- config.after do
10
+ config.after(:each) do
9
11
  Cache::Object.instance_variable_set(:@configuration, nil)
12
+ Cache::Object.instance_variable_set(:@adapter, nil)
10
13
  end
11
14
 
12
15
  config.raise_errors_for_deprecations!
13
16
  config.disable_monkey_patching!
14
-
15
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cache-object
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Camuto
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-collection_matchers
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: guard
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -139,11 +153,13 @@ files:
139
153
  - lib/cache/object/config.rb
140
154
  - lib/cache/object/instance_decorator.rb
141
155
  - lib/cache/object/key_generator.rb
156
+ - lib/cache/object/multi_get.rb
142
157
  - lib/cache/object/version.rb
143
158
  - spec/cache/object/active_record_spec.rb
144
159
  - spec/cache/object/adapter_spec.rb
145
160
  - spec/cache/object/config_spec.rb
146
161
  - spec/cache/object/instance_decorator_spec.rb
162
+ - spec/cache/object/multi_get_spec.rb
147
163
  - spec/features/cache_object_spec.rb
148
164
  - spec/spec_helper.rb
149
165
  - spec/support/models.rb
@@ -176,6 +192,7 @@ test_files:
176
192
  - spec/cache/object/adapter_spec.rb
177
193
  - spec/cache/object/config_spec.rb
178
194
  - spec/cache/object/instance_decorator_spec.rb
195
+ - spec/cache/object/multi_get_spec.rb
179
196
  - spec/features/cache_object_spec.rb
180
197
  - spec/spec_helper.rb
181
198
  - spec/support/models.rb