sequel 1.4.0 → 1.5.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 +56 -0
- data/README +257 -154
- data/Rakefile +8 -16
- data/lib/sequel_model.rb +15 -257
- data/lib/sequel_model/associations.rb +70 -33
- data/lib/sequel_model/base.rb +80 -35
- data/lib/sequel_model/caching.rb +3 -3
- data/lib/sequel_model/deprecated.rb +81 -0
- data/lib/sequel_model/eager_loading.rb +303 -43
- data/lib/sequel_model/hooks.rb +29 -25
- data/lib/sequel_model/inflections.rb +112 -0
- data/lib/sequel_model/inflector.rb +279 -0
- data/lib/sequel_model/plugins.rb +15 -14
- data/lib/sequel_model/record.rb +87 -75
- data/lib/sequel_model/schema.rb +2 -0
- data/lib/sequel_model/validations.rb +300 -2
- data/spec/associations_spec.rb +175 -9
- data/spec/base_spec.rb +37 -18
- data/spec/caching_spec.rb +7 -4
- data/spec/deprecated_relations_spec.rb +3 -43
- data/spec/eager_loading_spec.rb +295 -7
- data/spec/hooks_spec.rb +7 -4
- data/spec/inflector_spec.rb +34 -0
- data/spec/model_spec.rb +30 -53
- data/spec/record_spec.rb +191 -33
- data/spec/spec_helper.rb +17 -2
- data/spec/validations_spec.rb +414 -15
- metadata +7 -22
- data/lib/sequel_model/pretty_table.rb +0 -73
data/spec/eager_loading_spec.rb
CHANGED
@@ -1,34 +1,34 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
2
|
|
3
|
-
describe Sequel::Model, "eager" do
|
3
|
+
describe Sequel::Model, "#eager" do
|
4
4
|
before(:each) do
|
5
5
|
MODEL_DB.reset
|
6
6
|
|
7
7
|
class EagerAlbum < Sequel::Model(:albums)
|
8
|
-
|
8
|
+
columns :id, :band_id
|
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
12
|
end
|
13
13
|
|
14
14
|
class EagerBand < Sequel::Model(:bands)
|
15
|
-
|
15
|
+
columns :id
|
16
16
|
one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks
|
17
17
|
many_to_many :members, :class=>'EagerBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
|
18
18
|
end
|
19
19
|
|
20
20
|
class EagerTrack < Sequel::Model(:tracks)
|
21
|
-
|
21
|
+
columns :id, :album_id
|
22
22
|
many_to_one :album, :class=>'EagerAlbum', :key=>:album_id
|
23
23
|
end
|
24
24
|
|
25
25
|
class EagerGenre < Sequel::Model(:genres)
|
26
|
-
|
26
|
+
columns :id
|
27
27
|
many_to_many :albums, :class=>'EagerAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
|
28
28
|
end
|
29
29
|
|
30
30
|
class EagerBandMember < Sequel::Model(:members)
|
31
|
-
|
31
|
+
columns :id
|
32
32
|
many_to_many :bands, :class=>'EagerBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm, :order =>:id
|
33
33
|
end
|
34
34
|
|
@@ -206,7 +206,7 @@ describe Sequel::Model, "eager" do
|
|
206
206
|
a.first.values.should == {:id => 2}
|
207
207
|
MODEL_DB.sqls.should == ['SELECT * FROM bands']
|
208
208
|
a = a.first
|
209
|
-
a.albums
|
209
|
+
a.albums
|
210
210
|
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
211
211
|
'SELECT * FROM albums WHERE (band_id = 2)',
|
212
212
|
'SELECT * FROM tracks WHERE (album_id IN (1))']
|
@@ -258,3 +258,291 @@ describe Sequel::Model, "eager" do
|
|
258
258
|
MODEL_DB.sqls.length.should == 2
|
259
259
|
end
|
260
260
|
end
|
261
|
+
|
262
|
+
describe Sequel::Model, "#eager_graph" do
|
263
|
+
after(:all) do
|
264
|
+
class MockDataset
|
265
|
+
alias clone orig_clone
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
before(:all) do
|
270
|
+
class MockDataset
|
271
|
+
alias orig_clone clone
|
272
|
+
def clone(opts = {})
|
273
|
+
c = super()
|
274
|
+
c.opts = @opts.merge(opts)
|
275
|
+
c.instance_variable_set(:@columns, (@columns.dup if @columns))
|
276
|
+
c
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
class GraphAlbum < Sequel::Model(:albums)
|
281
|
+
dataset.opts[:from] = [:albums]
|
282
|
+
columns :id, :band_id
|
283
|
+
many_to_one :band, :class=>'GraphBand', :key=>:band_id
|
284
|
+
one_to_many :tracks, :class=>'GraphTrack', :key=>:album_id
|
285
|
+
many_to_many :genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
|
286
|
+
end
|
287
|
+
|
288
|
+
class GraphBand < Sequel::Model(:bands)
|
289
|
+
dataset.opts[:from] = [:bands]
|
290
|
+
columns :id, :vocalist_id
|
291
|
+
many_to_one :vocalist, :class=>'GraphBandMember', :key=>:vocalist_id
|
292
|
+
one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id
|
293
|
+
many_to_many :members, :class=>'GraphBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
|
294
|
+
many_to_many :genres, :class=>'GraphGenre', :left_key=>:band_id, :right_key=>:genre_id, :join_table=>:bg
|
295
|
+
end
|
296
|
+
|
297
|
+
class GraphTrack < Sequel::Model(:tracks)
|
298
|
+
dataset.opts[:from] = [:tracks]
|
299
|
+
columns :id, :album_id
|
300
|
+
many_to_one :album, :class=>'GraphAlbum', :key=>:album_id
|
301
|
+
end
|
302
|
+
|
303
|
+
class GraphGenre < Sequel::Model(:genres)
|
304
|
+
dataset.opts[:from] = [:genres]
|
305
|
+
columns :id
|
306
|
+
many_to_many :albums, :class=>'GraphAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
|
307
|
+
end
|
308
|
+
|
309
|
+
class GraphBandMember < Sequel::Model(:members)
|
310
|
+
dataset.opts[:from] = [:members]
|
311
|
+
columns :id
|
312
|
+
many_to_many :bands, :class=>'GraphBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should eagerly load a single many_to_one association" do
|
317
|
+
ds = GraphAlbum.eager_graph(:band)
|
318
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands band ON (band.id = albums.band_id)'
|
319
|
+
def ds.fetch_rows(sql, &block)
|
320
|
+
yield({:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3})
|
321
|
+
end
|
322
|
+
a = ds.all
|
323
|
+
a.should be_a_kind_of(Array)
|
324
|
+
a.size.should == 1
|
325
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
326
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
327
|
+
a = a.first
|
328
|
+
a.band.should be_a_kind_of(GraphBand)
|
329
|
+
a.band.values.should == {:id => 2, :vocalist_id=>3}
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should eagerly load a single one_to_many association" do
|
333
|
+
ds = GraphAlbum.eager_graph(:tracks)
|
334
|
+
ds.sql.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)'
|
335
|
+
def ds.fetch_rows(sql, &block)
|
336
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
337
|
+
end
|
338
|
+
a = ds.all
|
339
|
+
a.should be_a_kind_of(Array)
|
340
|
+
a.size.should == 1
|
341
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
342
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
343
|
+
a = a.first
|
344
|
+
a.tracks.should be_a_kind_of(Array)
|
345
|
+
a.tracks.size.should == 1
|
346
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
347
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should eagerly load a single many_to_many association" do
|
351
|
+
ds = GraphAlbum.eager_graph(:genres)
|
352
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id)'
|
353
|
+
def ds.fetch_rows(sql, &block)
|
354
|
+
yield({:id=>1, :band_id=>2, :genres_id=>4})
|
355
|
+
end
|
356
|
+
a = ds.all
|
357
|
+
a.should be_a_kind_of(Array)
|
358
|
+
a.size.should == 1
|
359
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
360
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
361
|
+
a = a.first
|
362
|
+
a.genres.should be_a_kind_of(Array)
|
363
|
+
a.genres.size.should == 1
|
364
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
365
|
+
a.genres.first.values.should == {:id => 4}
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should eagerly load multiple associations" do
|
369
|
+
ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
|
370
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands band ON (band.id = albums.band_id)'
|
371
|
+
def ds.fetch_rows(sql, &block)
|
372
|
+
yield({:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6})
|
373
|
+
end
|
374
|
+
a = ds.all
|
375
|
+
a.should be_a_kind_of(Array)
|
376
|
+
a.size.should == 1
|
377
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
378
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
379
|
+
a = a.first
|
380
|
+
a.band.should be_a_kind_of(GraphBand)
|
381
|
+
a.band.values.should == {:id => 2, :vocalist_id=>6}
|
382
|
+
a.tracks.should be_a_kind_of(Array)
|
383
|
+
a.tracks.size.should == 1
|
384
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
385
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
386
|
+
a.genres.should be_a_kind_of(Array)
|
387
|
+
a.genres.size.should == 1
|
388
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
389
|
+
a.genres.first.values.should == {:id => 4}
|
390
|
+
end
|
391
|
+
|
392
|
+
it "should allow cascading of eager loading for associations of associated models" do
|
393
|
+
ds = GraphTrack.eager_graph(:album=>{:band=>:members})
|
394
|
+
ds.sql.should == 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN albums album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
395
|
+
def ds.fetch_rows(sql, &block)
|
396
|
+
yield({:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :members_id=>5, :band_id_0=>2, :vocalist_id=>6})
|
397
|
+
end
|
398
|
+
a = ds.all
|
399
|
+
a.should be_a_kind_of(Array)
|
400
|
+
a.size.should == 1
|
401
|
+
a.first.should be_a_kind_of(GraphTrack)
|
402
|
+
a.first.values.should == {:id => 3, :album_id => 1}
|
403
|
+
a = a.first
|
404
|
+
a.album.should be_a_kind_of(GraphAlbum)
|
405
|
+
a.album.values.should == {:id => 1, :band_id => 2}
|
406
|
+
a.album.band.should be_a_kind_of(GraphBand)
|
407
|
+
a.album.band.values.should == {:id => 2, :vocalist_id=>6}
|
408
|
+
a.album.band.members.should be_a_kind_of(Array)
|
409
|
+
a.album.band.members.size.should == 1
|
410
|
+
a.album.band.members.first.should be_a_kind_of(GraphBandMember)
|
411
|
+
a.album.band.members.first.values.should == {:id => 5}
|
412
|
+
end
|
413
|
+
|
414
|
+
it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
|
415
|
+
MODEL_DB.reset
|
416
|
+
ds = GraphAlbum.eager_graph(:tracks)
|
417
|
+
ds.sql.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)'
|
418
|
+
def ds.fetch_rows(sql, &block)
|
419
|
+
@db << sql
|
420
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
421
|
+
end
|
422
|
+
a = ds.all
|
423
|
+
a.should be_a_kind_of(Array)
|
424
|
+
a.size.should == 1
|
425
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
426
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
427
|
+
a = a.first
|
428
|
+
a.tracks.should be_a_kind_of(Array)
|
429
|
+
a.tracks.size.should == 1
|
430
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
431
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
432
|
+
a.tracks.first.album.should be_a_kind_of(GraphAlbum)
|
433
|
+
a.tracks.first.album.should == a
|
434
|
+
MODEL_DB.sqls.length.should == 1
|
435
|
+
end
|
436
|
+
|
437
|
+
it "should eager load multiple associations from the same table" do
|
438
|
+
ds = GraphBand.eager_graph(:vocalist, :members)
|
439
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, vocalist.id AS vocalist_id_0, members.id AS members_id FROM bands LEFT OUTER JOIN members vocalist ON (vocalist.id = bands.vocalist_id) LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
440
|
+
def ds.fetch_rows(sql, &block)
|
441
|
+
yield({:id=>2, :vocalist_id=>6, :vocalist_id_0=>6, :members_id=>5})
|
442
|
+
end
|
443
|
+
a = ds.all
|
444
|
+
a.should be_a_kind_of(Array)
|
445
|
+
a.size.should == 1
|
446
|
+
a.first.should be_a_kind_of(GraphBand)
|
447
|
+
a.first.values.should == {:id => 2, :vocalist_id => 6}
|
448
|
+
a = a.first
|
449
|
+
a.vocalist.should be_a_kind_of(GraphBandMember)
|
450
|
+
a.vocalist.values.should == {:id => 6}
|
451
|
+
a.members.should be_a_kind_of(Array)
|
452
|
+
a.members.size.should == 1
|
453
|
+
a.members.first.should be_a_kind_of(GraphBandMember)
|
454
|
+
a.members.first.values.should == {:id => 5}
|
455
|
+
end
|
456
|
+
|
457
|
+
it "should give you a graph of tables when called without .all" do
|
458
|
+
ds = GraphAlbum.eager_graph(:band)
|
459
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands band ON (band.id = albums.band_id)'
|
460
|
+
def ds.fetch_rows(sql, &block)
|
461
|
+
yield({:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3})
|
462
|
+
end
|
463
|
+
ds.first.should == {:albums=>GraphAlbum.new(:id => 1, :band_id => 2), :band=>GraphBand.new(:id => 2, :vocalist_id=>3)}
|
464
|
+
end
|
465
|
+
|
466
|
+
it "should not drop any associated objects if the graph could not be a cartesian product" do
|
467
|
+
ds = GraphBand.eager_graph(:members, :vocalist)
|
468
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, vocalist.id AS vocalist_id_0 FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN members vocalist ON (vocalist.id = bands.vocalist_id)'
|
469
|
+
def ds.fetch_rows(sql, &block)
|
470
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :vocalist_id_0=>6})
|
471
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :vocalist_id_0=>6})
|
472
|
+
end
|
473
|
+
a = ds.all
|
474
|
+
a.should be_a_kind_of(Array)
|
475
|
+
a.size.should == 1
|
476
|
+
a.first.should be_a_kind_of(GraphBand)
|
477
|
+
a.first.values.should == {:id => 2, :vocalist_id => 6}
|
478
|
+
a = a.first
|
479
|
+
a.vocalist.should be_a_kind_of(GraphBandMember)
|
480
|
+
a.vocalist.values.should == {:id => 6}
|
481
|
+
a.members.should be_a_kind_of(Array)
|
482
|
+
a.members.size.should == 2
|
483
|
+
a.members.first.should be_a_kind_of(GraphBandMember)
|
484
|
+
a.members.first.values.should == {:id => 5}
|
485
|
+
a.members.last.should be_a_kind_of(GraphBandMember)
|
486
|
+
a.members.last.values.should == {:id => 5}
|
487
|
+
end
|
488
|
+
|
489
|
+
it "should drop duplicate items that occur in sequence if the graph could be a cartesian product" do
|
490
|
+
ds = GraphBand.eager_graph(:members, :genres)
|
491
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, genres.id AS genres_id FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN bg ON (bg.band_id = bands.id) LEFT OUTER JOIN genres ON (genres.id = bg.genre_id)'
|
492
|
+
def ds.fetch_rows(sql, &block)
|
493
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>7})
|
494
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>8})
|
495
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>7})
|
496
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>8})
|
497
|
+
end
|
498
|
+
a = ds.all
|
499
|
+
a.should be_a_kind_of(Array)
|
500
|
+
a.size.should == 1
|
501
|
+
a.first.should be_a_kind_of(GraphBand)
|
502
|
+
a.first.values.should == {:id => 2, :vocalist_id => 6}
|
503
|
+
a = a.first
|
504
|
+
a.members.should be_a_kind_of(Array)
|
505
|
+
a.members.size.should == 2
|
506
|
+
a.members.first.should be_a_kind_of(GraphBandMember)
|
507
|
+
a.members.first.values.should == {:id => 5}
|
508
|
+
a.members.last.should be_a_kind_of(GraphBandMember)
|
509
|
+
a.members.last.values.should == {:id => 6}
|
510
|
+
a.genres.size.should == 2
|
511
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
512
|
+
a.genres.first.values.should == {:id => 7}
|
513
|
+
a.genres.last.should be_a_kind_of(GraphGenre)
|
514
|
+
a.genres.last.values.should == {:id => 8}
|
515
|
+
end
|
516
|
+
|
517
|
+
it "should be able to be used in combination with #eager" do
|
518
|
+
MODEL_DB.reset
|
519
|
+
ds = GraphAlbum.eager_graph(:tracks).eager(:genres)
|
520
|
+
def ds.fetch_rows(sql, &block)
|
521
|
+
@db << sql
|
522
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
523
|
+
end
|
524
|
+
ds2 = GraphGenre.dataset
|
525
|
+
def ds2.fetch_rows(sql, &block)
|
526
|
+
@db << sql
|
527
|
+
yield({:id=>6, :x_foreign_key_x=>1})
|
528
|
+
end
|
529
|
+
a = ds.all
|
530
|
+
a.should be_a_kind_of(Array)
|
531
|
+
a.size.should == 1
|
532
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
533
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
534
|
+
a = a.first
|
535
|
+
a.tracks.should be_a_kind_of(Array)
|
536
|
+
a.tracks.size.should == 1
|
537
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
538
|
+
a.tracks.first.values.should == {:id=>3, :album_id=>1}
|
539
|
+
a.genres.should be_a_kind_of(Array)
|
540
|
+
a.genres.size.should == 1
|
541
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
542
|
+
a.genres.first.values.should == {:id=>6}
|
543
|
+
MODEL_DB.sqls[0].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)'
|
544
|
+
["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))",
|
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]))
|
547
|
+
end
|
548
|
+
end
|
data/spec/hooks_spec.rb
CHANGED
@@ -131,18 +131,19 @@ end
|
|
131
131
|
describe "Model#after_initialize" do
|
132
132
|
specify "should be called after initialization" do
|
133
133
|
$values1 = nil
|
134
|
+
$reached_after_initialized = false
|
134
135
|
|
135
136
|
a = Class.new(Sequel::Model) do
|
137
|
+
columns :x, :y
|
136
138
|
after_initialize do
|
137
139
|
$values1 = @values.clone
|
138
|
-
|
140
|
+
$reached_after_initialized = true
|
139
141
|
end
|
140
142
|
end
|
141
143
|
|
142
144
|
a.new(:x => 1, :y => 2)
|
143
145
|
$values1.should == {:x => 1, :y => 2}
|
144
|
-
|
145
|
-
proc {a.new(:blow => true)}.should raise_error(Sequel::Error)
|
146
|
+
$reached_after_initialized.should == true
|
146
147
|
end
|
147
148
|
end
|
148
149
|
|
@@ -151,6 +152,7 @@ describe "Model#before_create && Model#after_create" do
|
|
151
152
|
MODEL_DB.reset
|
152
153
|
|
153
154
|
@c = Class.new(Sequel::Model(:items)) do
|
155
|
+
columns :x
|
154
156
|
no_primary_key
|
155
157
|
|
156
158
|
before_create {MODEL_DB << "BLAH before"}
|
@@ -194,6 +196,7 @@ describe "Model#before_save && Model#after_save" do
|
|
194
196
|
MODEL_DB.reset
|
195
197
|
|
196
198
|
@c = Class.new(Sequel::Model(:items)) do
|
199
|
+
columns :x
|
197
200
|
before_save {MODEL_DB << "BLAH before"}
|
198
201
|
after_save {MODEL_DB << "BLAH after"}
|
199
202
|
end
|
@@ -266,4 +269,4 @@ describe "Model#has_hooks?" do
|
|
266
269
|
@c.before_save :blah
|
267
270
|
@d.has_hooks?(:before_save).should be_true
|
268
271
|
end
|
269
|
-
end
|
272
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Inflector do
|
4
|
+
it "should transform words from singular to plural" do
|
5
|
+
"post".pluralize.should == "posts"
|
6
|
+
"octopus".pluralize.should =="octopi"
|
7
|
+
"the blue mailman".pluralize.should == "the blue mailmen"
|
8
|
+
"CamelOctopus".pluralize.should == "CamelOctopi"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should transform words from plural to singular" do
|
12
|
+
"posts".singularize.should == "post"
|
13
|
+
"octopi".singularize.should == "octopus"
|
14
|
+
"the blue mailmen".singularize.should == "the blue mailman"
|
15
|
+
"CamelOctopi".singularize.should == "CamelOctopus"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should transform class names to table names" do
|
19
|
+
"RawScaledScorer".tableize.should == "raw_scaled_scorers"
|
20
|
+
"egg_and_ham".tableize.should == "egg_and_hams"
|
21
|
+
"fancyCategory".tableize.should == "fancy_categories"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should tranform table names to class names" do
|
25
|
+
"egg_and_hams".classify.should == "EggAndHam"
|
26
|
+
"post".classify.should == "Post"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create a foreign key name from a class name" do
|
30
|
+
"Message".foreign_key.should == "message_id"
|
31
|
+
"Message".foreign_key(false).should == "messageid"
|
32
|
+
"Admin::Post".foreign_key.should == "post_id"
|
33
|
+
end
|
34
|
+
end
|
data/spec/model_spec.rb
CHANGED
@@ -73,6 +73,7 @@ describe Sequel::Model, "constructor" do
|
|
73
73
|
|
74
74
|
before(:each) do
|
75
75
|
@m = Class.new(Sequel::Model)
|
76
|
+
@m.columns :a, :b
|
76
77
|
end
|
77
78
|
|
78
79
|
it "should accept a hash" do
|
@@ -102,7 +103,6 @@ describe Sequel::Model, "new" do
|
|
102
103
|
it "should be marked as new?" do
|
103
104
|
o = @m.new
|
104
105
|
o.should be_new
|
105
|
-
o.should be_new_record
|
106
106
|
end
|
107
107
|
|
108
108
|
it "should not be marked as new? once it is saved" do
|
@@ -110,7 +110,6 @@ describe Sequel::Model, "new" do
|
|
110
110
|
o.should be_new
|
111
111
|
o.save
|
112
112
|
o.should_not be_new
|
113
|
-
o.should_not be_new_record
|
114
113
|
end
|
115
114
|
|
116
115
|
it "should use the last inserted id as primary key if not in values" do
|
@@ -218,6 +217,7 @@ describe Sequel::Model, ".fetch" do
|
|
218
217
|
|
219
218
|
end
|
220
219
|
|
220
|
+
### DEPRECATED
|
221
221
|
describe Sequel::Model, "magic methods" do
|
222
222
|
|
223
223
|
before(:each) do
|
@@ -290,6 +290,7 @@ describe Sequel::Model, ".find_or_create" do
|
|
290
290
|
MODEL_DB.reset
|
291
291
|
@c = Class.new(Sequel::Model(:items)) do
|
292
292
|
no_primary_key
|
293
|
+
columns :x
|
293
294
|
end
|
294
295
|
end
|
295
296
|
|
@@ -355,22 +356,6 @@ describe Sequel::Model, ".destroy_all" do
|
|
355
356
|
end
|
356
357
|
end
|
357
358
|
|
358
|
-
describe Sequel::Model, ".join" do
|
359
|
-
|
360
|
-
before(:each) do
|
361
|
-
MODEL_DB.reset
|
362
|
-
@c = Class.new(Sequel::Model(:items)) do
|
363
|
-
no_primary_key
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
it "should format proper SQL" do
|
368
|
-
@c.join(:atts, :item_id => :id).sql.should == \
|
369
|
-
"SELECT items.* FROM items INNER JOIN atts ON (atts.item_id = items.id)"
|
370
|
-
end
|
371
|
-
|
372
|
-
end
|
373
|
-
|
374
359
|
describe Sequel::Model, ".all" do
|
375
360
|
|
376
361
|
before(:each) do
|
@@ -406,6 +391,7 @@ describe Sequel::Model, "A model class without a primary key" do
|
|
406
391
|
before(:each) do
|
407
392
|
MODEL_DB.reset
|
408
393
|
@c = Class.new(Sequel::Model(:items)) do
|
394
|
+
columns :x
|
409
395
|
no_primary_key
|
410
396
|
end
|
411
397
|
end
|
@@ -438,52 +424,43 @@ describe Sequel::Model, "attribute accessors" do
|
|
438
424
|
before(:each) do
|
439
425
|
MODEL_DB.reset
|
440
426
|
|
441
|
-
@c = Class.new(Sequel::Model
|
427
|
+
@c = Class.new(Sequel::Model) do
|
428
|
+
def self.columns; orig_columns; end
|
442
429
|
end
|
443
|
-
|
444
|
-
@
|
430
|
+
@dataset = Object.new
|
431
|
+
def @dataset.db; end
|
432
|
+
def @dataset.set_model(blah); end
|
433
|
+
def @dataset.naked; self; end
|
434
|
+
def @dataset.columns; [:x, :y]; end
|
435
|
+
def @dataset.def_mutation_method(*names); end
|
445
436
|
end
|
446
437
|
|
447
|
-
it "should be created
|
438
|
+
it "should be created on set_dataset" do
|
439
|
+
%w'x y x= y='.each do |x|
|
440
|
+
@c.instance_methods.include?(x).should == false
|
441
|
+
end
|
442
|
+
@c.set_dataset(@dataset)
|
443
|
+
%w'x y x= y='.each do |x|
|
444
|
+
@c.instance_methods.include?(x).should == true
|
445
|
+
end
|
448
446
|
o = @c.new
|
447
|
+
%w'x y x= y='.each do |x|
|
448
|
+
o.methods.include?(x).should == true
|
449
|
+
end
|
449
450
|
|
450
|
-
o.should_not be_respond_to(:x)
|
451
451
|
o.x.should be_nil
|
452
|
-
o.should be_respond_to(:x)
|
453
|
-
|
454
|
-
o.should_not be_respond_to(:x=)
|
455
452
|
o.x = 34
|
456
453
|
o.x.should == 34
|
457
|
-
o.should be_respond_to(:x=)
|
458
454
|
end
|
459
455
|
|
460
|
-
it "should
|
461
|
-
|
462
|
-
|
463
|
-
proc {o.x}.should_not raise_error
|
464
|
-
proc {o.xx}.should raise_error(Sequel::Error)
|
465
|
-
|
466
|
-
proc {o.x = 3}.should_not raise_error
|
467
|
-
proc {o.yy = 4}.should raise_error(Sequel::Error)
|
468
|
-
|
469
|
-
proc {o.yy?}.should raise_error(NoMethodError)
|
470
|
-
end
|
471
|
-
|
472
|
-
it "should not raise for a column not in the dataset, but for which there's a value" do
|
456
|
+
it "should be only accept one argument for the write accessor" do
|
457
|
+
@c.set_dataset(@dataset)
|
473
458
|
o = @c.new
|
474
459
|
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
o.
|
479
|
-
o.values[:yy] = nil
|
480
|
-
|
481
|
-
proc {o.xx; o.yy}.should_not raise_error(Sequel::Error)
|
482
|
-
|
483
|
-
o.xx.should == 123
|
484
|
-
o.yy.should == nil
|
485
|
-
|
486
|
-
proc {o.xx = 3}.should_not raise_error(Sequel::Error)
|
460
|
+
o.x = 34
|
461
|
+
o.x.should == 34
|
462
|
+
proc{o.send(:x=)}.should raise_error
|
463
|
+
proc{o.send(:x=, 3, 4)}.should raise_error
|
487
464
|
end
|
488
465
|
end
|
489
466
|
|
@@ -540,4 +517,4 @@ context "Model#inspect" do
|
|
540
517
|
specify "should include the class name and the values" do
|
541
518
|
@o.inspect.should == '#<Sequel::Model @values={:x=>333}>'
|
542
519
|
end
|
543
|
-
end
|
520
|
+
end
|