record-cache 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/lib/record_cache/base.rb +4 -4
- data/lib/record_cache/datastore/active_record_30.rb +1 -1
- data/lib/record_cache/datastore/active_record_31.rb +1 -1
- data/lib/record_cache/datastore/active_record_32.rb +2 -2
- data/lib/record_cache/datastore/active_record_40.rb +445 -0
- data/lib/record_cache/datastore/active_record_41.rb +446 -0
- data/lib/record_cache/strategy/full_table_cache.rb +1 -1
- data/lib/record_cache/strategy/util.rb +20 -3
- data/lib/record_cache/version.rb +1 -1
- data/spec/db/create-record-cache-db_and_user.sql +5 -0
- data/spec/db/database.yml +7 -0
- data/spec/db/schema.rb +9 -15
- data/spec/initializers/backward_compatibility.rb +32 -0
- data/spec/lib/active_record/visitor_spec.rb +1 -1
- data/spec/lib/base_spec.rb +2 -2
- data/spec/lib/dispatcher_spec.rb +1 -1
- data/spec/lib/multi_read_spec.rb +1 -1
- data/spec/lib/query_spec.rb +1 -1
- data/spec/lib/statistics_spec.rb +1 -1
- data/spec/lib/strategy/base_spec.rb +39 -39
- data/spec/lib/strategy/full_table_cache_spec.rb +18 -18
- data/spec/lib/strategy/index_cache_spec.rb +58 -52
- data/spec/lib/strategy/query_cache_spec.rb +1 -1
- data/spec/lib/strategy/unique_index_on_id_cache_spec.rb +57 -45
- data/spec/lib/strategy/unique_index_on_string_cache_spec.rb +47 -45
- data/spec/lib/strategy/util_spec.rb +49 -43
- data/spec/lib/version_store_spec.rb +1 -1
- data/spec/models/apple.rb +1 -2
- data/spec/spec_helper.rb +16 -7
- data/spec/support/matchers/hit_cache_matcher.rb +1 -1
- data/spec/support/matchers/miss_cache_matcher.rb +1 -1
- data/spec/support/matchers/use_cache_matcher.rb +1 -1
- metadata +63 -17
- data/spec/support/after_commit.rb +0 -73
@@ -1,26 +1,26 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe RecordCache::Strategy::FullTableCache do
|
3
|
+
RSpec.describe RecordCache::Strategy::FullTableCache do
|
4
4
|
|
5
5
|
it "should retrieve a Language from the cache" do
|
6
|
-
expect{ Language.where(:locale => 'en-US').
|
7
|
-
expect{ Language.where(:locale => 'en-US').
|
6
|
+
expect { Language.where(:locale => 'en-US').load }.to miss_cache(Language).on(:full_table).times(1)
|
7
|
+
expect { Language.where(:locale => 'en-US').load }.to hit_cache(Language).on(:full_table).times(1)
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should retrieve all Languages from cache" do
|
11
|
-
expect{ Language.all }.to miss_cache(Language).on(:full_table).times(1)
|
12
|
-
expect{ Language.all }.to hit_cache(Language).on(:full_table).times(1)
|
11
|
+
expect { Language.all.load }.to miss_cache(Language).on(:full_table).times(1)
|
12
|
+
expect { Language.all.load }.to hit_cache(Language).on(:full_table).times(1)
|
13
13
|
expect(Language.all.map(&:locale).sort).to eq(%w(du-NL en-GB en-US hu))
|
14
14
|
end
|
15
15
|
|
16
16
|
context "logging" do
|
17
17
|
it "should write hit to the debug log" do
|
18
|
-
Language.all
|
19
|
-
expect{ Language.all }.to log(:debug, "FullTableCache hit for model Language")
|
18
|
+
Language.all.load
|
19
|
+
expect { Language.all.load }.to log(:debug, "FullTableCache hit for model Language")
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should write miss to the debug log" do
|
23
|
-
expect{ Language.all }.to log(:debug, "FullTableCache miss for model Language")
|
23
|
+
expect{ Language.all.load }.to log(:debug, "FullTableCache miss for model Language")
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -29,38 +29,38 @@ describe RecordCache::Strategy::FullTableCache do
|
|
29
29
|
expect(Language.record_cache[:full_table].cacheable?("any query")).to be_truthy
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
context "record_change" do
|
34
34
|
before(:each) do
|
35
|
-
@Languages = Language.all
|
35
|
+
@Languages = Language.all.load
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should invalidate the cache when a record is added" do
|
39
|
-
expect{ Language.where(:locale => 'en-US').
|
39
|
+
expect{ Language.where(:locale => 'en-US').load }.to hit_cache(Language).on(:full_table).times(1)
|
40
40
|
Language.create!(:name => 'Deutsch', :locale => 'de')
|
41
|
-
expect{ Language.where(:locale => 'en-US').
|
41
|
+
expect{ Language.where(:locale => 'en-US').load }.to miss_cache(Language).on(:full_table).times(1)
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should invalidate the cache when any record is deleted" do
|
45
|
-
expect{ Language.where(:locale => 'en-US').
|
45
|
+
expect{ Language.where(:locale => 'en-US').load }.to hit_cache(Language).on(:full_table).times(1)
|
46
46
|
Language.where(:locale => 'hu').first.destroy
|
47
|
-
expect{ Language.where(:locale => 'en-US').
|
47
|
+
expect{ Language.where(:locale => 'en-US').load }.to miss_cache(Language).on(:full_table).times(1)
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should invalidate the cache when any record is modified" do
|
51
|
-
expect{ Language.where(:locale => 'en-US').
|
51
|
+
expect{ Language.where(:locale => 'en-US').load }.to hit_cache(Language).on(:full_table).times(1)
|
52
52
|
hungarian = Language.where(:locale => 'hu').first
|
53
53
|
hungarian.name = 'Magyar (Magyarorszag)'
|
54
54
|
hungarian.save!
|
55
|
-
expect{ Language.where(:locale => 'en-US').
|
55
|
+
expect{ Language.where(:locale => 'en-US').load }.to miss_cache(Language).on(:full_table).times(1)
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
context "invalidate" do
|
60
60
|
|
61
61
|
it "should invalidate the full cache" do
|
62
62
|
Language.record_cache[:full_table].invalidate(-10) # any id
|
63
|
-
expect{ Language.where(:locale => 'en-US').
|
63
|
+
expect{ Language.where(:locale => 'en-US').load }.to miss_cache(Language).on(:full_table).times(1)
|
64
64
|
end
|
65
65
|
|
66
66
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe RecordCache::Strategy::IndexCache do
|
3
|
+
RSpec.describe RecordCache::Strategy::IndexCache do
|
4
4
|
|
5
5
|
context "initialize" do
|
6
6
|
it "should only accept index cache on DB columns" do
|
@@ -13,58 +13,64 @@ describe RecordCache::Strategy::IndexCache do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should use the id cache to retrieve the actual records" do
|
16
|
-
expect{ @apples = Apple.where(:store_id => 1).
|
17
|
-
expect{ Apple.where(:store_id => 1).
|
18
|
-
expect{ Apple.where(:store_id => 1).
|
16
|
+
expect{ @apples = Apple.where(:store_id => 1).load }.to miss_cache(Apple).on(:store_id).times(1)
|
17
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:store_id).times(1)
|
18
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:id).times(@apples.size)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should find cached records through relationship" do
|
22
|
+
store = Store.first
|
23
|
+
expect{ @apple = store.apples.find(3) }.to use_cache(Apple).on(:id).times(1)
|
24
|
+
expect(@apple.name).to eq("Adams Apple 3")
|
19
25
|
end
|
20
26
|
|
21
27
|
context "logging" do
|
22
28
|
before(:each) do
|
23
|
-
Apple.where(:store_id => 1).
|
29
|
+
Apple.where(:store_id => 1).load
|
24
30
|
end
|
25
31
|
|
26
32
|
it "should write hit to the debug log" do
|
27
|
-
expect{ Apple.where(:store_id => 1).
|
33
|
+
expect{ Apple.where(:store_id => 1).load }.to log(:debug, /IndexCache hit for rc\/apl\/store_id=1v\d+: found 5 ids/)
|
28
34
|
end
|
29
35
|
|
30
36
|
it "should write miss to the debug log" do
|
31
|
-
expect{ Apple.where(:store_id => 2).
|
37
|
+
expect{ Apple.where(:store_id => 2).load }.to log(:debug, /IndexCache miss for rc\/apl\/store_id=2v\d+: found no ids/)
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
35
41
|
context "cacheable?" do
|
36
42
|
before(:each) do
|
37
|
-
@store1_apples = Apple.where(:store_id => 1).
|
38
|
-
@store2_apples = Apple.where(:store_id => 2).
|
43
|
+
@store1_apples = Apple.where(:store_id => 1).load
|
44
|
+
@store2_apples = Apple.where(:store_id => 2).load
|
39
45
|
end
|
40
46
|
|
41
47
|
it "should hit the cache for a single index id" do
|
42
|
-
expect{ Apple.where(:store_id => 1).
|
48
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:store_id).times(1)
|
43
49
|
end
|
44
50
|
|
45
51
|
it "should hit the cache for a single index id with other where clauses" do
|
46
|
-
expect{ Apple.where(:store_id => 1).where(:name => "applegate").
|
52
|
+
expect{ Apple.where(:store_id => 1).where(:name => "applegate").load }.to hit_cache(Apple).on(:store_id).times(1)
|
47
53
|
end
|
48
54
|
|
49
55
|
it "should hit the cache for a single index id with (simple) sort clauses" do
|
50
|
-
expect{ Apple.where(:store_id => 1).order("name ASC").
|
56
|
+
expect{ Apple.where(:store_id => 1).order("name ASC").load }.to hit_cache(Apple).on(:store_id).times(1)
|
51
57
|
end
|
52
58
|
|
53
59
|
#Allow limit == 1 by filtering records after cache hit. Needed for has_one
|
54
60
|
it "should not hit the cache for a single index id with limit > 0" do
|
55
|
-
expect{ Apple.where(:store_id => 1).limit(2).
|
61
|
+
expect{ Apple.where(:store_id => 1).limit(2).load }.to_not hit_cache(Apple).on(:store_id)
|
56
62
|
end
|
57
63
|
|
58
64
|
it "should not hit the cache when an :id where clause is defined" do
|
59
65
|
# this query should make use of the :id cache, which is faster
|
60
|
-
expect{ Apple.where(:store_id => 1).where(:id => 1).
|
66
|
+
expect{ Apple.where(:store_id => 1).where(:id => 1).load }.to_not hit_cache(Apple).on(:store_id)
|
61
67
|
end
|
62
68
|
end
|
63
|
-
|
69
|
+
|
64
70
|
context "record_change" do
|
65
71
|
before(:each) do
|
66
|
-
@store1_apples = Apple.where(:store_id => 1).order('id ASC').
|
67
|
-
@store2_apples = Apple.where(:store_id => 2).order('id ASC').
|
72
|
+
@store1_apples = Apple.where(:store_id => 1).order('id ASC').to_a
|
73
|
+
@store2_apples = Apple.where(:store_id => 2).order('id ASC').to_a
|
68
74
|
end
|
69
75
|
|
70
76
|
[false, true].each do |fresh|
|
@@ -76,14 +82,14 @@ describe RecordCache::Strategy::IndexCache do
|
|
76
82
|
@destroyed.destroy
|
77
83
|
# check the cache hit/miss on the index that contained that apple
|
78
84
|
if fresh
|
79
|
-
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').
|
85
|
+
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
80
86
|
else
|
81
|
-
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').
|
87
|
+
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').load }.to miss_cache(Apple).on(:store_id).times(1)
|
82
88
|
end
|
83
89
|
expect(@apples.size).to eq(@store1_apples.size - 1)
|
84
90
|
expect(@apples.map(&:id)).to eq(@store1_apples.map(&:id) - [@destroyed.id])
|
85
91
|
# and the index should be cached again
|
86
|
-
expect{ Apple.where(:store_id => 1).
|
92
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:store_id).times(1)
|
87
93
|
end
|
88
94
|
|
89
95
|
it "should #{fresh ? 'update' : 'invalidate'} the index when a record in the index is created and the current index is #{fresh ? '' : 'not '}fresh" do
|
@@ -93,14 +99,14 @@ describe RecordCache::Strategy::IndexCache do
|
|
93
99
|
@new_apple_in_store1 = Apple.create!(:name => "Fresh Apple", :store_id => 1)
|
94
100
|
# check the cache hit/miss on the index that contains that apple
|
95
101
|
if fresh
|
96
|
-
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').
|
102
|
+
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
97
103
|
else
|
98
|
-
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').
|
104
|
+
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').load }.to miss_cache(Apple).on(:store_id).times(1)
|
99
105
|
end
|
100
106
|
expect(@apples.size).to eq(@store1_apples.size + 1)
|
101
107
|
expect(@apples.map(&:id)).to eq(@store1_apples.map(&:id) + [@new_apple_in_store1.id])
|
102
108
|
# and the index should be cached again
|
103
|
-
expect{ Apple.where(:store_id => 1).
|
109
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:store_id).times(1)
|
104
110
|
end
|
105
111
|
|
106
112
|
it "should #{fresh ? 'update' : 'invalidate'} two indexes when the indexed value is updated and the current index is #{fresh ? '' : 'not '}fresh" do
|
@@ -113,25 +119,25 @@ describe RecordCache::Strategy::IndexCache do
|
|
113
119
|
@apple_moved_from_store1_to_store2.save!
|
114
120
|
# check the cache hit/miss on the indexes that contained/contains that apple
|
115
121
|
if fresh
|
116
|
-
expect{ @apples1 = Apple.where(:store_id => 1).order('id ASC').
|
117
|
-
expect{ @apples2 = Apple.where(:store_id => 2).order('id ASC').
|
122
|
+
expect{ @apples1 = Apple.where(:store_id => 1).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
123
|
+
expect{ @apples2 = Apple.where(:store_id => 2).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
118
124
|
else
|
119
|
-
expect{ @apples1 = Apple.where(:store_id => 1).order('id ASC').
|
120
|
-
expect{ @apples2 = Apple.where(:store_id => 2).order('id ASC').
|
125
|
+
expect{ @apples1 = Apple.where(:store_id => 1).order('id ASC').load }.to miss_cache(Apple).on(:store_id).times(1)
|
126
|
+
expect{ @apples2 = Apple.where(:store_id => 2).order('id ASC').load }.to miss_cache(Apple).on(:store_id).times(1)
|
121
127
|
end
|
122
128
|
expect(@apples1.size).to eq(@store1_apples.size - 1)
|
123
129
|
expect(@apples2.size).to eq(@store2_apples.size + 1)
|
124
130
|
expect(@apples1.map(&:id)).to eq(@store1_apples.map(&:id) - [@apple_moved_from_store1_to_store2.id])
|
125
131
|
expect(@apples2.map(&:id)).to eq([@apple_moved_from_store1_to_store2.id] + @store2_apples.map(&:id))
|
126
132
|
# and the index should be cached again
|
127
|
-
expect{ Apple.where(:store_id => 1).
|
128
|
-
expect{ Apple.where(:store_id => 2).
|
133
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:store_id).times(1)
|
134
|
+
expect{ Apple.where(:store_id => 2).load }.to hit_cache(Apple).on(:store_id).times(1)
|
129
135
|
end
|
130
136
|
|
131
137
|
it "should #{fresh ? 'update' : 'invalidate'} multiple indexes when several values on different indexed attributes are updated at once and one of the indexes is #{fresh ? '' : 'not '}fresh" do
|
132
138
|
# find the apples for person 1 and 5 (Chase)
|
133
|
-
@person4_apples = Apple.where(:person_id => 4).
|
134
|
-
@person5_apples = Apple.where(:person_id => 5).
|
139
|
+
@person4_apples = Apple.where(:person_id => 4).to_a # Fry's Apples
|
140
|
+
@person5_apples = Apple.where(:person_id => 5).to_a # Chases' Apples
|
135
141
|
# make sure person indexes are no longer fresh
|
136
142
|
Apple.record_cache.invalidate(:person_id, 4) unless fresh
|
137
143
|
Apple.record_cache.invalidate(:person_id, 5) unless fresh
|
@@ -141,14 +147,14 @@ describe RecordCache::Strategy::IndexCache do
|
|
141
147
|
@apple_moved_from_s1to2_p5to4.person_id = 4
|
142
148
|
@apple_moved_from_s1to2_p5to4.save!
|
143
149
|
# check the cache hit/miss on the indexes that contained/contains that apple
|
144
|
-
expect{ @apples_s1 = Apple.where(:store_id => 1).order('id ASC').
|
145
|
-
expect{ @apples_s2 = Apple.where(:store_id => 2).order('id ASC').
|
150
|
+
expect{ @apples_s1 = Apple.where(:store_id => 1).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
151
|
+
expect{ @apples_s2 = Apple.where(:store_id => 2).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
146
152
|
if fresh
|
147
|
-
expect{ @apples_p1 = Apple.where(:person_id => 4).order('id ASC').
|
148
|
-
expect{ @apples_p2 = Apple.where(:person_id => 5).order('id ASC').
|
153
|
+
expect{ @apples_p1 = Apple.where(:person_id => 4).order('id ASC').load }.to hit_cache(Apple).on(:person_id).times(1)
|
154
|
+
expect{ @apples_p2 = Apple.where(:person_id => 5).order('id ASC').load }.to hit_cache(Apple).on(:person_id).times(1)
|
149
155
|
else
|
150
|
-
expect{ @apples_p1 = Apple.where(:person_id => 4).order('id ASC').
|
151
|
-
expect{ @apples_p2 = Apple.where(:person_id => 5).order('id ASC').
|
156
|
+
expect{ @apples_p1 = Apple.where(:person_id => 4).order('id ASC').load }.to miss_cache(Apple).on(:person_id).times(1)
|
157
|
+
expect{ @apples_p2 = Apple.where(:person_id => 5).order('id ASC').load }.to miss_cache(Apple).on(:person_id).times(1)
|
152
158
|
end
|
153
159
|
expect(@apples_s1.size).to eq(@store1_apples.size - 1)
|
154
160
|
expect(@apples_s2.size).to eq(@store2_apples.size + 1)
|
@@ -159,10 +165,10 @@ describe RecordCache::Strategy::IndexCache do
|
|
159
165
|
expect(@apples_p1.map(&:id)).to eq(([@apple_moved_from_s1to2_p5to4.id] + @person4_apples.map(&:id)).sort)
|
160
166
|
expect(@apples_p2.map(&:id)).to eq( (@person5_apples.map(&:id) - [@apple_moved_from_s1to2_p5to4.id]).sort)
|
161
167
|
# and the index should be cached again
|
162
|
-
expect{ Apple.where(:store_id => 1).
|
163
|
-
expect{ Apple.where(:store_id => 2).
|
164
|
-
expect{ Apple.where(:person_id => 4).
|
165
|
-
expect{ Apple.where(:person_id => 5).
|
168
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:store_id).times(1)
|
169
|
+
expect{ Apple.where(:store_id => 2).load }.to hit_cache(Apple).on(:store_id).times(1)
|
170
|
+
expect{ Apple.where(:person_id => 4).load }.to hit_cache(Apple).on(:person_id).times(1)
|
171
|
+
expect{ Apple.where(:person_id => 5).load }.to hit_cache(Apple).on(:person_id).times(1)
|
166
172
|
end
|
167
173
|
end
|
168
174
|
|
@@ -170,36 +176,36 @@ describe RecordCache::Strategy::IndexCache do
|
|
170
176
|
# destroy an apple of store 2
|
171
177
|
@store2_apples.first.destroy
|
172
178
|
# index of apples of store 1 are not affected
|
173
|
-
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').
|
179
|
+
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
174
180
|
end
|
175
181
|
|
176
182
|
it "should leave the index alone when a record outside the index is created" do
|
177
183
|
# create an apple for store 2
|
178
184
|
Apple.create!(:name => "Fresh Apple", :store_id => 2)
|
179
185
|
# index of apples of store 1 are not affected
|
180
|
-
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').
|
186
|
+
expect{ @apples = Apple.where(:store_id => 1).order('id ASC').load }.to hit_cache(Apple).on(:store_id).times(1)
|
181
187
|
end
|
182
188
|
end
|
183
189
|
|
184
190
|
context "invalidate" do
|
185
191
|
before(:each) do
|
186
|
-
@store1_apples = Apple.where(:store_id => 1).
|
187
|
-
@store2_apples = Apple.where(:store_id => 2).
|
188
|
-
@address_1 = Address.where(:store_id => 1).
|
189
|
-
@address_2 = Address.where(:store_id => 2).
|
192
|
+
@store1_apples = Apple.where(:store_id => 1).to_a
|
193
|
+
@store2_apples = Apple.where(:store_id => 2).to_a
|
194
|
+
@address_1 = Address.where(:store_id => 1).to_a
|
195
|
+
@address_2 = Address.where(:store_id => 2).to_a
|
190
196
|
end
|
191
197
|
|
192
198
|
it "should invalidate single index" do
|
193
199
|
Apple.record_cache[:store_id].invalidate(1)
|
194
|
-
expect{ Apple.where(:store_id => 1).
|
200
|
+
expect{ Apple.where(:store_id => 1).load }.to miss_cache(Apple).on(:store_id).times(1)
|
195
201
|
end
|
196
202
|
|
197
203
|
it "should invalidate indexes when using update_all" do
|
198
204
|
pending "is there a performant way to invalidate index caches within update_all? only the new value is available, so we should query the old values..."
|
199
205
|
# update 2 apples for index values store 1 and store 2
|
200
206
|
Apple.where(:id => [@store1_apples.first.id, @store2_apples.first.id]).update_all(:store_id => 3)
|
201
|
-
expect{ @apples_1 = Apple.where(:store_id => 1).
|
202
|
-
expect{ @apples_2 = Apple.where(:store_id => 2).
|
207
|
+
expect{ @apples_1 = Apple.where(:store_id => 1).load }.to miss_cache(Apple).on(:store_id).times(1)
|
208
|
+
expect{ @apples_2 = Apple.where(:store_id => 2).load }.to miss_cache(Apple).on(:store_id).times(1)
|
203
209
|
expect(@apples_1.map(&:id).sort).to eq(@store1_apples[1..-1].sort)
|
204
210
|
expect(@apples_2.map(&:id).sort).to eq(@store2_apples[1..-1].sort)
|
205
211
|
end
|
@@ -212,10 +218,10 @@ describe RecordCache::Strategy::IndexCache do
|
|
212
218
|
store1.apple_ids = store2_apple_ids
|
213
219
|
store1.save!
|
214
220
|
# apples in Store 1 should be all (only) the apples that were in Store 2 (cache invalidated)
|
215
|
-
expect{ @apples_1 = Apple.where(:store_id => 1).
|
221
|
+
expect{ @apples_1 = Apple.where(:store_id => 1).load }.to miss_cache(Apple).on(:store_id).times(1)
|
216
222
|
expect(@apples_1.map(&:id).sort).to eq(store2_apple_ids)
|
217
223
|
# there are no apples in Store 2 anymore (incremental cache update, as each apples in store 2 was saved separately)
|
218
|
-
expect{ @apples_2 = Apple.where(:store_id => 2).
|
224
|
+
expect{ @apples_2 = Apple.where(:store_id => 2).load }.to hit_cache(Apple).on(:store_id).times(1)
|
219
225
|
expect(@apples_2).to eq([])
|
220
226
|
end
|
221
227
|
|
@@ -15,7 +15,7 @@ require 'spec_helper'
|
|
15
15
|
# happen to records by another process, while you have already got
|
16
16
|
# references to that records in QueryCache, that you won't see the changes
|
17
17
|
# made by the other process.
|
18
|
-
describe "QueryCache" do
|
18
|
+
RSpec.describe "QueryCache" do
|
19
19
|
|
20
20
|
it "should retrieve a record from the QueryCache" do
|
21
21
|
ActiveRecord::Base.cache do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe RecordCache::Strategy::UniqueIndexCache do
|
3
|
+
RSpec.describe RecordCache::Strategy::UniqueIndexCache do
|
4
4
|
|
5
5
|
it "should retrieve an Apple from the cache" do
|
6
6
|
expect{ Apple.find(1) }.to miss_cache(Apple).on(:id).times(1)
|
@@ -40,9 +40,9 @@ describe RecordCache::Strategy::UniqueIndexCache do
|
|
40
40
|
it "should write full miss to the debug log" do
|
41
41
|
expect{ Apple.find(2) }.to log(:debug, %(UniqueIndexCache on 'Apple.id' miss for ids 2))
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
it "should write partial hits to the debug log" do
|
45
|
-
expect{ Apple.where(:id => [1,2]).
|
45
|
+
expect{ Apple.where(:id => [1,2]).load }.to log(:debug, %(UniqueIndexCache on 'Apple.id' partial hit for ids [1, 2]: missing [2]))
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -55,50 +55,60 @@ describe RecordCache::Strategy::UniqueIndexCache do
|
|
55
55
|
|
56
56
|
# @see https://github.com/orslumen/record-cache/issues/2
|
57
57
|
it "should not use the cache when a lock is used" do
|
58
|
-
|
58
|
+
pending("Any_lock is sqlite specific and I'm not aware of a mysql alternative") unless ActiveRecord::Base.connection.adapter_name == "SQLite"
|
59
|
+
|
60
|
+
expect{ Apple.lock("any_lock").where(:id => 1).load }.to_not hit_cache(Apple)
|
59
61
|
end
|
60
62
|
|
61
63
|
it "should use the cache when a single id is requested" do
|
62
|
-
expect{ Apple.where(:id => 1).
|
64
|
+
expect{ Apple.where(:id => 1).load }.to hit_cache(Apple).on(:id).times(1)
|
63
65
|
end
|
64
66
|
|
65
67
|
it "should use the cache when a multiple ids are requested" do
|
66
|
-
expect{ Apple.where(:id => [1, 2]).
|
68
|
+
expect{ Apple.where(:id => [1, 2]).load }.to hit_cache(Apple).on(:id).times(2)
|
67
69
|
end
|
68
70
|
|
69
71
|
it "should use the cache when a single id is requested and the limit is 1" do
|
70
|
-
expect{ Apple.where(:id => 1).limit(1).
|
72
|
+
expect{ Apple.where(:id => 1).limit(1).load }.to hit_cache(Apple).on(:id).times(1)
|
71
73
|
end
|
72
74
|
|
73
75
|
it "should not use the cache when a single id is requested and the limit is > 1" do
|
74
|
-
expect{ Apple.where(:id => 1).limit(2).
|
76
|
+
expect{ Apple.where(:id => 1).limit(2).load }.to_not use_cache(Apple).on(:id)
|
75
77
|
end
|
76
78
|
|
77
79
|
it "should not use the cache when multiple ids are requested and the limit is 1" do
|
78
|
-
expect{ Apple.where(:id => [1, 2]).limit(1).
|
80
|
+
expect{ Apple.where(:id => [1, 2]).limit(1).load }.to_not use_cache(Apple).on(:id)
|
79
81
|
end
|
80
82
|
|
81
83
|
it "should use the cache when a single id is requested together with other where clauses" do
|
82
|
-
expect{ Apple.where(:id => 1).where(:name => "Adams Apple x").
|
84
|
+
expect{ Apple.where(:id => 1).where(:name => "Adams Apple x").load }.to hit_cache(Apple).on(:id).times(1)
|
83
85
|
end
|
84
86
|
|
85
87
|
it "should use the cache when a multiple ids are requested together with other where clauses" do
|
86
|
-
expect{ Apple.where(:id => [1,2]).where(:name => "Adams Apple x").
|
88
|
+
expect{ Apple.where(:id => [1,2]).where(:name => "Adams Apple x").load }.to hit_cache(Apple).on(:id).times(2)
|
87
89
|
end
|
88
90
|
|
89
91
|
it "should use the cache when a single id is requested together with (simple) sort clauses" do
|
90
|
-
expect{ Apple.where(:id => 1).order("name ASC").
|
92
|
+
expect{ Apple.where(:id => 1).order("name ASC").load }.to hit_cache(Apple).on(:id).times(1)
|
91
93
|
end
|
92
94
|
|
93
95
|
it "should use the cache when a multiple ids are requested together with (simple) sort clauses" do
|
94
|
-
expect{ Apple.where(:id => [1,2]).order("name ASC").
|
96
|
+
expect{ Apple.where(:id => [1,2]).order("name ASC").load }.to hit_cache(Apple).on(:id).times(2)
|
95
97
|
end
|
96
98
|
|
97
99
|
it "should not use the cache when a join clause is used" do
|
98
|
-
expect{ Apple.where(:id => [1,2]).joins(:store).
|
100
|
+
expect{ Apple.where(:id => [1,2]).joins(:store).load }.to_not use_cache(Apple).on(:id)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should not use the cache when distinct is used in a select" do
|
104
|
+
expect{ Apple.select('distinct person_id').where(:id => [1, 2]).load }.not_to hit_cache(Apple).on(:id)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should not use the cache when distinct is used in a select" do
|
108
|
+
expect{ Apple.select('distinct person_id').where(:id => [1, 2]).load }.not_to hit_cache(Apple).on(:id)
|
99
109
|
end
|
100
110
|
end
|
101
|
-
|
111
|
+
|
102
112
|
context "record_change" do
|
103
113
|
before(:each) do
|
104
114
|
# fill cache
|
@@ -107,12 +117,12 @@ describe RecordCache::Strategy::UniqueIndexCache do
|
|
107
117
|
end
|
108
118
|
|
109
119
|
it "should invalidate destroyed records" do
|
110
|
-
expect{ Apple.where(:id => 1).
|
120
|
+
expect{ Apple.where(:id => 1).load }.to hit_cache(Apple).on(:id).times(1)
|
111
121
|
@apple1.destroy
|
112
|
-
expect{ @apples = Apple.where(:id => 1).
|
122
|
+
expect{ @apples = Apple.where(:id => 1).load }.to miss_cache(Apple).on(:id).times(1)
|
113
123
|
expect(@apples).to be_empty
|
114
124
|
# try again, to make sure the "missing record" is not cached
|
115
|
-
expect{ Apple.where(:id => 1).
|
125
|
+
expect{ Apple.where(:id => 1).load }.to miss_cache(Apple).on(:id).times(1)
|
116
126
|
end
|
117
127
|
|
118
128
|
it "should add updated records directly to the cache" do
|
@@ -131,12 +141,12 @@ describe RecordCache::Strategy::UniqueIndexCache do
|
|
131
141
|
it "should add updated records to the cache, also when multiple ids are queried" do
|
132
142
|
@apple1.name = "Applejuice"
|
133
143
|
@apple1.save!
|
134
|
-
expect{ @apples = Apple.where(:id => [1, 2]).order('id ASC').
|
144
|
+
expect{ @apples = Apple.where(:id => [1, 2]).order('id ASC').load }.to hit_cache(Apple).on(:id).times(2)
|
135
145
|
expect(@apples.map(&:name)).to eq(["Applejuice", "Adams Apple 2"])
|
136
146
|
end
|
137
147
|
|
138
148
|
end
|
139
|
-
|
149
|
+
|
140
150
|
context "invalidate" do
|
141
151
|
before(:each) do
|
142
152
|
@apple1 = Apple.find(1)
|
@@ -151,27 +161,27 @@ describe RecordCache::Strategy::UniqueIndexCache do
|
|
151
161
|
it "should only miss the cache for the invalidated record when multiple ids are queried" do
|
152
162
|
# miss on 1
|
153
163
|
Apple.record_cache[:id].invalidate(1)
|
154
|
-
expect{ Apple.where(:id => [1, 2]).
|
164
|
+
expect{ Apple.where(:id => [1, 2]).load }.to miss_cache(Apple).on(:id).times(1)
|
155
165
|
# hit on 2
|
156
166
|
Apple.record_cache[:id].invalidate(1)
|
157
|
-
expect{ Apple.where(:id => [1, 2]).
|
167
|
+
expect{ Apple.where(:id => [1, 2]).load }.to hit_cache(Apple).on(:id).times(1)
|
158
168
|
# nothing invalidated, both hit
|
159
|
-
expect{ Apple.where(:id => [1, 2]).
|
169
|
+
expect{ Apple.where(:id => [1, 2]).load }.to hit_cache(Apple).on(:id).times(2)
|
160
170
|
end
|
161
171
|
|
162
172
|
it "should invalidate records when using update_all" do
|
163
|
-
Apple.where(:id => [3,4,5]).
|
164
|
-
expect{ @apples = Apple.where(:id => [1, 2, 3, 4, 5]).order('id ASC').
|
173
|
+
Apple.where(:id => [3,4,5]).load # fill id cache on all Adam Store apples
|
174
|
+
expect{ @apples = Apple.where(:id => [1, 2, 3, 4, 5]).order('id ASC').load }.to hit_cache(Apple).on(:id).times(5)
|
165
175
|
expect(@apples.map(&:name)).to eq(["Adams Apple 1", "Adams Apple 2", "Adams Apple 3", "Adams Apple 4", "Adams Apple 5"])
|
166
176
|
# update 3 of the 5 apples in the Adam Store
|
167
177
|
Apple.where(:id => [1,2,3]).update_all(:name => "Uniform Apple")
|
168
|
-
expect{ @apples = Apple.where(:id => [1, 2, 3, 4, 5]).order('id ASC').
|
178
|
+
expect{ @apples = Apple.where(:id => [1, 2, 3, 4, 5]).order('id ASC').load }.to hit_cache(Apple).on(:id).times(2)
|
169
179
|
expect(@apples.map(&:name)).to eq(["Uniform Apple", "Uniform Apple", "Uniform Apple", "Adams Apple 4", "Adams Apple 5"])
|
170
180
|
end
|
171
181
|
|
172
182
|
it "should invalidate reflection indexes when a has_many relation is updated" do
|
173
183
|
# assign different apples to store 2
|
174
|
-
expect{ Apple.where(:store_id => 1).
|
184
|
+
expect{ Apple.where(:store_id => 1).load }.to hit_cache(Apple).on(:id).times(2)
|
175
185
|
store2_apple_ids = Apple.where(:store_id => 2).map(&:id)
|
176
186
|
store1 = Store.find(1)
|
177
187
|
store1.apple_ids = store2_apple_ids
|
@@ -288,30 +298,32 @@ describe RecordCache::Strategy::UniqueIndexCache do
|
|
288
298
|
end
|
289
299
|
end
|
290
300
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
301
|
+
# does not work for Rails 3.0
|
302
|
+
unless ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
|
303
|
+
it "should not update the cache for the rolled back inner transaction" do
|
304
|
+
apple1, apple2 = nil
|
295
305
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
306
|
+
ActiveRecord::Base.transaction do
|
307
|
+
apple1 = Apple.find(1)
|
308
|
+
apple1.name = "Committed Apple 1"
|
309
|
+
apple1.save!
|
300
310
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
311
|
+
ActiveRecord::Base.transaction(requires_new: true) do
|
312
|
+
apple2 = Apple.find(2)
|
313
|
+
apple2.name = "Rollback Apple 2"
|
314
|
+
apple2.save!
|
305
315
|
|
306
|
-
|
316
|
+
raise ActiveRecord::Rollback, "oops"
|
317
|
+
end
|
307
318
|
end
|
308
|
-
end
|
309
319
|
|
310
|
-
|
311
|
-
|
320
|
+
expect{ apple1 = Apple.find(1) }.to use_cache(Apple).on(:id)
|
321
|
+
expect(apple1.name).to eq("Committed Apple 1")
|
312
322
|
|
313
|
-
|
314
|
-
|
323
|
+
expect{ apple2 = Apple.find(2) }.to use_cache(Apple).on(:id)
|
324
|
+
expect(apple2.name).to eq("Adams Apple 2")
|
325
|
+
end
|
315
326
|
end
|
327
|
+
|
316
328
|
end
|
317
329
|
end
|