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.
Files changed (35) hide show
  1. checksums.yaml +8 -8
  2. data/lib/record_cache/base.rb +4 -4
  3. data/lib/record_cache/datastore/active_record_30.rb +1 -1
  4. data/lib/record_cache/datastore/active_record_31.rb +1 -1
  5. data/lib/record_cache/datastore/active_record_32.rb +2 -2
  6. data/lib/record_cache/datastore/active_record_40.rb +445 -0
  7. data/lib/record_cache/datastore/active_record_41.rb +446 -0
  8. data/lib/record_cache/strategy/full_table_cache.rb +1 -1
  9. data/lib/record_cache/strategy/util.rb +20 -3
  10. data/lib/record_cache/version.rb +1 -1
  11. data/spec/db/create-record-cache-db_and_user.sql +5 -0
  12. data/spec/db/database.yml +7 -0
  13. data/spec/db/schema.rb +9 -15
  14. data/spec/initializers/backward_compatibility.rb +32 -0
  15. data/spec/lib/active_record/visitor_spec.rb +1 -1
  16. data/spec/lib/base_spec.rb +2 -2
  17. data/spec/lib/dispatcher_spec.rb +1 -1
  18. data/spec/lib/multi_read_spec.rb +1 -1
  19. data/spec/lib/query_spec.rb +1 -1
  20. data/spec/lib/statistics_spec.rb +1 -1
  21. data/spec/lib/strategy/base_spec.rb +39 -39
  22. data/spec/lib/strategy/full_table_cache_spec.rb +18 -18
  23. data/spec/lib/strategy/index_cache_spec.rb +58 -52
  24. data/spec/lib/strategy/query_cache_spec.rb +1 -1
  25. data/spec/lib/strategy/unique_index_on_id_cache_spec.rb +57 -45
  26. data/spec/lib/strategy/unique_index_on_string_cache_spec.rb +47 -45
  27. data/spec/lib/strategy/util_spec.rb +49 -43
  28. data/spec/lib/version_store_spec.rb +1 -1
  29. data/spec/models/apple.rb +1 -2
  30. data/spec/spec_helper.rb +16 -7
  31. data/spec/support/matchers/hit_cache_matcher.rb +1 -1
  32. data/spec/support/matchers/miss_cache_matcher.rb +1 -1
  33. data/spec/support/matchers/use_cache_matcher.rb +1 -1
  34. metadata +63 -17
  35. 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').all }.to miss_cache(Language).on(:full_table).times(1)
