sequel 2.1.0 → 2.2.0

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/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
@@ -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 bands.* FROM bands WHERE (id IN (2))']
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 tracks.* FROM tracks WHERE (album_id IN (1))']
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 bands.* FROM bands WHERE (id IN (2))'))
155
- MODEL_DB.sqls[1..-1].should(include('SELECT tracks.* FROM tracks WHERE (album_id IN (1))'))
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 albums.* FROM albums WHERE (id IN (1))',
180
- 'SELECT bands.* FROM bands WHERE (id IN (2))',
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 albums.* FROM albums WHERE (band_id IN (2))',
202
- 'SELECT tracks.* FROM tracks WHERE (album_id IN (1))']
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 albums.* FROM albums WHERE (band_id = 2)',
227
- 'SELECT tracks.* FROM tracks WHERE (album_id IN (1))']
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 tracks.* FROM tracks WHERE (album_id IN (1))']
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 bands.* FROM bands WHERE (id IN (101))']
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 albums.* FROM albums WHERE (band_id IN (101, 102))', "SELECT tracks.* FROM tracks WHERE (album_id IN (101))"]
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 tracks.* FROM tracks WHERE ((album_id IN (1)) AND (name = 'Good'))"]
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 albums.* FROM albums WHERE ((band_id IN (2)) AND (name = 'good'))"]
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 albums.* FROM albums WHERE ((band_id IN (2)) AND (name = 'good'))", "SELECT tracks.* FROM tracks WHERE ((album_id IN (1)) AND (name = 'Good'))"]
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