seifertd-seifertd-cache-money 0.2.5.1
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.
- data/README +205 -0
- data/TODO +17 -0
- data/UNSUPPORTED_FEATURES +14 -0
- data/config/environment.rb +6 -0
- data/config/memcache.yml +6 -0
- data/db/schema.rb +12 -0
- data/lib/cache_money.rb +54 -0
- data/lib/cash/accessor.rb +79 -0
- data/lib/cash/buffered.rb +126 -0
- data/lib/cash/config.rb +71 -0
- data/lib/cash/finders.rb +38 -0
- data/lib/cash/index.rb +207 -0
- data/lib/cash/local.rb +59 -0
- data/lib/cash/lock.rb +53 -0
- data/lib/cash/mock.rb +86 -0
- data/lib/cash/query/abstract.rb +162 -0
- data/lib/cash/query/calculation.rb +45 -0
- data/lib/cash/query/primary_key.rb +51 -0
- data/lib/cash/query/select.rb +16 -0
- data/lib/cash/request.rb +3 -0
- data/lib/cash/transactional.rb +42 -0
- data/lib/cash/util/array.rb +9 -0
- data/lib/cash/write_through.rb +72 -0
- data/spec/cash/accessor_spec.rb +159 -0
- data/spec/cash/active_record_spec.rb +199 -0
- data/spec/cash/calculations_spec.rb +67 -0
- data/spec/cash/finders_spec.rb +355 -0
- data/spec/cash/lock_spec.rb +87 -0
- data/spec/cash/order_spec.rb +166 -0
- data/spec/cash/transactional_spec.rb +574 -0
- data/spec/cash/window_spec.rb +195 -0
- data/spec/cash/write_through_spec.rb +223 -0
- data/spec/spec_helper.rb +56 -0
- metadata +113 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
module Cash
|
4
|
+
describe Finders do
|
5
|
+
describe 'when the cache is populated' do
|
6
|
+
describe "#find" do
|
7
|
+
describe '#find(id...)' do
|
8
|
+
describe '#find(id)' do
|
9
|
+
it "returns an active record" do
|
10
|
+
story = Story.create!(:title => 'a story')
|
11
|
+
Story.find(story.id).should == story
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'when the object is destroyed' do
|
16
|
+
describe '#find(id)' do
|
17
|
+
it "raises an error" do
|
18
|
+
story = Story.create!(:title => "I am delicious")
|
19
|
+
story.destroy
|
20
|
+
lambda { Story.find(story.id) }.should raise_error(ActiveRecord::RecordNotFound)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#find(id1, id2, ...)' do
|
26
|
+
it "returns an array" do
|
27
|
+
story1, story2 = Story.create!, Story.create!
|
28
|
+
Story.find(story1.id, story2.id).should == [story1, story2]
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#find(id, nil)" do
|
32
|
+
it "ignores the nils" do
|
33
|
+
story = Story.create!
|
34
|
+
Story.find(story.id, nil).should == story
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'when given nonexistent ids' do
|
40
|
+
describe 'when given one nonexistent id' do
|
41
|
+
it 'raises an error' do
|
42
|
+
lambda { Story.find(1) }.should raise_error(ActiveRecord::RecordNotFound)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'when given multiple nonexistent ids' do
|
47
|
+
it "raises an error" do
|
48
|
+
lambda { Story.find(1, 2, 3) }.should raise_error(ActiveRecord::RecordNotFound)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
describe '#find(nil)' do
|
54
|
+
it 'raises an error' do
|
55
|
+
lambda { Story.find(nil) }.should raise_error(ActiveRecord::RecordNotFound)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#find(object)' do
|
62
|
+
it "coerces arguments to integers" do
|
63
|
+
story = Story.create!
|
64
|
+
Story.find(story.id.to_s).should == story
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#find([...])' do
|
69
|
+
describe 'when given an array with valid ids' do
|
70
|
+
it "#finds the object with that id" do
|
71
|
+
story = Story.create!
|
72
|
+
Story.find([story.id]).should == [story]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#find([])' do
|
77
|
+
it 'returns the empty array' do
|
78
|
+
Story.find([]).should == []
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'when given nonexistent ids' do
|
83
|
+
it 'raises an error' do
|
84
|
+
lambda { Story.find([1, 2, 3]) }.should raise_error(ActiveRecord::RecordNotFound)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'when given limits and offsets' do
|
89
|
+
describe '#find([1, 2, ...], :limit => ..., :offset => ...)' do
|
90
|
+
it "returns the correct slice of objects" do
|
91
|
+
character1 = Character.create!(:name => "Sam", :story_id => 1)
|
92
|
+
character2 = Character.create!(:name => "Sam", :story_id => 1)
|
93
|
+
character3 = Character.create!(:name => "Sam", :story_id => 1)
|
94
|
+
Character.find(
|
95
|
+
[character1.id, character2.id, character3.id],
|
96
|
+
:conditions => { :name => "Sam", :story_id => 1 }, :limit => 2
|
97
|
+
).should == [character1, character2]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#find([1], :limit => 0)' do
|
102
|
+
it "raises an error" do
|
103
|
+
character = Character.create!(:name => "Sam", :story_id => 1)
|
104
|
+
lambda do
|
105
|
+
Character.find([character.id], :conditions => { :name => "Sam", :story_id => 1 }, :limit => 0)
|
106
|
+
end.should raise_error(ActiveRecord::RecordNotFound)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#find(:first, ..., :offset => ...)' do
|
113
|
+
it "#finds the object in the correct order" do
|
114
|
+
story1 = Story.create!(:title => 'title1')
|
115
|
+
story2 = Story.create!(:title => story1.title)
|
116
|
+
Story.find(:first, :conditions => { :title => story1.title }, :offset => 1).should == story2
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe '#find(:first, :conditions => [])' do
|
121
|
+
it 'works' do
|
122
|
+
story = Story.create!
|
123
|
+
Story.find(:first, :conditions => []).should == story
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "#find(:first, :conditions => '...')" do
|
128
|
+
it "uses the active record instance to typecast values extracted from the conditions" do
|
129
|
+
story1 = Story.create! :title => 'a story', :published => true
|
130
|
+
story2 = Story.create! :title => 'another story', :published => false
|
131
|
+
Story.get('published/false').should == [story2.id]
|
132
|
+
Story.find(:first, :conditions => 'published = 0').should == story2
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#find_by_attr' do
|
138
|
+
describe '#find_by_attr(nil)' do
|
139
|
+
it 'returns nil' do
|
140
|
+
Story.find_by_id(nil).should == nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'when given non-existent ids' do
|
145
|
+
it 'returns nil' do
|
146
|
+
Story.find_by_id(-1).should == nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#find_all_by_attr' do
|
152
|
+
describe 'when given non-existent ids' do
|
153
|
+
it "does not raise an error" do
|
154
|
+
lambda { Story.find_all_by_id([-1, -2, -3]) }.should_not raise_error
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe 'when the cache is partially populated' do
|
161
|
+
describe '#find(:all, :conditions => ...)' do
|
162
|
+
it "returns the correct records" do
|
163
|
+
story1 = Story.create!(:title => title = 'once upon a time...')
|
164
|
+
$memcache.flush_all
|
165
|
+
story2 = Story.create!(:title => title)
|
166
|
+
Story.find(:all, :conditions => { :title => story1.title }).should == [story1, story2]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#find(id1, id2, ...)' do
|
171
|
+
it "returns the correct records" do
|
172
|
+
story1 = Story.create!(:title => 'story 1')
|
173
|
+
$memcache.flush_all
|
174
|
+
story2 = Story.create!(:title => 'story 2')
|
175
|
+
Story.find(story1.id, story2.id).should == [story1, story2]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe 'when the cache is not populated' do
|
181
|
+
describe '#find(id)' do
|
182
|
+
it "returns the correct records" do
|
183
|
+
story = Story.create!(:title => 'a story')
|
184
|
+
$memcache.flush_all
|
185
|
+
Story.find(story.id).should == story
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe '#find(id1, id2, ...)' do
|
190
|
+
it "handles finds with multiple ids correctly" do
|
191
|
+
story1 = Story.create!
|
192
|
+
story2 = Story.create!
|
193
|
+
$memcache.flush_all
|
194
|
+
Story.find(story1.id, story2.id).should == [story1, story2]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
module Cash
|
4
|
+
describe Finders do
|
5
|
+
describe 'Calculations' do
|
6
|
+
describe 'when the cache is populated' do
|
7
|
+
before do
|
8
|
+
@stories = [Story.create!(:title => @title = 'asdf'), Story.create!(:title => @title)]
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#count(:all, :conditions => ...)' do
|
12
|
+
it "does not use the database" do
|
13
|
+
Story.count(:all, :conditions => { :title => @title }).should == @stories.size
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#count(:column, :conditions => ...)' do
|
18
|
+
it "uses the database, not the cache" do
|
19
|
+
mock(Story).get.never
|
20
|
+
Story.count(:title, :conditions => { :title => @title }).should == @stories.size
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#count(:all, :distinct => ..., :select => ...)' do
|
25
|
+
it 'uses the database, not the cache' do
|
26
|
+
mock(Story).get.never
|
27
|
+
Story.count(:all, :distinct => true, :select => :title, :conditions => { :title => @title }).should == @stories.collect(&:title).uniq.size
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'association proxies' do
|
32
|
+
describe '#count(:all, :conditions => ...)' do
|
33
|
+
it 'does not use the database' do
|
34
|
+
story = Story.create!
|
35
|
+
characters = [story.characters.create!(:name => name = 'name'), story.characters.create!(:name => name)]
|
36
|
+
mock(Story.connection).execute.never
|
37
|
+
story.characters.count(:all, :conditions => { :name => name }).should == characters.size
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'when the cache is not populated' do
|
44
|
+
describe '#count(:all, ...)' do
|
45
|
+
describe '#count(:all)' do
|
46
|
+
it 'uses the database, not the cache' do
|
47
|
+
mock(Story).get.never
|
48
|
+
Story.count
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#count(:all, :conditions => ...)' do
|
53
|
+
before do
|
54
|
+
Story.create!(:title => @title = 'title')
|
55
|
+
$memcache.flush_all
|
56
|
+
end
|
57
|
+
|
58
|
+
it "populates the count correctly" do
|
59
|
+
Story.count(:all, :conditions => { :title => @title }).should == 1
|
60
|
+
Story.fetch("title/#{@title}/count", :raw => true).should =~ /\s*1\s*/
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,355 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
module Cash
|
4
|
+
describe Finders do
|
5
|
+
describe 'Cache Usage' do
|
6
|
+
describe 'when the cache is populated' do
|
7
|
+
describe '#find' do
|
8
|
+
describe '#find(1)' do
|
9
|
+
it 'does not use the database' do
|
10
|
+
story = Story.create!
|
11
|
+
mock(Story.connection).execute.never
|
12
|
+
Story.find(story.id).should == story
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#find(object)' do
|
17
|
+
it 'uses the objects quoted id' do
|
18
|
+
story = Story.create!
|
19
|
+
mock(Story.connection).execute.never
|
20
|
+
Story.find(story).should == story
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#find(:first, ...)' do
|
25
|
+
describe '#find(:first, :conditions => { :id => ?})' do
|
26
|
+
it "does not use the database" do
|
27
|
+
story = Story.create!
|
28
|
+
mock(Story.connection).execute.never
|
29
|
+
Story.find(:first, :conditions => { :id => story.id }).should == story
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#find(:first, :conditions => 'id = ?')" do
|
34
|
+
it "does not use the database" do
|
35
|
+
story = Story.create!
|
36
|
+
mock(Story.connection).execute.never
|
37
|
+
Story.find(:first, :conditions => "id = #{story.id}").should == story
|
38
|
+
Story.find(:first, :conditions => "`stories`.id = #{story.id}").should == story
|
39
|
+
Story.find(:first, :conditions => "`stories`.`id` = #{story.id}").should == story
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#find(:first, :readonly => false) and any other options other than conditions are nil' do
|
44
|
+
it "does not use the database" do
|
45
|
+
story = Story.create!
|
46
|
+
mock(Story.connection).execute.never
|
47
|
+
Story.find(:first, :conditions => { :id => story.id }, :readonly => false, :limit => nil, :offset => nil, :joins => nil, :include => nil).should == story
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#find(:first, :readonly => true)' do
|
52
|
+
it "uses the database, not the cache" do
|
53
|
+
story = Story.create!
|
54
|
+
mock(Story).get.never
|
55
|
+
Story.find(:first, :conditions => { :id => story.id }, :readonly => true).should == story
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#find(:first, :join => ...) or find(..., :include => ...)' do
|
60
|
+
it "uses the database, not the cache" do
|
61
|
+
story = Story.create!
|
62
|
+
mock(Story).get.never
|
63
|
+
Story.find(:first, :conditions => { :id => story.id }, :joins => 'AS stories').should == story
|
64
|
+
Story.find(:first, :conditions => { :id => story.id }, :include => :characters).should == story
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#find(:first)' do
|
69
|
+
it 'uses the database, not the cache' do
|
70
|
+
mock(Story).get.never
|
71
|
+
Story.find(:first)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#find(:first, :conditions => "...")' do
|
76
|
+
describe 'on unindexed attributes' do
|
77
|
+
it 'uses the database, not the cache' do
|
78
|
+
story = Story.create!
|
79
|
+
mock(Story).get.never
|
80
|
+
Story.find(:first, :conditions => "type IS NULL")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'on indexed attributes' do
|
85
|
+
describe 'when the attributes are integers' do
|
86
|
+
it 'does not use the database' do
|
87
|
+
story = Story.create!
|
88
|
+
mock(Story.connection).execute.never
|
89
|
+
Story.find(:first, :conditions => "`stories`.id = #{story.id}") \
|
90
|
+
.should == story
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'when the attributes are non-integers' do
|
95
|
+
it 'uses the database, not the cache' do
|
96
|
+
story = Story.create!(:title => "title")
|
97
|
+
mock(Story.connection).execute.never
|
98
|
+
Story.find(:first, :conditions => "`stories`.title = '#{story.title }'") \
|
99
|
+
.should == story
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '#find(:first, :conditions => [...])' do
|
105
|
+
describe 'with one indexed attribute' do
|
106
|
+
it 'does not use the database' do
|
107
|
+
story = Story.create!
|
108
|
+
mock(Story.connection).execute.never
|
109
|
+
Story.find(:first, :conditions => ['id = ?', story.id]).should == story
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'with two attributes that match a combo-index' do
|
114
|
+
it 'does not use the database' do
|
115
|
+
story = Story.create!(:title => 'title')
|
116
|
+
mock(Story.connection).execute.never
|
117
|
+
Story.find(:first, :conditions => ['id = ? AND title = ?', story.id, story.title]).should == story
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#find(:first, :conditions => {...})' do
|
124
|
+
it "does not use the database" do
|
125
|
+
story = Story.create!(:title => "Sam")
|
126
|
+
mock(Story.connection).execute.never
|
127
|
+
Story.find(:first, :conditions => { :id => story.id, :title => story.title }).should == story
|
128
|
+
end
|
129
|
+
|
130
|
+
describe 'regardless of hash order' do
|
131
|
+
it 'does not use the database' do
|
132
|
+
story = Story.create!(:title => "Sam")
|
133
|
+
mock(Story.connection).execute.never
|
134
|
+
Story.find(:first, :conditions => { :id => story.id, :title => story.title }).should == story
|
135
|
+
Story.find(:first, :conditions => { :title => story.title, :id => story.id }).should == story
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'on unindexed attribtes' do
|
140
|
+
it 'uses the database, not the cache' do
|
141
|
+
story = Story.create!
|
142
|
+
mock(Story).get.never
|
143
|
+
Story.find(:first, :conditions => { :id => story.id, :type => story.type }).should == story
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe 'when there is a with_scope' do
|
150
|
+
describe 'when the with_scope has conditions' do
|
151
|
+
describe 'when the scope conditions is a string' do
|
152
|
+
it "uses the database, not the cache" do
|
153
|
+
story = Story.create!(:title => title = 'title')
|
154
|
+
mock(Story.connection).execute.never
|
155
|
+
Story.send :with_scope, :find => { :conditions => "title = '#{title}'"} do
|
156
|
+
Story.find(:first, :conditions => { :id => story.id }).should == story
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe 'when the find conditions is a string' do
|
162
|
+
it "does not use the database" do
|
163
|
+
story = Story.create!(:title => title = 'title')
|
164
|
+
mock(Story.connection).execute.never
|
165
|
+
Story.send :with_scope, :find => { :conditions => { :id => story.id }} do
|
166
|
+
Story.find(:first, :conditions => "title = '#{title}'").should == story
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#find(1, :conditions => ...)' do
|
172
|
+
it "does not use the database" do
|
173
|
+
story = Story.create!
|
174
|
+
character = Character.create!(:name => name = 'barbara', :story_id => story)
|
175
|
+
mock(Character.connection).execute.never
|
176
|
+
Character.send :with_scope, :find => { :conditions => { :story_id => story.id } } do
|
177
|
+
Character.find(character.id, :conditions => { :name => name }).should == character
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'has_many associations' do
|
184
|
+
describe '#find(1)' do
|
185
|
+
it "does not use the database" do
|
186
|
+
story = Story.create!
|
187
|
+
character = story.characters.create!
|
188
|
+
mock(Character.connection).execute.never
|
189
|
+
story.characters.find(character.id).should == character
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#find(1, 2, ...)' do
|
194
|
+
it "does not use the database" do
|
195
|
+
story = Story.create!
|
196
|
+
character1 = story.characters.create!
|
197
|
+
character2 = story.characters.create!
|
198
|
+
mock(Character.connection).execute.never
|
199
|
+
story.characters.find(character1.id, character2.id).should == [character1, character2]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe '#find_by_attr' do
|
204
|
+
it "does not use the database" do
|
205
|
+
story = Story.create!
|
206
|
+
character = story.characters.create!
|
207
|
+
mock(Character.connection).execute.never
|
208
|
+
story.characters.find_by_id(character.id).should == character
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe '#find(:all)' do
|
215
|
+
it "uses the database, not the cache" do
|
216
|
+
character = Character.create!
|
217
|
+
mock(Character).get.never
|
218
|
+
Character.find(:all).should == [character]
|
219
|
+
end
|
220
|
+
|
221
|
+
describe '#find(:all, :conditions => {...})' do
|
222
|
+
describe 'when the index is not empty' do
|
223
|
+
it 'does not use the database' do
|
224
|
+
story1 = Story.create!(:title => title = "title")
|
225
|
+
story2 = Story.create!(:title => title)
|
226
|
+
mock(Story.connection).execute.never
|
227
|
+
Story.find(:all, :conditions => { :title => story1.title }).should == [story1, story2]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe '#find(:all, :limit => ..., :offset => ...)' do
|
233
|
+
it "cached attributes should support limits and offsets" do
|
234
|
+
character1 = Character.create!(:name => "Sam", :story_id => 1)
|
235
|
+
character2 = Character.create!(:name => "Sam", :story_id => 1)
|
236
|
+
character3 = Character.create!(:name => "Sam", :story_id => 1)
|
237
|
+
mock(Character.connection).execute.never
|
238
|
+
|
239
|
+
Character.find(:all, :conditions => { :name => character1.name, :story_id => character1.story_id }, :limit => 1).should == [character1]
|
240
|
+
Character.find(:all, :conditions => { :name => character1.name, :story_id => character1.story_id }, :offset => 1).should == [character2, character3]
|
241
|
+
Character.find(:all, :conditions => { :name => character1.name, :story_id => character1.story_id }, :limit => 1, :offset => 1).should == [character2]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe '#find([...])' do
|
247
|
+
describe '#find([1, 2, ...], :conditions => ...)' do
|
248
|
+
it "uses the database, not the cache" do
|
249
|
+
story1, story2 = Story.create!, Story.create!
|
250
|
+
mock(Story).get.never
|
251
|
+
Story.find([story1.id, story2.id], :conditions => "type IS NULL").should == [story1, story2]
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe '#find([1], :conditions => ...)' do
|
256
|
+
it "uses the database, not the cache" do
|
257
|
+
story1, story2 = Story.create!, Story.create!
|
258
|
+
mock(Story).get.never
|
259
|
+
Story.find([story1.id], :conditions => "type IS NULL").should == [story1]
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe '#find_by_attr' do
|
265
|
+
describe 'on indexed attributes' do
|
266
|
+
describe '#find_by_id(id)' do
|
267
|
+
it "does not use the database" do
|
268
|
+
story = Story.create!
|
269
|
+
mock(Story.connection).execute.never
|
270
|
+
Story.find_by_id(story.id).should == story
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe '#find_by_title(title)' do
|
275
|
+
it "does not use the database" do
|
276
|
+
story1 = Story.create!(:title => 'title1')
|
277
|
+
story2 = Story.create!(:title => 'title2')
|
278
|
+
mock(Story.connection).execute.never
|
279
|
+
Story.find_by_title('title1').should == story1
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "Single Table Inheritence" do
|
286
|
+
describe '#find(:all, ...)' do
|
287
|
+
it "does not use the database" do
|
288
|
+
story, epic, oral = Story.create!(:title => title = 'foo'), Epic.create!(:title => title), Oral.create!(:title => title)
|
289
|
+
mock(Story.connection).execute.never
|
290
|
+
Story.find(:all, :conditions => { :title => title }).should == [story, epic, oral]
|
291
|
+
Epic.find(:all, :conditions => { :title => title }).should == [epic, oral]
|
292
|
+
Oral.find(:all, :conditions => { :title => title }).should == [oral]
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
describe '#without_cache' do
|
299
|
+
describe 'when finders are called within the provided block' do
|
300
|
+
it 'uses the database not the cache' do
|
301
|
+
story = Story.create!
|
302
|
+
mock(Story).get.never
|
303
|
+
Story.without_cache do
|
304
|
+
Story.find(story.id).should == story
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
describe 'when the cache is not populated' do
|
312
|
+
before do
|
313
|
+
@story = Story.create!(:title => 'title')
|
314
|
+
$memcache.flush_all
|
315
|
+
end
|
316
|
+
|
317
|
+
describe '#find(:first, ...)' do
|
318
|
+
it 'populates the cache' do
|
319
|
+
Story.find(:first, :conditions => { :title => @story.title })
|
320
|
+
Story.fetch("title/#{@story.title}").should == [@story.id]
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
describe '#find_by_attr' do
|
325
|
+
it 'populates the cache' do
|
326
|
+
Story.find_by_title(@story.title)
|
327
|
+
Story.fetch("title/#{@story.title}").should == [@story.id]
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe '#find(:all, :conditions => ...)' do
|
332
|
+
it 'populates the cache' do
|
333
|
+
Story.find(:all, :conditions => { :title => @story.title })
|
334
|
+
Story.fetch("title/#{@story.title}").should == [@story.id]
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
describe '#find(1)' do
|
339
|
+
it 'populates the cache' do
|
340
|
+
Story.find(@story.id)
|
341
|
+
Story.fetch("id/#{@story.id}").should == [@story]
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
describe 'when there is a with_scope' do
|
346
|
+
it "uses the database, not the cache" do
|
347
|
+
Story.send :with_scope, :find => { :conditions => { :title => @story.title }} do
|
348
|
+
Story.find(:first, :conditions => { :id => @story.id }).should == @story
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|