7
- expect{ Language.where(:locale => 'en-US').all }.to hit_cache(Language).on(:full_table).times(1)
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').all }.to hit_cache(Language).on(:full_table).times(1)
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').all }.to miss_cache(Language).on(:full_table).times(1)
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').all }.to hit_cache(Language).on(:full_table).times(1)
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').all }.to miss_cache(Language).on(:full_table).times(1)
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').all }.to hit_cache(Language).on(:full_table).times(1)
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').all }.to miss_cache(Language).on(:full_table).times(1)
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').all }.to miss_cache(Language).on(:full_table).times(1)
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).all }.to miss_cache(Apple).on(:store_id).times(1)
17
- expect{ Apple.where(:store_id => 1).all }.to hit_cache(Apple).on(:store_id).times(1)
18
- expect{ Apple.where(:store_id => 1).all }.to hit_cache(Apple).on(:id).times(@apples.size)
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).all
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).all }.to log(:debug, /IndexCache hit for rc\/apl\/store_id=1v\d+: found 5 ids/)
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).all }.to log(:debug, /IndexCache miss for rc\/apl\/store_id=2v\d+: found no ids/)
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).all
38
- @store2_apples = Apple.where(:store_id => 2).all
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).all }.to hit_cache(Apple).on(:store_id).times(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").all }.to hit_cache(Apple).on(:store_id).times(1)
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").all }.to hit_cache(Apple).on(:store_id).times(1)
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).all }.to_not hit_cache(Apple).on(:store_id)
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).all }.to_not hit_cache(Apple).on(:store_id)
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').all
67
- @store2_apples = Apple.where(:store_id => 2).order('id ASC').all
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').all }.to hit_cache(Apple).on(:store_id).times(1)
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').all }.to miss_cache(Apple).on(:store_id).times(1)
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).all }.to hit_cache(Apple).on(:store_id).times(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').all }.to hit_cache(Apple).on(:store_id).times(1)
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').all }.to miss_cache(Apple).on(:store_id).times(1)
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).all }.to hit_cache(Apple).on(:store_id).times(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').all }.to hit_cache(Apple).on(:store_id).times(1)
117
- expect{ @apples2 = Apple.where(:store_id => 2).order('id ASC').all }.to hit_cache(Apple).on(:store_id).times(1)
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').all }.to miss_cache(Apple).on(:store_id).times(1)
120
- expect{ @apples2 = Apple.where(:store_id => 2).order('id ASC').all }.to miss_cache(Apple).on(:store_id).times(1)
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).all }.to hit_cache(Apple).on(:store_id).times(1)
128
- expect{ Apple.where(:store_id => 2).all }.to hit_cache(Apple).on(:store_id).times(1)
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).all # Fry's Apples
134
- @person5_apples = Apple.where(:person_id => 5).all # Chases' Apples
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').all }.to hit_cache(Apple).on(:store_id).times(1)
145
- expect{ @apples_s2 = Apple.where(:store_id => 2).order('id ASC').all }.to hit_cache(Apple).on(:store_id).times(1)
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').all }.to hit_cache(Apple).on(:person_id).times(1)
148
- expect{ @apples_p2 = Apple.where(:person_id => 5).order('id ASC').all }.to hit_cache(Apple).on(:person_id).times(1)
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').all }.to miss_cache(Apple).on(:person_id).times(1)
151
- expect{ @apples_p2 = Apple.where(:person_id => 5).order('id ASC').all }.to miss_cache(Apple).on(:person_id).times(1)
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).all }.to hit_cache(Apple).on(:store_id).times(1)
163
- expect{ Apple.where(:store_id => 2).all }.to hit_cache(Apple).on(:store_id).times(1)
164
- expect{ Apple.where(:person_id => 4).all }.to hit_cache(Apple).on(:person_id).times(1)
165
- expect{ Apple.where(:person_id => 5).all }.to hit_cache(Apple).on(:person_id).times(1)
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').all }.to hit_cache(Apple).on(:store_id).times(1)
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').all }.to hit_cache(Apple).on(:store_id).times(1)
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).all
187
- @store2_apples = Apple.where(:store_id => 2).all
188
- @address_1 = Address.where(:store_id => 1).all
189
- @address_2 = Address.where(:store_id => 2).all
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).all }.to miss_cache(Apple).on(:store_id).times(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).all }.to miss_cache(Apple).on(:store_id).times(1)
202
- expect{ @apples_2 = Apple.where(:store_id => 2).all }.to miss_cache(Apple).on(:store_id).times(1)
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).all }.to miss_cache(Apple).on(:store_id).times(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).all }.to hit_cache(Apple).on(:store_id).times(1)
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]).all }.to log(:debug, %(UniqueIndexCache on 'Apple.id' partial hit for ids [1, 2]: missing [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
- expect{ Apple.lock("any_lock").where(:id => 1).all }.to_not hit_cache(Apple)
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).all }.to hit_cache(Apple).on(:id).times(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]).all }.to hit_cache(Apple).on(:id).times(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).all }.to hit_cache(Apple).on(:id).times(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).all }.to_not use_cache(Apple).on(:id)
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).all }.to_not use_cache(Apple).on(:id)
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").all }.to hit_cache(Apple).on(:id).times(1)
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").all }.to hit_cache(Apple).on(:id).times(2)
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").all }.to hit_cache(Apple).on(:id).times(1)
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").all }.to hit_cache(Apple).on(:id).times(2)
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).all }.to_not use_cache(Apple).on(:id)
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).all }.to hit_cache(Apple).on(:id).times(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).all }.to miss_cache(Apple).on(:id).times(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).all }.to miss_cache(Apple).on(:id).times(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').all }.to hit_cache(Apple).on(:id).times(2)
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]).all }.to miss_cache(Apple).on(:id).times(1)
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]).all }.to hit_cache(Apple).on(:id).times(1)
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]).all }.to hit_cache(Apple).on(:id).times(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]).all # fill id cache on all Adam Store apples
164
- expect{ @apples = Apple.where(:id => [1, 2, 3, 4, 5]).order('id ASC').all }.to hit_cache(Apple).on(:id).times(5)
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').all }.to hit_cache(Apple).on(:id).times(2)
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).all }.to hit_cache(Apple).on(:id).times(2)
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
- it "should not update the cache for the rolled back inner transaction" do
292
- pending "rails calls after_commit on records that are in a transaction that is rolled back"
293
-
294
- apple1, apple2 = nil
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
- ActiveRecord::Base.transaction do
297
- apple1 = Apple.find(1)
298
- apple1.name = "Committed Apple 1"
299
- apple1.save!
306
+ ActiveRecord::Base.transaction do
307
+ apple1 = Apple.find(1)
308
+ apple1.name = "Committed Apple 1"
309
+ apple1.save!
300
310
 
301
- ActiveRecord::Base.transaction(requires_new: true) do
302
- apple2 = Apple.find(2)
303
- apple2.name = "Rollback Apple 2"
304
- apple2.save!
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
- raise ActiveRecord::Rollback, "oops"
316
+ raise ActiveRecord::Rollback, "oops"
317
+ end
307
318
  end
308
- end
309
319
 
310
- expect{ apple1 = Apple.find(1) }.to use_cache(Apple).on(:id)
311
- expect(apple1.name).to eq("Committed Apple 1")
320
+ expect{ apple1 = Apple.find(1) }.to use_cache(Apple).on(:id)
321
+ expect(apple1.name).to eq("Committed Apple 1")
312
322
 
313
- expect{ apple2 = Apple.find(2) }.to use_cache(Apple).on(:id)
314
- expect(apple2.name).to eq("Adams Apple 2")
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