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