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/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