sequel 1.5.1 → 2.0.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 +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
|