sequel 1.5.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +30 -0
- data/README +12 -15
- data/Rakefile +9 -20
- data/lib/sequel_model.rb +47 -72
- data/lib/sequel_model/association_reflection.rb +59 -0
- data/lib/sequel_model/associations.rb +99 -94
- data/lib/sequel_model/base.rb +308 -102
- data/lib/sequel_model/caching.rb +72 -27
- data/lib/sequel_model/eager_loading.rb +308 -300
- data/lib/sequel_model/hooks.rb +51 -49
- data/lib/sequel_model/inflector.rb +186 -182
- data/lib/sequel_model/plugins.rb +54 -40
- data/lib/sequel_model/record.rb +185 -220
- data/lib/sequel_model/schema.rb +27 -34
- data/lib/sequel_model/validations.rb +54 -73
- data/spec/association_reflection_spec.rb +85 -0
- data/spec/associations_spec.rb +160 -73
- data/spec/base_spec.rb +3 -3
- data/spec/eager_loading_spec.rb +132 -35
- data/spec/hooks_spec.rb +120 -20
- data/spec/inflector_spec.rb +2 -2
- data/spec/model_spec.rb +110 -78
- data/spec/plugins_spec.rb +4 -0
- data/spec/rcov.opts +1 -1
- data/spec/record_spec.rb +160 -59
- data/spec/spec.opts +0 -5
- data/spec/spec_helper.rb +12 -0
- data/spec/validations_spec.rb +23 -0
- metadata +60 -50
- data/lib/sequel_model/deprecated.rb +0 -81
- data/lib/sequel_model/inflections.rb +0 -112
- data/spec/deprecated_relations_spec.rb +0 -113
data/spec/base_spec.rb
CHANGED
@@ -240,10 +240,10 @@ end
|
|
240
240
|
|
241
241
|
describe "Model.db=" do
|
242
242
|
setup do
|
243
|
-
$db1 =
|
244
|
-
$db2 =
|
243
|
+
$db1 = MockDatabase.new
|
244
|
+
$db2 = MockDatabase.new
|
245
245
|
|
246
|
-
class BlueBlue < Sequel::Model
|
246
|
+
class BlueBlue < Sequel::Model(:items)
|
247
247
|
set_dataset $db1[:blue]
|
248
248
|
end
|
249
249
|
end
|
data/spec/eager_loading_spec.rb
CHANGED
@@ -9,12 +9,25 @@ describe Sequel::Model, "#eager" do
|
|
9
9
|
many_to_one :band, :class=>'EagerBand', :key=>:band_id
|
10
10
|
one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id
|
11
11
|
many_to_many :genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
|
12
|
+
one_to_many :good_tracks, :class=>'EagerTrack', :key=>:album_id do |ds|
|
13
|
+
ds.filter(:name=>'Good')
|
14
|
+
end
|
15
|
+
many_to_one :band_name, :class=>'EagerBand', :key=>:band_id, :select=>[:id, :name]
|
16
|
+
one_to_many :track_names, :class=>'EagerTrack', :key=>:album_id, :select=>[:id, :name]
|
17
|
+
many_to_many :genre_names, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :select=>[:id]
|
12
18
|
end
|
13
19
|
|
14
20
|
class EagerBand < Sequel::Model(:bands)
|
15
21
|
columns :id
|
16
22
|
one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks
|
17
23
|
many_to_many :members, :class=>'EagerBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
|
24
|
+
one_to_many :good_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_block=>proc{|ds| ds.filter(:name=>'good')} do |ds|
|
25
|
+
ds.filter(:name=>'Good')
|
26
|
+
end
|
27
|
+
one_to_many :self_titled_albums, :class=>'EagerAlbum', :key=>:band_id, :allow_eager=>false do |ds|
|
28
|
+
ds.filter(:name=>name)
|
29
|
+
end
|
30
|
+
one_to_many :albums_by_name, :class=>'EagerAlbum', :key=>:band_id, :order=>:name, :allow_eager=>false
|
18
31
|
end
|
19
32
|
|
20
33
|
class EagerTrack < Sequel::Model(:tracks)
|
@@ -34,7 +47,11 @@ describe Sequel::Model, "#eager" do
|
|
34
47
|
|
35
48
|
EagerAlbum.dataset.extend(Module.new {
|
36
49
|
def fetch_rows(sql)
|
37
|
-
h =
|
50
|
+
h = if sql =~ /101/
|
51
|
+
{:id => 101, :band_id=> 101}
|
52
|
+
else
|
53
|
+
{:id => 1, :band_id=> 2}
|
54
|
+
end
|
38
55
|
h.merge!(:x_foreign_key_x=>4) if sql =~ /ag\.genre_id/
|
39
56
|
@db << sql
|
40
57
|
yield h
|
@@ -46,7 +63,14 @@ describe Sequel::Model, "#eager" do
|
|
46
63
|
h = {:id => 2}
|
47
64
|
h.merge!(:x_foreign_key_x=>5) if sql =~ /bm\.member_id/
|
48
65
|
@db << sql
|
49
|
-
|
66
|
+
case sql
|
67
|
+
when /id IN (101)/
|
68
|
+
when /id > 100/
|
69
|
+
yield({:id => 101})
|
70
|
+
yield({:id => 102})
|
71
|
+
else
|
72
|
+
yield h
|
73
|
+
end
|
50
74
|
end
|
51
75
|
})
|
52
76
|
|
@@ -82,7 +106,7 @@ describe Sequel::Model, "#eager" do
|
|
82
106
|
a.size.should == 1
|
83
107
|
a.first.should be_a_kind_of(EagerAlbum)
|
84
108
|
a.first.values.should == {:id => 1, :band_id => 2}
|
85
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT
|
109
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT bands.* FROM bands WHERE (id IN (2))']
|
86
110
|
a = a.first
|
87
111
|
a.band.should be_a_kind_of(EagerBand)
|
88
112
|
a.band.values.should == {:id => 2}
|
@@ -95,7 +119,7 @@ describe Sequel::Model, "#eager" do
|
|
95
119
|
a.size.should == 1
|
96
120
|
a.first.should be_a_kind_of(EagerAlbum)
|
97
121
|
a.first.values.should == {:id => 1, :band_id => 2}
|
98
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT
|
122
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT tracks.* FROM tracks WHERE (album_id IN (1))']
|
99
123
|
a = a.first
|
100
124
|
a.tracks.should be_a_kind_of(Array)
|
101
125
|
a.tracks.size.should == 1
|
@@ -110,11 +134,7 @@ describe Sequel::Model, "#eager" do
|
|
110
134
|
a.size.should == 1
|
111
135
|
a.first.should be_a_kind_of(EagerAlbum)
|
112
136
|
a.first.values.should == {:id => 1, :band_id => 2}
|
113
|
-
MODEL_DB.sqls.
|
114
|
-
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
115
|
-
["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))",
|
116
|
-
"SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.album_id IN (1)) AND (ag.genre_id = genres.id)"
|
117
|
-
].should(include(MODEL_DB.sqls[1]))
|
137
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "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)))"]
|
118
138
|
a = a.first
|
119
139
|
a.genres.should be_a_kind_of(Array)
|
120
140
|
a.genres.size.should == 1
|
@@ -131,12 +151,9 @@ describe Sequel::Model, "#eager" do
|
|
131
151
|
a.first.values.should == {:id => 1, :band_id => 2}
|
132
152
|
MODEL_DB.sqls.length.should == 4
|
133
153
|
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
134
|
-
MODEL_DB.sqls[1..-1].should(include('SELECT
|
135
|
-
MODEL_DB.sqls[1..-1].should(include('SELECT
|
136
|
-
|
137
|
-
["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))",
|
138
|
-
"SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.album_id IN (1)) AND (ag.genre_id = genres.id)"
|
139
|
-
].should(include(sqls[0]))
|
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))'))
|
156
|
+
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)))'))
|
140
157
|
a = a.first
|
141
158
|
a.band.should be_a_kind_of(EagerBand)
|
142
159
|
a.band.values.should == {:id => 2}
|
@@ -158,12 +175,10 @@ describe Sequel::Model, "#eager" do
|
|
158
175
|
a.first.should be_a_kind_of(EagerTrack)
|
159
176
|
a.first.values.should == {:id => 3, :album_id => 1}
|
160
177
|
MODEL_DB.sqls.length.should == 4
|
161
|
-
MODEL_DB.sqls
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
"SELECT members.*, bm.band_id AS x_foreign_key_x FROM members INNER JOIN bm ON (bm.band_id IN (2)) AND (bm.member_id = members.id)"
|
166
|
-
].should(include(MODEL_DB.sqls[-1]))
|
178
|
+
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))',
|
181
|
+
"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)))"]
|
167
182
|
a = a.first
|
168
183
|
a.album.should be_a_kind_of(EagerAlbum)
|
169
184
|
a.album.values.should == {:id => 1, :band_id => 2}
|
@@ -183,8 +198,8 @@ describe Sequel::Model, "#eager" do
|
|
183
198
|
a.first.should be_a_kind_of(EagerBand)
|
184
199
|
a.first.values.should == {:id => 2}
|
185
200
|
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
186
|
-
'SELECT
|
187
|
-
'SELECT
|
201
|
+
'SELECT albums.* FROM albums WHERE (band_id IN (2))',
|
202
|
+
'SELECT tracks.* FROM tracks WHERE (album_id IN (1))']
|
188
203
|
a = a.first
|
189
204
|
a.albums.should be_a_kind_of(Array)
|
190
205
|
a.albums.size.should == 1
|
@@ -208,8 +223,8 @@ describe Sequel::Model, "#eager" do
|
|
208
223
|
a = a.first
|
209
224
|
a.albums
|
210
225
|
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
211
|
-
'SELECT
|
212
|
-
'SELECT
|
226
|
+
'SELECT albums.* FROM albums WHERE (band_id = 2)',
|
227
|
+
'SELECT tracks.* FROM tracks WHERE (album_id IN (1))']
|
213
228
|
a.albums.should be_a_kind_of(Array)
|
214
229
|
a.albums.size.should == 1
|
215
230
|
a.albums.first.should be_a_kind_of(EagerAlbum)
|
@@ -228,11 +243,7 @@ describe Sequel::Model, "#eager" do
|
|
228
243
|
a.size.should == 1
|
229
244
|
a.first.should be_a_kind_of(EagerBandMember)
|
230
245
|
a.first.values.should == {:id => 5}
|
231
|
-
MODEL_DB.sqls.
|
232
|
-
MODEL_DB.sqls[0].should == 'SELECT * FROM members'
|
233
|
-
['SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON (bm.band_id = bands.id) AND (bm.member_id IN (5)) ORDER BY id',
|
234
|
-
'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON (bm.member_id IN (5)) AND (bm.band_id = bands.id) ORDER BY id'
|
235
|
-
].should(include(MODEL_DB.sqls[1]))
|
246
|
+
MODEL_DB.sqls.should == ['SELECT * FROM members', 'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON ((bm.band_id = bands.id) AND (bm.member_id IN (5))) ORDER BY id']
|
236
247
|
a = a.first
|
237
248
|
a.bands.should be_a_kind_of(Array)
|
238
249
|
a.bands.size.should == 1
|
@@ -247,7 +258,7 @@ describe Sequel::Model, "#eager" do
|
|
247
258
|
a.size.should == 1
|
248
259
|
a.first.should be_a_kind_of(EagerAlbum)
|
249
260
|
a.first.values.should == {:id => 1, :band_id => 2}
|
250
|
-
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT
|
261
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT tracks.* FROM tracks WHERE (album_id IN (1))']
|
251
262
|
a = a.first
|
252
263
|
a.tracks.should be_a_kind_of(Array)
|
253
264
|
a.tracks.size.should == 1
|
@@ -257,6 +268,64 @@ describe Sequel::Model, "#eager" do
|
|
257
268
|
a.tracks.first.album.should == a
|
258
269
|
MODEL_DB.sqls.length.should == 2
|
259
270
|
end
|
271
|
+
|
272
|
+
it "should cache the negative lookup when eagerly loading a many_to_one association" do
|
273
|
+
a = EagerAlbum.eager(:band).filter(:id=>101).all
|
274
|
+
a.should be_a_kind_of(Array)
|
275
|
+
a.size.should == 1
|
276
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
277
|
+
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))']
|
279
|
+
a = a.first
|
280
|
+
a.instance_variable_get(:@band).should == :null
|
281
|
+
a.band.should == nil
|
282
|
+
MODEL_DB.sqls.length.should == 2
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should cache the negative lookup when eagerly loading a *_to_many associations" do
|
286
|
+
a = EagerBand.eager(:albums).filter('id > 100').all
|
287
|
+
a.should be_a_kind_of(Array)
|
288
|
+
a.size.should == 2
|
289
|
+
a.first.should be_a_kind_of(EagerBand)
|
290
|
+
a.first.values.should == {:id => 101}
|
291
|
+
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))"]
|
293
|
+
a.first.instance_variable_get(:@albums).should be_a_kind_of(Array)
|
294
|
+
a.first.albums.length.should == 1
|
295
|
+
a.first.albums.first.should be_a_kind_of(EagerAlbum)
|
296
|
+
a.last.instance_variable_get(:@albums).should == []
|
297
|
+
a.last.albums.should == []
|
298
|
+
MODEL_DB.sqls.length.should == 3
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should use the association's block when eager loading by default" do
|
302
|
+
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'))"]
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should use the eager_block option when eager loading if given" do
|
307
|
+
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'))"]
|
309
|
+
MODEL_DB.sqls.clear
|
310
|
+
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'))"]
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should raise an error when attempting to eagerly load an association with the :allow_eager option set to false" do
|
315
|
+
proc{EagerBand.eager(:self_titled_albums).all}.should raise_error(Sequel::Error)
|
316
|
+
proc{EagerBand.eager(:albums_by_name).all}.should raise_error(Sequel::Error)
|
317
|
+
end
|
318
|
+
|
319
|
+
it "should respect the association's :select option" do
|
320
|
+
EagerAlbum.eager(:band_name).all
|
321
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM bands WHERE (id IN (2))"]
|
322
|
+
MODEL_DB.sqls.clear
|
323
|
+
EagerAlbum.eager(:track_names).all
|
324
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM tracks WHERE (album_id IN (1))"]
|
325
|
+
MODEL_DB.sqls.clear
|
326
|
+
EagerAlbum.eager(:genre_names).all
|
327
|
+
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
|
+
end
|
260
329
|
end
|
261
330
|
|
262
331
|
describe Sequel::Model, "#eager_graph" do
|
@@ -540,10 +609,8 @@ describe Sequel::Model, "#eager_graph" do
|
|
540
609
|
a.genres.size.should == 1
|
541
610
|
a.genres.first.should be_a_kind_of(GraphGenre)
|
542
611
|
a.genres.first.values.should == {:id=>6}
|
543
|
-
MODEL_DB.sqls
|
544
|
-
|
545
|
-
"SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.album_id IN (1)) AND (ag.genre_id = genres.id)"
|
546
|
-
].should(include(MODEL_DB.sqls[1]))
|
612
|
+
MODEL_DB.sqls.should == ['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)',
|
613
|
+
"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)))"]
|
547
614
|
end
|
548
615
|
|
549
616
|
it "should handle no associated records for a single many_to_one association" do
|
@@ -645,4 +712,34 @@ describe Sequel::Model, "#eager_graph" do
|
|
645
712
|
a[3].album.band.members.last.should be_a_kind_of(GraphBandMember)
|
646
713
|
a[3].album.band.members.last.values.should == {:id => 6}
|
647
714
|
end
|
715
|
+
|
716
|
+
it "should respect the association's :graph_join_type option" do
|
717
|
+
GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_join_type=>:inner
|
718
|
+
GraphAlbum.eager_graph(:inner_band).sql.should == 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums INNER JOIN bands inner_band ON (inner_band.id = albums.band_id)'
|
719
|
+
|
720
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_join_type=>:right_outer
|
721
|
+
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 RIGHT OUTER JOIN tracks right_tracks ON (right_tracks.album_id = albums.id)'
|
722
|
+
|
723
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_type=>:inner
|
724
|
+
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 inner_genres ON (inner_genres.id = ag.genre_id)'
|
725
|
+
end
|
726
|
+
|
727
|
+
it "should respect the association's :graph_conditions option" do
|
728
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:active=>true}
|
729
|
+
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 active_band ON ((active_band.id = albums.band_id) AND (active_band.active = 't'))"
|
730
|
+
|
731
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}
|
732
|
+
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 active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
733
|
+
|
734
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:id=>(0..100)}
|
735
|
+
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 active_band ON ((active_band.id = albums.band_id) AND ((active_band.id >= 0) AND (active_band.id <= 100)))"
|
736
|
+
end
|
737
|
+
|
738
|
+
it "should respect the association's :graph_join_table_conditions option" do
|
739
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_conditions=>{:active=>true}
|
740
|
+
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 active_genres ON (active_genres.id = ag.genre_id)"
|
741
|
+
|
742
|
+
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}
|
743
|
+
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 active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
744
|
+
end
|
648
745
|
end
|
data/spec/hooks_spec.rb
CHANGED
@@ -3,20 +3,6 @@ require File.join(File.dirname(__FILE__), "spec_helper")
|
|
3
3
|
describe "Model hooks" do
|
4
4
|
before do
|
5
5
|
MODEL_DB.reset
|
6
|
-
|
7
|
-
@hooks = [
|
8
|
-
:after_initialize,
|
9
|
-
:before_create,
|
10
|
-
:after_create,
|
11
|
-
:before_update,
|
12
|
-
:after_update,
|
13
|
-
:before_save,
|
14
|
-
:after_save,
|
15
|
-
:before_destroy,
|
16
|
-
:after_destroy
|
17
|
-
]
|
18
|
-
|
19
|
-
# @hooks.each {|h| Sequel::Model.class_def(h) {}}
|
20
6
|
end
|
21
7
|
|
22
8
|
specify "should be definable using def <hook name>" do
|
@@ -60,6 +46,47 @@ describe "Model hooks" do
|
|
60
46
|
c.new.before_save
|
61
47
|
$adds.should == ['hyiyie', 'byiyie']
|
62
48
|
end
|
49
|
+
|
50
|
+
specify "should not be additive if the method or tag already exists" do
|
51
|
+
$adds = []
|
52
|
+
c = Class.new(Sequel::Model) do
|
53
|
+
def bye; $adds << 'bye'; end
|
54
|
+
before_save :bye
|
55
|
+
before_save :bye
|
56
|
+
end
|
57
|
+
|
58
|
+
c.new.before_save
|
59
|
+
$adds.should == ['bye']
|
60
|
+
|
61
|
+
$adds = []
|
62
|
+
d = Class.new(Sequel::Model) do
|
63
|
+
before_save(:bye){$adds << 'hyiyie'}
|
64
|
+
before_save(:bye){$adds << 'byiyie'}
|
65
|
+
end
|
66
|
+
|
67
|
+
d.new.before_save
|
68
|
+
$adds.should == ['byiyie']
|
69
|
+
|
70
|
+
$adds = []
|
71
|
+
e = Class.new(Sequel::Model) do
|
72
|
+
def bye; $adds << 'bye'; end
|
73
|
+
before_save :bye
|
74
|
+
before_save(:bye){$adds << 'byiyie'}
|
75
|
+
end
|
76
|
+
|
77
|
+
e.new.before_save
|
78
|
+
$adds.should == ['byiyie']
|
79
|
+
|
80
|
+
$adds = []
|
81
|
+
e = Class.new(Sequel::Model) do
|
82
|
+
def bye; $adds << 'bye'; end
|
83
|
+
before_save(:bye){$adds << 'byiyie'}
|
84
|
+
before_save :bye
|
85
|
+
end
|
86
|
+
|
87
|
+
e.new.before_save
|
88
|
+
$adds.should == ['bye']
|
89
|
+
end
|
63
90
|
|
64
91
|
specify "should be inheritable" do
|
65
92
|
# pending
|
@@ -155,12 +182,12 @@ describe "Model#before_create && Model#after_create" do
|
|
155
182
|
columns :x
|
156
183
|
no_primary_key
|
157
184
|
|
158
|
-
before_create {MODEL_DB << "BLAH before"}
|
159
185
|
after_create {MODEL_DB << "BLAH after"}
|
160
186
|
end
|
161
187
|
end
|
162
188
|
|
163
189
|
specify "should be called around new record creation" do
|
190
|
+
@c.before_create {MODEL_DB << "BLAH before"}
|
164
191
|
@c.create(:x => 2)
|
165
192
|
MODEL_DB.sqls.should == [
|
166
193
|
'BLAH before',
|
@@ -168,6 +195,12 @@ describe "Model#before_create && Model#after_create" do
|
|
168
195
|
'BLAH after'
|
169
196
|
]
|
170
197
|
end
|
198
|
+
|
199
|
+
specify "should cancel the save if before_create returns false" do
|
200
|
+
@c.before_create{false}
|
201
|
+
@c.create(:x => 2).should == false
|
202
|
+
MODEL_DB.sqls.should == []
|
203
|
+
end
|
171
204
|
end
|
172
205
|
|
173
206
|
describe "Model#before_update && Model#after_update" do
|
@@ -175,12 +208,12 @@ describe "Model#before_update && Model#after_update" do
|
|
175
208
|
MODEL_DB.reset
|
176
209
|
|
177
210
|
@c = Class.new(Sequel::Model(:items)) do
|
178
|
-
before_update {MODEL_DB << "BLAH before"}
|
179
211
|
after_update {MODEL_DB << "BLAH after"}
|
180
212
|
end
|
181
213
|
end
|
182
214
|
|
183
215
|
specify "should be called around record update" do
|
216
|
+
@c.before_update {MODEL_DB << "BLAH before"}
|
184
217
|
m = @c.load(:id => 2233)
|
185
218
|
m.save
|
186
219
|
MODEL_DB.sqls.should == [
|
@@ -189,6 +222,12 @@ describe "Model#before_update && Model#after_update" do
|
|
189
222
|
'BLAH after'
|
190
223
|
]
|
191
224
|
end
|
225
|
+
|
226
|
+
specify "should cancel the save if before_update returns false" do
|
227
|
+
@c.before_update{false}
|
228
|
+
@c.load(:id => 2233).save.should == false
|
229
|
+
MODEL_DB.sqls.should == []
|
230
|
+
end
|
192
231
|
end
|
193
232
|
|
194
233
|
describe "Model#before_save && Model#after_save" do
|
@@ -221,6 +260,12 @@ describe "Model#before_save && Model#after_save" do
|
|
221
260
|
'BLAH after'
|
222
261
|
]
|
223
262
|
end
|
263
|
+
|
264
|
+
specify "should cancel the save if before_save returns false" do
|
265
|
+
@c.before_save{false}
|
266
|
+
@c.load(:id => 2233).save.should == false
|
267
|
+
MODEL_DB.sqls.should == ["BLAH before"]
|
268
|
+
end
|
224
269
|
end
|
225
270
|
|
226
271
|
describe "Model#before_destroy && Model#after_destroy" do
|
@@ -228,7 +273,6 @@ describe "Model#before_destroy && Model#after_destroy" do
|
|
228
273
|
MODEL_DB.reset
|
229
274
|
|
230
275
|
@c = Class.new(Sequel::Model(:items)) do
|
231
|
-
before_destroy {MODEL_DB << "BLAH before"}
|
232
276
|
after_destroy {MODEL_DB << "BLAH after"}
|
233
277
|
|
234
278
|
def delete
|
@@ -237,7 +281,8 @@ describe "Model#before_destroy && Model#after_destroy" do
|
|
237
281
|
end
|
238
282
|
end
|
239
283
|
|
240
|
-
specify "should be called around record
|
284
|
+
specify "should be called around record destruction" do
|
285
|
+
@c.before_destroy {MODEL_DB << "BLAH before"}
|
241
286
|
m = @c.new(:id => 2233)
|
242
287
|
m.destroy
|
243
288
|
MODEL_DB.sqls.should == [
|
@@ -246,11 +291,66 @@ describe "Model#before_destroy && Model#after_destroy" do
|
|
246
291
|
'BLAH after'
|
247
292
|
]
|
248
293
|
end
|
294
|
+
|
295
|
+
specify "should cancel the destroy if before_destroy returns false" do
|
296
|
+
@c.before_destroy{false}
|
297
|
+
@c.load(:id => 2233).destroy.should == false
|
298
|
+
MODEL_DB.sqls.should == []
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe "Model#before_validation && Model#after_validation" do
|
303
|
+
setup do
|
304
|
+
MODEL_DB.reset
|
305
|
+
|
306
|
+
@c = Class.new(Sequel::Model(:items)) do
|
307
|
+
before_validation{MODEL_DB << "BLAH before"}
|
308
|
+
after_validation{MODEL_DB << "BLAH after"}
|
309
|
+
|
310
|
+
def self.validate(o)
|
311
|
+
o.errors[:id] << 'not valid' unless o[:id] == 2233
|
312
|
+
end
|
313
|
+
|
314
|
+
def save!(*columns)
|
315
|
+
MODEL_DB << "CREATE BLAH"
|
316
|
+
self
|
317
|
+
end
|
318
|
+
columns :id
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
specify "should be called around validation" do
|
323
|
+
m = @c.new(:id => 2233)
|
324
|
+
m.should be_valid
|
325
|
+
MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
|
326
|
+
|
327
|
+
MODEL_DB.sqls.clear
|
328
|
+
m = @c.new(:id => 22)
|
329
|
+
m.should_not be_valid
|
330
|
+
MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
|
331
|
+
end
|
332
|
+
|
333
|
+
specify "should be called when calling save" do
|
334
|
+
m = @c.new(:id => 2233)
|
335
|
+
m.save.should == m
|
336
|
+
MODEL_DB.sqls.should == ['BLAH before', 'BLAH after', 'CREATE BLAH']
|
337
|
+
|
338
|
+
MODEL_DB.sqls.clear
|
339
|
+
m = @c.new(:id => 22)
|
340
|
+
m.save.should == false
|
341
|
+
MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
|
342
|
+
end
|
343
|
+
|
344
|
+
specify "should cancel the save if before_validation returns false" do
|
345
|
+
@c.before_validation{false}
|
346
|
+
@c.load(:id => 2233).save.should == false
|
347
|
+
MODEL_DB.sqls.should == ["BLAH before"]
|
348
|
+
end
|
249
349
|
end
|
250
350
|
|
251
|
-
describe "Model
|
351
|
+
describe "Model.has_hooks?" do
|
252
352
|
setup do
|
253
|
-
@c = Class.new(Sequel::Model)
|
353
|
+
@c = Class.new(Sequel::Model(:items))
|
254
354
|
end
|
255
355
|
|
256
356
|
specify "should return false if no hooks are defined" do
|