sequel 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +37 -1
- data/Rakefile +2 -2
- data/doc/advanced_associations.rdoc +624 -0
- data/lib/sequel_model.rb +7 -2
- data/lib/sequel_model/association_reflection.rb +112 -2
- data/lib/sequel_model/associations.rb +171 -222
- data/lib/sequel_model/base.rb +28 -7
- data/lib/sequel_model/eager_loading.rb +12 -71
- data/lib/sequel_model/record.rb +143 -14
- data/lib/sequel_model/validations.rb +108 -17
- data/spec/association_reflection_spec.rb +10 -2
- data/spec/associations_spec.rb +449 -94
- data/spec/caching_spec.rb +72 -11
- data/spec/eager_loading_spec.rb +168 -21
- data/spec/hooks_spec.rb +53 -15
- data/spec/model_spec.rb +12 -11
- data/spec/spec_helper.rb +0 -7
- data/spec/validations_spec.rb +39 -16
- metadata +6 -4
data/spec/caching_spec.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
2
|
|
3
3
|
describe Sequel::Model, "caching" do
|
4
|
-
|
5
|
-
before(:each) do
|
4
|
+
before do
|
6
5
|
MODEL_DB.reset
|
7
6
|
|
8
7
|
@cache_class = Class.new(Hash) do
|
@@ -15,6 +14,7 @@ describe Sequel::Model, "caching" do
|
|
15
14
|
|
16
15
|
@c = Class.new(Sequel::Model(:items)) do
|
17
16
|
set_cache cache
|
17
|
+
def self.name; 'Item' end
|
18
18
|
|
19
19
|
columns :name, :id
|
20
20
|
end
|
@@ -37,37 +37,51 @@ describe Sequel::Model, "caching" do
|
|
37
37
|
$sqls << delete_sql
|
38
38
|
end
|
39
39
|
})
|
40
|
+
@c2 = Class.new(@c) do
|
41
|
+
def self.name; 'SubItem' end
|
42
|
+
end
|
40
43
|
end
|
41
44
|
|
42
45
|
it "should set the model's cache store" do
|
43
46
|
@c.cache_store.should be(@cache)
|
47
|
+
@c2.cache_store.should be(@cache)
|
44
48
|
end
|
45
49
|
|
46
50
|
it "should have a default ttl of 3600" do
|
47
51
|
@c.cache_ttl.should == 3600
|
52
|
+
@c2.cache_ttl.should == 3600
|
48
53
|
end
|
49
54
|
|
50
55
|
it "should take a ttl option" do
|
51
56
|
@c.set_cache @cache, :ttl => 1234
|
52
57
|
@c.cache_ttl.should == 1234
|
58
|
+
Class.new(@c).cache_ttl.should == 1234
|
53
59
|
end
|
54
60
|
|
55
61
|
it "should offer a set_cache_ttl method for setting the ttl" do
|
56
62
|
@c.cache_ttl.should == 3600
|
57
63
|
@c.set_cache_ttl 1234
|
58
64
|
@c.cache_ttl.should == 1234
|
65
|
+
Class.new(@c).cache_ttl.should == 1234
|
59
66
|
end
|
60
67
|
|
61
68
|
it "should generate a cache key appropriate to the class" do
|
62
69
|
m = @c.new
|
63
70
|
m.values[:id] = 1
|
64
71
|
m.cache_key.should == "#{m.class}:1"
|
72
|
+
m = @c2.new
|
73
|
+
m.values[:id] = 1
|
74
|
+
m.cache_key.should == "#{m.class}:1"
|
65
75
|
|
66
76
|
# custom primary key
|
67
77
|
@c.set_primary_key :ttt
|
68
78
|
m = @c.new
|
69
79
|
m.values[:ttt] = 333
|
70
80
|
m.cache_key.should == "#{m.class}:333"
|
81
|
+
c = Class.new(@c)
|
82
|
+
m = c.new
|
83
|
+
m.values[:ttt] = 333
|
84
|
+
m.cache_key.should == "#{m.class}:333"
|
71
85
|
|
72
86
|
# composite primary key
|
73
87
|
@c.set_primary_key [:a, :b, :c]
|
@@ -76,12 +90,22 @@ describe Sequel::Model, "caching" do
|
|
76
90
|
m.values[:c] = 456
|
77
91
|
m.values[:b] = 789
|
78
92
|
m.cache_key.should == "#{m.class}:123,789,456"
|
93
|
+
c = Class.new(@c)
|
94
|
+
m = c.new
|
95
|
+
m.values[:a] = 123
|
96
|
+
m.values[:c] = 456
|
97
|
+
m.values[:b] = 789
|
98
|
+
m.cache_key.should == "#{m.class}:123,789,456"
|
79
99
|
end
|
80
100
|
|
81
101
|
it "should raise error if attempting to generate cache_key and primary key value is null" do
|
82
102
|
m = @c.new
|
83
103
|
proc {m.cache_key}.should raise_error(Sequel::Error)
|
84
|
-
|
104
|
+
m.values[:id] = 1
|
105
|
+
proc {m.cache_key}.should_not raise_error(Sequel::Error)
|
106
|
+
|
107
|
+
m = @c2.new
|
108
|
+
proc {m.cache_key}.should raise_error(Sequel::Error)
|
85
109
|
m.values[:id] = 1
|
86
110
|
proc {m.cache_key}.should_not raise_error(Sequel::Error)
|
87
111
|
end
|
@@ -89,6 +113,8 @@ describe Sequel::Model, "caching" do
|
|
89
113
|
it "should not raise error if trying to save a new record" do
|
90
114
|
proc {@c.new(:name=>'blah').save}.should_not raise_error
|
91
115
|
proc {@c.create(:name=>'blah')}.should_not raise_error
|
116
|
+
proc {@c2.new(:name=>'blah').save}.should_not raise_error
|
117
|
+
proc {@c2.create(:name=>'blah')}.should_not raise_error
|
92
118
|
end
|
93
119
|
|
94
120
|
it "should set the cache when reading from the database" do
|
@@ -99,16 +125,23 @@ describe Sequel::Model, "caching" do
|
|
99
125
|
$sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
|
100
126
|
m.values.should == $cache_dataset_row
|
101
127
|
@cache[m.cache_key].should == m
|
102
|
-
|
103
|
-
# read from cache
|
104
128
|
m2 = @c[1]
|
105
129
|
$sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
|
106
130
|
m2.should == m
|
107
131
|
m2.values.should == $cache_dataset_row
|
132
|
+
|
133
|
+
$sqls.clear
|
134
|
+
m = @c2[1]
|
135
|
+
$sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
|
136
|
+
m.values.should == $cache_dataset_row
|
137
|
+
@cache[m.cache_key].should == m
|
138
|
+
m2 = @c2[1]
|
139
|
+
$sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
|
140
|
+
m2.should == m
|
141
|
+
m2.values.should == $cache_dataset_row
|
108
142
|
end
|
109
143
|
|
110
144
|
it "should delete the cache when writing to the database" do
|
111
|
-
# fill the cache
|
112
145
|
m = @c[1]
|
113
146
|
@cache[m.cache_key].should == m
|
114
147
|
|
@@ -122,13 +155,31 @@ describe Sequel::Model, "caching" do
|
|
122
155
|
m.save
|
123
156
|
@cache.has_key?(m.cache_key).should be_false
|
124
157
|
$sqls.last.should == "UPDATE items SET name = 'hey', id = 1 WHERE (id = 1)"
|
158
|
+
|
159
|
+
m = @c2[1]
|
160
|
+
@cache[m.cache_key].should == m
|
161
|
+
|
162
|
+
m.update_values(:name => 'tutu')
|
163
|
+
@cache.has_key?(m.cache_key).should be_false
|
164
|
+
$sqls.last.should == "UPDATE items SET name = 'tutu' WHERE (id = 1)"
|
165
|
+
|
166
|
+
m = @c2[1]
|
167
|
+
@cache[m.cache_key].should == m
|
168
|
+
m.name = 'hey'
|
169
|
+
m.save
|
170
|
+
@cache.has_key?(m.cache_key).should be_false
|
171
|
+
$sqls.last.should == "UPDATE items SET name = 'hey', id = 1 WHERE (id = 1)"
|
125
172
|
end
|
126
173
|
|
127
174
|
it "should delete the cache when deleting the record" do
|
128
|
-
# fill the cache
|
129
175
|
m = @c[1]
|
130
176
|
@cache[m.cache_key].should == m
|
131
|
-
|
177
|
+
m.delete
|
178
|
+
@cache.has_key?(m.cache_key).should be_false
|
179
|
+
$sqls.last.should == "DELETE FROM items WHERE (id = 1)"
|
180
|
+
|
181
|
+
m = @c2[1]
|
182
|
+
@cache[m.cache_key].should == m
|
132
183
|
m.delete
|
133
184
|
@cache.has_key?(m.cache_key).should be_false
|
134
185
|
$sqls.last.should == "DELETE FROM items WHERE (id = 1)"
|
@@ -138,16 +189,26 @@ describe Sequel::Model, "caching" do
|
|
138
189
|
m = @c[:id => 3]
|
139
190
|
@cache[m.cache_key].should be_nil
|
140
191
|
$sqls.last.should == "SELECT * FROM items WHERE (id = 3) LIMIT 1"
|
141
|
-
|
142
192
|
m = @c[1]
|
143
193
|
@cache[m.cache_key].should == m
|
144
194
|
$sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
|
145
195
|
"SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
146
|
-
|
147
196
|
@c[:id => 4]
|
148
197
|
$sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
|
149
198
|
"SELECT * FROM items WHERE (id = 1) LIMIT 1", \
|
150
199
|
"SELECT * FROM items WHERE (id = 4) LIMIT 1"]
|
200
|
+
|
201
|
+
$sqls.clear
|
202
|
+
m = @c2[:id => 3]
|
203
|
+
@cache[m.cache_key].should be_nil
|
204
|
+
$sqls.last.should == "SELECT * FROM items WHERE (id = 3) LIMIT 1"
|
205
|
+
m = @c2[1]
|
206
|
+
@cache[m.cache_key].should == m
|
207
|
+
$sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
|
208
|
+
"SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
209
|
+
@c2[:id => 4]
|
210
|
+
$sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
|
211
|
+
"SELECT * FROM items WHERE (id = 1) LIMIT 1", \
|
212
|
+
"SELECT * FROM items WHERE (id = 4) LIMIT 1"]
|
151
213
|
end
|
152
|
-
|
153
214
|
end
|
data/spec/eager_loading_spec.rb
CHANGED
@@ -20,6 +20,7 @@ describe Sequel::Model, "#eager" do
|
|
20
20
|
class EagerBand < Sequel::Model(:bands)
|
21
21
|
columns :id
|
22
22
|
one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks
|
23
|
+
one_to_many :graph_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_graph=>:tracks
|
23
24
|
many_to_many :members, :class=>'EagerBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
|
24
25
|
one_to_many :good_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_block=>proc{|ds| ds.filter(:name=>'good')} do |ds|
|
25
26
|
ds.filter(:name=>'Good')
|
@@ -28,6 +29,7 @@ describe Sequel::Model, "#eager" do
|
|
28
29
|
ds.filter(:name=>name)
|
29
30
|
end
|
30
31
|
one_to_many :albums_by_name, :class=>'EagerAlbum', :key=>:band_id, :order=>:name, :allow_eager=>false
|
32
|
+
one_to_many :top_10_albums, :class=>'EagerAlbum', :key=>:band_id, :limit=>10
|
31
33
|
end
|
32
34
|
|
33
35
|
class EagerTrack < Sequel::Model(:tracks)
|
@@ -46,6 +48,10 @@ describe Sequel::Model, "#eager" do
|
|
46
48
|
end
|
47
49
|
|
48
50
|
EagerAlbum.dataset.extend(Module.new {
|
51
|
+
def columns
|
52
|
+
[:id, :band_id]
|
53
|
+
end
|
54
|
+
|
49
55
|
def fetch_rows(sql)
|
50
56
|
h = if sql =~ /101/
|
51
57
|
{:id => 101, :band_id=> 101}
|
@@ -106,7 +112,7 @@ describe Sequel::Model, "#eager" do
|
|
106
112
|
a.size.should == 1
|
107
113
|
a.first.should be_a_kind_of(EagerAlbum)
|
108
114
|
a.first.values.should == {:id => 1, :band_id => 2}
|
109
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT
|
115
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (2))']
|
110
116
|
a = a.first
|
111
117
|
a.band.should be_a_kind_of(EagerBand)
|
112
118
|
a.band.values.should == {:id => 2}
|
@@ -119,7 +125,7 @@ describe Sequel::Model, "#eager" do
|
|
119
125
|
a.size.should == 1
|
120
126
|
a.first.should be_a_kind_of(EagerAlbum)
|
121
127
|
a.first.values.should == {:id => 1, :band_id => 2}
|
122
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT
|
128
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
123
129
|
a = a.first
|
124
130
|
a.tracks.should be_a_kind_of(Array)
|
125
131
|
a.tracks.size.should == 1
|
@@ -151,8 +157,8 @@ describe Sequel::Model, "#eager" do
|
|
151
157
|
a.first.values.should == {:id => 1, :band_id => 2}
|
152
158
|
MODEL_DB.sqls.length.should == 4
|
153
159
|
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
154
|
-
MODEL_DB.sqls[1..-1].should(include('SELECT
|
155
|
-
MODEL_DB.sqls[1..-1].should(include('SELECT
|
160
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM bands WHERE (bands.id IN (2))'))
|
161
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM tracks WHERE (tracks.album_id IN (1))'))
|
156
162
|
MODEL_DB.sqls[1..-1].should(include('SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))'))
|
157
163
|
a = a.first
|
158
164
|
a.band.should be_a_kind_of(EagerBand)
|
@@ -176,8 +182,8 @@ describe Sequel::Model, "#eager" do
|
|
176
182
|
a.first.values.should == {:id => 3, :album_id => 1}
|
177
183
|
MODEL_DB.sqls.length.should == 4
|
178
184
|
MODEL_DB.sqls.should == ['SELECT * FROM tracks',
|
179
|
-
'SELECT
|
180
|
-
'SELECT
|
185
|
+
'SELECT * FROM albums WHERE (albums.id IN (1))',
|
186
|
+
'SELECT * FROM bands WHERE (bands.id IN (2))',
|
181
187
|
"SELECT members.*, bm.band_id AS x_foreign_key_x FROM members INNER JOIN bm ON ((bm.member_id = members.id) AND (bm.band_id IN (2)))"]
|
182
188
|
a = a.first
|
183
189
|
a.album.should be_a_kind_of(EagerAlbum)
|
@@ -198,8 +204,8 @@ describe Sequel::Model, "#eager" do
|
|
198
204
|
a.first.should be_a_kind_of(EagerBand)
|
199
205
|
a.first.values.should == {:id => 2}
|
200
206
|
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
201
|
-
'SELECT
|
202
|
-
'SELECT
|
207
|
+
'SELECT * FROM albums WHERE (albums.band_id IN (2))',
|
208
|
+
'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
203
209
|
a = a.first
|
204
210
|
a.albums.should be_a_kind_of(Array)
|
205
211
|
a.albums.size.should == 1
|
@@ -223,8 +229,8 @@ describe Sequel::Model, "#eager" do
|
|
223
229
|
a = a.first
|
224
230
|
a.albums
|
225
231
|
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
226
|
-
'SELECT
|
227
|
-
'SELECT
|
232
|
+
'SELECT * FROM albums WHERE (albums.band_id = 2)',
|
233
|
+
'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
228
234
|
a.albums.should be_a_kind_of(Array)
|
229
235
|
a.albums.size.should == 1
|
230
236
|
a.albums.first.should be_a_kind_of(EagerAlbum)
|
@@ -237,6 +243,62 @@ describe Sequel::Model, "#eager" do
|
|
237
243
|
MODEL_DB.sqls.length.should == 3
|
238
244
|
end
|
239
245
|
|
246
|
+
it "should cascade eagerly loading when the :eager_graph association option is used" do
|
247
|
+
EagerAlbum.dataset.extend(Module.new {
|
248
|
+
def fetch_rows(sql)
|
249
|
+
@db << sql
|
250
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
251
|
+
end
|
252
|
+
})
|
253
|
+
a = EagerBand.eager(:graph_albums).all
|
254
|
+
a.should be_a_kind_of(Array)
|
255
|
+
a.size.should == 1
|
256
|
+
a.first.should be_a_kind_of(EagerBand)
|
257
|
+
a.first.values.should == {:id => 2}
|
258
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
259
|
+
'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) WHERE (albums.band_id IN (2))']
|
260
|
+
a = a.first
|
261
|
+
a.graph_albums.should be_a_kind_of(Array)
|
262
|
+
a.graph_albums.size.should == 1
|
263
|
+
a.graph_albums.first.should be_a_kind_of(EagerAlbum)
|
264
|
+
a.graph_albums.first.values.should == {:id => 1, :band_id => 2}
|
265
|
+
a = a.graph_albums.first
|
266
|
+
a.tracks.should be_a_kind_of(Array)
|
267
|
+
a.tracks.size.should == 1
|
268
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
269
|
+
a.tracks.first.values.should == {:id => 3, :album_id => 1}
|
270
|
+
MODEL_DB.sqls.length.should == 2
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should respect :eager_graph when lazily loading an association" do
|
274
|
+
a = EagerBand.all
|
275
|
+
a.should be_a_kind_of(Array)
|
276
|
+
a.size.should == 1
|
277
|
+
a.first.should be_a_kind_of(EagerBand)
|
278
|
+
a.first.values.should == {:id => 2}
|
279
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands']
|
280
|
+
a = a.first
|
281
|
+
EagerAlbum.dataset.extend(Module.new {
|
282
|
+
def fetch_rows(sql)
|
283
|
+
@db << sql
|
284
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
285
|
+
end
|
286
|
+
})
|
287
|
+
a.graph_albums
|
288
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
289
|
+
'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) WHERE (albums.band_id = 2)']
|
290
|
+
a.graph_albums.should be_a_kind_of(Array)
|
291
|
+
a.graph_albums.size.should == 1
|
292
|
+
a.graph_albums.first.should be_a_kind_of(EagerAlbum)
|
293
|
+
a.graph_albums.first.values.should == {:id => 1, :band_id => 2}
|
294
|
+
a = a.graph_albums.first
|
295
|
+
a.tracks.should be_a_kind_of(Array)
|
296
|
+
a.tracks.size.should == 1
|
297
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
298
|
+
a.tracks.first.values.should == {:id => 3, :album_id => 1}
|
299
|
+
MODEL_DB.sqls.length.should == 2
|
300
|
+
end
|
301
|
+
|
240
302
|
it "should respect :order when eagerly loading" do
|
241
303
|
a = EagerBandMember.eager(:bands).all
|
242
304
|
a.should be_a_kind_of(Array)
|
@@ -258,7 +320,7 @@ describe Sequel::Model, "#eager" do
|
|
258
320
|
a.size.should == 1
|
259
321
|
a.first.should be_a_kind_of(EagerAlbum)
|
260
322
|
a.first.values.should == {:id => 1, :band_id => 2}
|
261
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT
|
323
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
262
324
|
a = a.first
|
263
325
|
a.tracks.should be_a_kind_of(Array)
|
264
326
|
a.tracks.size.should == 1
|
@@ -275,7 +337,7 @@ describe Sequel::Model, "#eager" do
|
|
275
337
|
a.size.should == 1
|
276
338
|
a.first.should be_a_kind_of(EagerAlbum)
|
277
339
|
a.first.values.should == {:id => 101, :band_id => 101}
|
278
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums WHERE (id = 101)', 'SELECT
|
340
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums WHERE (id = 101)', 'SELECT * FROM bands WHERE (bands.id IN (101))']
|
279
341
|
a = a.first
|
280
342
|
a.associations.fetch(:band, 2).should == nil
|
281
343
|
a.band.should == nil
|
@@ -289,7 +351,7 @@ describe Sequel::Model, "#eager" do
|
|
289
351
|
a.first.should be_a_kind_of(EagerBand)
|
290
352
|
a.first.values.should == {:id => 101}
|
291
353
|
a.last.values.should == {:id => 102}
|
292
|
-
MODEL_DB.sqls.should == ['SELECT * FROM bands WHERE (id > 100)', 'SELECT
|
354
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands WHERE (id > 100)', 'SELECT * FROM albums WHERE (albums.band_id IN (101, 102))', "SELECT * FROM tracks WHERE (tracks.album_id IN (101))"]
|
293
355
|
a.first.associations[:albums].should be_a_kind_of(Array)
|
294
356
|
a.first.albums.length.should == 1
|
295
357
|
a.first.albums.first.should be_a_kind_of(EagerAlbum)
|
@@ -300,15 +362,15 @@ describe Sequel::Model, "#eager" do
|
|
300
362
|
|
301
363
|
it "should use the association's block when eager loading by default" do
|
302
364
|
EagerAlbum.eager(:good_tracks).all
|
303
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT
|
365
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM tracks WHERE ((tracks.album_id IN (1)) AND (name = 'Good'))"]
|
304
366
|
end
|
305
367
|
|
306
368
|
it "should use the eager_block option when eager loading if given" do
|
307
369
|
EagerBand.eager(:good_albums).all
|
308
|
-
MODEL_DB.sqls.should == ['SELECT * FROM bands', "SELECT
|
370
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands', "SELECT * FROM albums WHERE ((albums.band_id IN (2)) AND (name = 'good'))"]
|
309
371
|
MODEL_DB.sqls.clear
|
310
372
|
EagerBand.eager(:good_albums=>:good_tracks).all
|
311
|
-
MODEL_DB.sqls.should == ['SELECT * FROM bands', "SELECT
|
373
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands', "SELECT * FROM albums WHERE ((albums.band_id IN (2)) AND (name = 'good'))", "SELECT * FROM tracks WHERE ((tracks.album_id IN (1)) AND (name = 'Good'))"]
|
312
374
|
end
|
313
375
|
|
314
376
|
it "should raise an error when attempting to eagerly load an association with the :allow_eager option set to false" do
|
@@ -318,14 +380,52 @@ describe Sequel::Model, "#eager" do
|
|
318
380
|
|
319
381
|
it "should respect the association's :select option" do
|
320
382
|
EagerAlbum.eager(:band_name).all
|
321
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM bands WHERE (id IN (2))"]
|
383
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM bands WHERE (bands.id IN (2))"]
|
322
384
|
MODEL_DB.sqls.clear
|
323
385
|
EagerAlbum.eager(:track_names).all
|
324
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM tracks WHERE (album_id IN (1))"]
|
386
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM tracks WHERE (tracks.album_id IN (1))"]
|
325
387
|
MODEL_DB.sqls.clear
|
326
388
|
EagerAlbum.eager(:genre_names).all
|
327
389
|
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
|
328
390
|
end
|
391
|
+
|
392
|
+
it "should use the :eager_loader association option when eager loading" do
|
393
|
+
EagerAlbum.many_to_one :special_band, :eager_loader=>(proc do |key_hash, records, assocs|
|
394
|
+
item = EagerBand.filter(:album_id=>records.collect{|r| [r.pk, r.pk*2]}.flatten).order(:name).first
|
395
|
+
records.each{|r| r.associations[:special_band] = item}
|
396
|
+
end)
|
397
|
+
EagerAlbum.one_to_many :special_tracks, :eager_loader=>(proc do |key_hash, records, assocs|
|
398
|
+
items = EagerTrack.filter(:album_id=>records.collect{|r| [r.pk, r.pk*2]}.flatten).all
|
399
|
+
records.each{|r| r.associations[:special_tracks] = items}
|
400
|
+
end)
|
401
|
+
EagerAlbum.many_to_many :special_genres, :eager_loader=>(proc do |key_hash, records, assocs|
|
402
|
+
items = EagerGenre.inner_join(:ag, [:genre_id]).filter(:album_id=>records.collect{|r| r.pk}).all
|
403
|
+
records.each{|r| r.associations[:special_genres] = items}
|
404
|
+
end)
|
405
|
+
a = EagerAlbum.eager(:special_genres, :special_tracks, :special_band).all
|
406
|
+
a.should be_a_kind_of(Array)
|
407
|
+
a.size.should == 1
|
408
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
409
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
410
|
+
MODEL_DB.sqls.length.should == 4
|
411
|
+
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
412
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM bands WHERE (album_id IN (1, 2)) ORDER BY name LIMIT 1'))
|
413
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM tracks WHERE (album_id IN (1, 2))'))
|
414
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM genres INNER JOIN ag USING (genre_id) WHERE (album_id IN (1))'))
|
415
|
+
a = a.first
|
416
|
+
a.special_band.should be_a_kind_of(EagerBand)
|
417
|
+
a.special_band.values.should == {:id => 2}
|
418
|
+
a.special_tracks.should be_a_kind_of(Array)
|
419
|
+
a.special_tracks.size.should == 1
|
420
|
+
a.special_tracks.first.should be_a_kind_of(EagerTrack)
|
421
|
+
a.special_tracks.first.values.should == {:id => 3, :album_id=>1}
|
422
|
+
a.special_genres.should be_a_kind_of(Array)
|
423
|
+
a.special_genres.size.should == 1
|
424
|
+
a.special_genres.first.should be_a_kind_of(EagerGenre)
|
425
|
+
a.special_genres.first.values.should == {:id => 4}
|
426
|
+
MODEL_DB.sqls.length.should == 4
|
427
|
+
end
|
428
|
+
|
329
429
|
end
|
330
430
|
|
331
431
|
describe Sequel::Model, "#eager_graph" do
|
@@ -735,15 +835,23 @@ describe Sequel::Model, "#eager_graph" do
|
|
735
835
|
GraphAlbum.eager_graph(:inner_genres).sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
|
736
836
|
end
|
737
837
|
|
838
|
+
it "should respect the association's :graph_join_type option" do
|
839
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_join_type=>:inner
|
840
|
+
GraphAlbum.eager_graph(:inner_genres).sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
|
841
|
+
|
842
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_join_type=>:inner, :graph_join_type=>:right_outer
|
843
|
+
GraphAlbum.eager_graph(:inner_genres).sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) RIGHT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
|
844
|
+
end
|
845
|
+
|
738
846
|
it "should respect the association's :graph_conditions option" do
|
739
847
|
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:active=>true}
|
740
848
|
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active = 't'))"
|
741
849
|
|
850
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:id=>(0..100)}
|
851
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND ((right_tracks.id >= 0) AND (right_tracks.id <= 100)))'
|
852
|
+
|
742
853
|
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}
|
743
854
|
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
744
|
-
|
745
|
-
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:id=>(0..100)}
|
746
|
-
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND ((active_band.id >= 0) AND (active_band.id <= 100)))"
|
747
855
|
end
|
748
856
|
|
749
857
|
it "should respect the association's :graph_join_table_conditions option" do
|
@@ -753,4 +861,43 @@ describe Sequel::Model, "#eager_graph" do
|
|
753
861
|
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}, :graph_join_table_conditions=>{true=>:active}
|
754
862
|
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND ('t' = albums.active)) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
755
863
|
end
|
864
|
+
|
865
|
+
it "should respect the association's :graph_block option" do
|
866
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_block=>proc{|ja,lja,js| {:active.qualify(ja)=>true}}
|
867
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active = 't'))"
|
868
|
+
|
869
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_block=>proc{|ja,lja,js| {:id.qualify(ja)=>(0..100)}}
|
870
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND ((right_tracks.id >= 0) AND (right_tracks.id <= 100)))'
|
871
|
+
|
872
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_block=>proc{|ja,lja,js| {true=>:active.qualify(lja)}}
|
873
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
874
|
+
end
|
875
|
+
|
876
|
+
it "should respect the association's :graph_join_block option" do
|
877
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_block=>proc{|ja,lja,js| {:active.qualify(ja)=>true}}
|
878
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND (ag.active = 't')) LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
|
879
|
+
|
880
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_block=>proc{|ja,lja,js| {true=>:active.qualify(lja)}}, :graph_join_table_block=>proc{|ja,lja,js| {true=>:active.qualify(lja)}}
|
881
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND ('t' = albums.active)) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
882
|
+
end
|
883
|
+
|
884
|
+
it "should respect the association's :graph_only_conditions option" do
|
885
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_only_conditions=>{:active=>true}
|
886
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON (active_band.active = 't')"
|
887
|
+
|
888
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_only_conditions=>nil, :graph_join_type=>:natural
|
889
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums NATURAL JOIN tracks AS right_tracks'
|
890
|
+
|
891
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>[:album_id]
|
892
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres USING (album_id)"
|
893
|
+
end
|
894
|
+
|
895
|
+
it "should respect the association's :graph_join_table_only_conditions option" do
|
896
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_only_conditions=>{:active=>true}
|
897
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.active = 't') LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
|
898
|
+
|
899
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>(:price + 2 > 100), :graph_join_table_only_conditions=>"active"
|
900
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (active) LEFT OUTER JOIN genres AS active_genres ON ((price + 2) > 100)"
|
901
|
+
end
|
902
|
+
|
756
903
|
end
|