sequel 3.9.0 → 3.10.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.rdoc +1 -1
- data/Rakefile +1 -1
- data/doc/advanced_associations.rdoc +7 -10
- data/doc/release_notes/3.10.0.txt +286 -0
- data/lib/sequel/adapters/do/mysql.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +5 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +30 -0
- data/lib/sequel/adapters/shared/mssql.rb +23 -9
- data/lib/sequel/adapters/shared/mysql.rb +12 -1
- data/lib/sequel/adapters/shared/postgres.rb +7 -18
- data/lib/sequel/adapters/shared/sqlite.rb +5 -0
- data/lib/sequel/adapters/sqlite.rb +5 -0
- data/lib/sequel/connection_pool/single.rb +3 -3
- data/lib/sequel/database.rb +3 -2
- data/lib/sequel/dataset.rb +6 -5
- data/lib/sequel/dataset/convenience.rb +3 -3
- data/lib/sequel/dataset/query.rb +13 -0
- data/lib/sequel/dataset/sql.rb +31 -1
- data/lib/sequel/extensions/schema_dumper.rb +3 -3
- data/lib/sequel/model.rb +8 -6
- data/lib/sequel/model/associations.rb +144 -102
- data/lib/sequel/model/base.rb +21 -1
- data/lib/sequel/model/plugins.rb +3 -1
- data/lib/sequel/plugins/association_dependencies.rb +14 -7
- data/lib/sequel/plugins/caching.rb +4 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/identity_map.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +3 -2
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/typecast_on_load.rb +16 -5
- data/lib/sequel/sql.rb +18 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +4 -0
- data/spec/adapters/mysql_spec.rb +4 -0
- data/spec/adapters/postgres_spec.rb +55 -5
- data/spec/core/database_spec.rb +5 -3
- data/spec/core/dataset_spec.rb +86 -15
- data/spec/core/expression_filters_spec.rb +23 -6
- data/spec/extensions/association_dependencies_spec.rb +24 -5
- data/spec/extensions/association_proxies_spec.rb +3 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/identity_map_spec.rb +16 -0
- data/spec/extensions/nested_attributes_spec.rb +44 -1
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +6 -0
- data/spec/extensions/spec_helper.rb +6 -0
- data/spec/extensions/typecast_on_load_spec.rb +9 -0
- data/spec/extensions/validation_helpers_spec.rb +5 -5
- data/spec/integration/dataset_test.rb +13 -9
- data/spec/integration/eager_loader_test.rb +56 -1
- data/spec/integration/model_test.rb +8 -0
- data/spec/integration/plugin_test.rb +270 -0
- data/spec/integration/schema_test.rb +1 -1
- data/spec/model/associations_spec.rb +541 -118
- data/spec/model/eager_loading_spec.rb +24 -3
- data/spec/model/record_spec.rb +34 -0
- metadata +9 -2
@@ -78,7 +78,7 @@ describe "Database schema parser" do
|
|
78
78
|
INTEGRATION_DB.schema(:items).first.last[:ruby_default].should == 'blah'
|
79
79
|
end
|
80
80
|
|
81
|
-
cspecify "should parse types from the schema properly", [:
|
81
|
+
cspecify "should parse types from the schema properly", [:jdbc, :mysql] do
|
82
82
|
INTEGRATION_DB.create_table!(:items){Integer :number}
|
83
83
|
INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
|
84
84
|
INTEGRATION_DB.create_table!(:items){Fixnum :number}
|
@@ -382,6 +382,28 @@ describe Sequel::Model, "many_to_one" do
|
|
382
382
|
MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.parent_id = 2)']
|
383
383
|
end
|
384
384
|
|
385
|
+
it "should have many_to_one setter deal with a one_to_one reciprocal" do
|
386
|
+
@c2.many_to_one :parent, :class => @c2, :key=>:parent_id
|
387
|
+
@c2.one_to_one :child, :class => @c2, :key=>:parent_id
|
388
|
+
|
389
|
+
d = @c2.new(:id => 1)
|
390
|
+
e = @c2.new(:id => 2)
|
391
|
+
e.associations[:child] = nil
|
392
|
+
d.parent = e
|
393
|
+
e.child.should == d
|
394
|
+
d.parent = nil
|
395
|
+
e.child.should == nil
|
396
|
+
d.parent = e
|
397
|
+
e.child.should == d
|
398
|
+
|
399
|
+
f = @c2.new(:id => 3)
|
400
|
+
d.parent = nil
|
401
|
+
e.child.should == nil
|
402
|
+
e.associations[:child] = f
|
403
|
+
d.parent = e
|
404
|
+
e.child.should == d
|
405
|
+
end
|
406
|
+
|
385
407
|
it "should have the setter remove the object from the previous associated object's reciprocal one_to_many cached association list if it exists" do
|
386
408
|
@c2.many_to_one :parent, :class => @c2
|
387
409
|
@c2.one_to_many :children, :class => @c2, :key=>:parent_id
|
@@ -459,16 +481,16 @@ describe Sequel::Model, "many_to_one" do
|
|
459
481
|
p.instance_variable_get(:@x).should == c
|
460
482
|
end
|
461
483
|
|
462
|
-
it "should support (before|after)
|
484
|
+
it "should support (before|after)_set callbacks" do
|
463
485
|
h = []
|
464
|
-
@c2.many_to_one :parent, :class => @c2, :
|
486
|
+
@c2.many_to_one :parent, :class => @c2, :before_set=>[proc{|x,y| h << x.pk; h << (y ? -y.pk : :y)}, :blah], :after_set=>proc{h << 3}
|
465
487
|
@c2.class_eval do
|
466
488
|
@@blah = h
|
467
489
|
def []=(a, v)
|
468
490
|
a == :parent_id ? (@@blah << (v ? 4 : 5)) : super
|
469
491
|
end
|
470
492
|
def blah(x)
|
471
|
-
@@blah << x.pk
|
493
|
+
@@blah << (x ? x.pk : :x)
|
472
494
|
end
|
473
495
|
def blahr(x)
|
474
496
|
@@blah << 6
|
@@ -480,7 +502,7 @@ describe Sequel::Model, "many_to_one" do
|
|
480
502
|
p.parent = c
|
481
503
|
h.should == [10, -123, 123, 4, 3]
|
482
504
|
p.parent = nil
|
483
|
-
h.should == [10, -123, 123, 4, 3,
|
505
|
+
h.should == [10, -123, 123, 4, 3, 10, :y, :x, 5, 3]
|
484
506
|
end
|
485
507
|
|
486
508
|
it "should support after_load association callback" do
|
@@ -507,19 +529,19 @@ describe Sequel::Model, "many_to_one" do
|
|
507
529
|
p = @c2.new
|
508
530
|
c = @c2.load(:id=>123)
|
509
531
|
p.raise_on_save_failure = false
|
510
|
-
@c2.many_to_one :parent, :class => @c2, :
|
511
|
-
p.
|
532
|
+
@c2.many_to_one :parent, :class => @c2, :before_set=>:bs
|
533
|
+
p.meta_def(:bs){|x| false}
|
512
534
|
p.should_not_receive(:_parent=)
|
513
535
|
proc{p.parent = c}.should raise_error(Sequel::Error)
|
536
|
+
|
514
537
|
p.parent.should == nil
|
515
538
|
p.associations[:parent] = c
|
516
539
|
p.parent.should == c
|
517
|
-
p.should_receive(:br).once.with(c).and_return(false)
|
518
540
|
proc{p.parent = nil}.should raise_error(Sequel::Error)
|
519
541
|
end
|
520
542
|
|
521
543
|
it "should raise an error if a callback is not a proc or symbol" do
|
522
|
-
@c2.many_to_one :parent, :class => @c2, :
|
544
|
+
@c2.many_to_one :parent, :class => @c2, :before_set=>Object.new
|
523
545
|
proc{@c2.new.parent = @c2.load(:id=>1)}.should raise_error(Sequel::Error)
|
524
546
|
end
|
525
547
|
|
@@ -529,27 +551,507 @@ describe Sequel::Model, "many_to_one" do
|
|
529
551
|
p = @c2.new
|
530
552
|
p.associations[:parent] = d
|
531
553
|
h = []
|
532
|
-
@c2.many_to_one :parent, :class => @c2, :
|
554
|
+
@c2.many_to_one :parent, :class => @c2, :before_set=>:bs, :after_set=>:as
|
533
555
|
@c2.class_eval do
|
534
556
|
@@blah = h
|
535
557
|
def []=(a, v)
|
536
558
|
a == :parent_id ? (@@blah << 5) : super
|
537
559
|
end
|
538
|
-
def
|
560
|
+
def bs(x)
|
539
561
|
@@blah << x.pk
|
540
562
|
end
|
541
|
-
def
|
542
|
-
@@blah << x.pk * -1
|
543
|
-
end
|
544
|
-
def aa(x)
|
563
|
+
def as(x)
|
545
564
|
@@blah << x.pk * 2
|
546
565
|
end
|
547
|
-
|
548
|
-
|
566
|
+
end
|
567
|
+
p.parent = c
|
568
|
+
h.should == [123, 5, 246]
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
describe Sequel::Model, "one_to_one" do
|
573
|
+
before do
|
574
|
+
@c1 = Class.new(Sequel::Model(:attributes)) do
|
575
|
+
def _refresh(ds); end
|
576
|
+
unrestrict_primary_key
|
577
|
+
columns :id, :node_id, :y
|
578
|
+
end
|
579
|
+
|
580
|
+
@c2 = Class.new(Sequel::Model(:nodes)) do
|
581
|
+
def _refresh(ds); end
|
582
|
+
unrestrict_primary_key
|
583
|
+
attr_accessor :xxx
|
584
|
+
|
585
|
+
def self.name; 'Node'; end
|
586
|
+
def self.to_s; 'Node'; end
|
587
|
+
columns :id, :x, :parent_id, :par_parent_id, :blah, :node_id
|
588
|
+
end
|
589
|
+
@dataset = @c2.dataset
|
590
|
+
|
591
|
+
@c2.dataset.extend(Module.new {
|
592
|
+
def empty?; false; end
|
593
|
+
def fetch_rows(sql)
|
594
|
+
@db << sql
|
595
|
+
yield Hash.new
|
596
|
+
end
|
597
|
+
})
|
598
|
+
|
599
|
+
@c1.dataset.extend(Module.new {
|
600
|
+
def empty?; opts.has_key?(:empty) ? (super; true) : false; end
|
601
|
+
def fetch_rows(sql)
|
602
|
+
@db << sql
|
603
|
+
yield Hash.new
|
604
|
+
end
|
605
|
+
})
|
606
|
+
|
607
|
+
@dataset = @c2.dataset
|
608
|
+
MODEL_DB.reset
|
609
|
+
end
|
610
|
+
|
611
|
+
it "should have the getter method return a single object if the :one_to_one option is true" do
|
612
|
+
@c2.one_to_one :attribute, :class => @c1
|
613
|
+
att = @c2.new(:id => 1234).attribute
|
614
|
+
MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (attributes.node_id = 1234) LIMIT 1']
|
615
|
+
att.should be_a_kind_of(@c1)
|
616
|
+
att.values.should == {}
|
617
|
+
end
|
618
|
+
|
619
|
+
it "should not add a setter method if the :read_only option is true" do
|
620
|
+
@c2.one_to_one :attribute, :class => @c1, :read_only=>true
|
621
|
+
im = @c2.instance_methods.collect{|x| x.to_s}
|
622
|
+
im.should(include('attribute'))
|
623
|
+
im.should_not(include('attribute='))
|
624
|
+
end
|
625
|
+
|
626
|
+
it "should add a setter method" do
|
627
|
+
@c2.one_to_one :attribute, :class => @c1
|
628
|
+
attrib = @c1.new(:id=>3)
|
629
|
+
d = @c1.dataset
|
630
|
+
@c1.class_eval{remove_method :_refresh}
|
631
|
+
def d.fetch_rows(s); yield({:id=>3}) end
|
632
|
+
@c2.new(:id => 1234).attribute = attrib
|
633
|
+
['INSERT INTO attributes (node_id, id) VALUES (1234, 3)',
|
634
|
+
'INSERT INTO attributes (id, node_id) VALUES (3, 1234)'].should(include(MODEL_DB.sqls.last))
|
635
|
+
MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))'
|
636
|
+
MODEL_DB.sqls.length.should == 2
|
637
|
+
@c2.new(:id => 1234).attribute.should == attrib
|
638
|
+
MODEL_DB.sqls.clear
|
639
|
+
attrib = @c1.load(:id=>3)
|
640
|
+
@c2.new(:id => 1234).attribute = attrib
|
641
|
+
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))',
|
642
|
+
"UPDATE attributes SET node_id = 1234 WHERE (id = 3)"]
|
643
|
+
end
|
644
|
+
|
645
|
+
it "should use a transaction in the setter method" do
|
646
|
+
@c2.one_to_one :attribute, :class => @c1
|
647
|
+
@c2.use_transactions = true
|
648
|
+
MODEL_DB.sqls.clear
|
649
|
+
attrib = @c1.load(:id=>3)
|
650
|
+
@c2.new(:id => 1234).attribute = attrib
|
651
|
+
MODEL_DB.sqls.should == ['BEGIN',
|
652
|
+
'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))',
|
653
|
+
"UPDATE attributes SET node_id = 1234 WHERE (id = 3)",
|
654
|
+
'COMMIT']
|
655
|
+
end
|
656
|
+
|
657
|
+
it "should have setter method respect association filters" do
|
658
|
+
@c2.one_to_one :attribute, :class => @c1, :conditions=>{:a=>1} do |ds|
|
659
|
+
ds.filter(:b=>2)
|
660
|
+
end
|
661
|
+
MODEL_DB.sqls.clear
|
662
|
+
attrib = @c1.load(:id=>3)
|
663
|
+
@c2.new(:id => 1234).attribute = attrib
|
664
|
+
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (a = 1) AND (b = 2) AND (id != 3))',
|
665
|
+
"UPDATE attributes SET node_id = 1234 WHERE (id = 3)"]
|
666
|
+
end
|
667
|
+
|
668
|
+
it "should have the setter method respect the :primary_key option" do
|
669
|
+
@c2.one_to_one :attribute, :class => @c1, :primary_key=>:xxx
|
670
|
+
attrib = @c1.new(:id=>3)
|
671
|
+
d = @c1.dataset
|
672
|
+
@c1.class_eval{remove_method :_refresh}
|
673
|
+
def d.fetch_rows(s); yield({:id=>3}) end
|
674
|
+
@c2.new(:id => 1234, :xxx=>5).attribute = attrib
|
675
|
+
['INSERT INTO attributes (node_id, id) VALUES (5, 3)',
|
676
|
+
'INSERT INTO attributes (id, node_id) VALUES (3, 5)'].should(include(MODEL_DB.sqls.last))
|
677
|
+
MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))'
|
678
|
+
MODEL_DB.sqls.length.should == 2
|
679
|
+
@c2.new(:id => 321, :xxx=>5).attribute.should == attrib
|
680
|
+
MODEL_DB.sqls.clear
|
681
|
+
attrib = @c1.load(:id=>3)
|
682
|
+
@c2.new(:id => 621, :xxx=>5).attribute = attrib
|
683
|
+
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))',
|
684
|
+
'UPDATE attributes SET node_id = 5 WHERE (id = 3)']
|
685
|
+
end
|
686
|
+
|
687
|
+
it "should have the setter method respect composite keys" do
|
688
|
+
@c2.one_to_one :attribute, :class => @c1, :key=>[:node_id, :y], :primary_key=>[:id, :x]
|
689
|
+
attrib = @c1.load(:id=>3, :y=>6)
|
690
|
+
d = @c1.dataset
|
691
|
+
def d.fetch_rows(s); yield({:id=>3, :y=>6}) end
|
692
|
+
@c2.load(:id => 1234, :x=>5).attribute = attrib
|
693
|
+
MODEL_DB.sqls.last.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 3\)/
|
694
|
+
MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\) AND \(id != 3\)\)/
|
695
|
+
end
|
696
|
+
|
697
|
+
it "should use implicit key if omitted" do
|
698
|
+
@c2.one_to_one :parent, :class => @c2
|
699
|
+
|
700
|
+
d = @c2.new(:id => 234)
|
701
|
+
p = d.parent
|
702
|
+
p.class.should == @c2
|
703
|
+
p.values.should == {}
|
704
|
+
|
705
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.node_id = 234) LIMIT 1"]
|
706
|
+
end
|
707
|
+
|
708
|
+
it "should use implicit class if omitted" do
|
709
|
+
class ::ParParent < Sequel::Model
|
710
|
+
end
|
711
|
+
|
712
|
+
@c2.one_to_one :par_parent
|
713
|
+
|
714
|
+
d = @c2.new(:id => 234)
|
715
|
+
p = d.par_parent
|
716
|
+
p.class.should == ParParent
|
717
|
+
|
718
|
+
MODEL_DB.sqls.should == ["SELECT * FROM par_parents WHERE (par_parents.node_id = 234) LIMIT 1"]
|
719
|
+
end
|
720
|
+
|
721
|
+
it "should use class inside module if given as a string" do
|
722
|
+
module ::Par
|
723
|
+
class Parent < Sequel::Model
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
@c2.one_to_one :par_parent, :class=>"Par::Parent"
|
728
|
+
|
729
|
+
d = @c2.new(:id => 234)
|
730
|
+
p = d.par_parent
|
731
|
+
p.class.should == Par::Parent
|
732
|
+
|
733
|
+
MODEL_DB.sqls.should == ["SELECT * FROM parents WHERE (parents.node_id = 234) LIMIT 1"]
|
734
|
+
end
|
735
|
+
|
736
|
+
it "should use explicit key if given" do
|
737
|
+
@c2.one_to_one :parent, :class => @c2, :key => :blah
|
738
|
+
|
739
|
+
d = @c2.new(:id => 234)
|
740
|
+
p = d.parent
|
741
|
+
p.class.should == @c2
|
742
|
+
p.values.should == {}
|
743
|
+
|
744
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.blah = 234) LIMIT 1"]
|
745
|
+
end
|
746
|
+
|
747
|
+
it "should use :primary_key option if given" do
|
748
|
+
@c2.one_to_one :parent, :class => @c2, :key => :pk, :primary_key => :blah
|
749
|
+
@c2.new(:id => 1, :blah => 567).parent
|
750
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.pk = 567) LIMIT 1"]
|
751
|
+
end
|
752
|
+
|
753
|
+
it "should support composite keys" do
|
754
|
+
@c2.one_to_one :parent, :class => @c2, :primary_key=>[:id, :parent_id], :key=>[:parent_id, :id]
|
755
|
+
@c2.new(:id => 1, :parent_id => 234).parent
|
756
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.parent_id = 1) AND (nodes.id = 234)) LIMIT 1"]
|
757
|
+
end
|
758
|
+
|
759
|
+
it "should not issue query if not all keys have values" do
|
760
|
+
@c2.one_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
|
761
|
+
@c2.new(:id => 1, :parent_id => nil).parent.should == nil
|
762
|
+
MODEL_DB.sqls.should == []
|
763
|
+
end
|
764
|
+
|
765
|
+
it "should raise an Error unless same number of composite keys used" do
|
766
|
+
proc{@c2.one_to_one :parent, :class => @c2, :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
767
|
+
proc{@c2.one_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>:id}.should raise_error(Sequel::Error)
|
768
|
+
proc{@c2.one_to_one :parent, :class => @c2, :key=>:id, :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
769
|
+
proc{@c2.one_to_one :parent, :class => @c2, :key=>[:id, :parent_id, :blah], :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
770
|
+
end
|
771
|
+
|
772
|
+
it "should use :select option if given" do
|
773
|
+
@c2.one_to_one :parent, :class => @c2, :select=>[:id, :name]
|
774
|
+
@c2.new(:id => 567).parent
|
775
|
+
MODEL_DB.sqls.should == ["SELECT id, name FROM nodes WHERE (nodes.node_id = 567) LIMIT 1"]
|
776
|
+
end
|
777
|
+
|
778
|
+
it "should use :conditions option if given" do
|
779
|
+
@c2.one_to_one :parent, :class => @c2, :conditions=>{:a=>32}
|
780
|
+
@c2.new(:id => 567).parent
|
781
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.node_id = 567) AND (a = 32)) LIMIT 1"]
|
782
|
+
|
783
|
+
@c2.one_to_one :parent, :class => @c2, :conditions=>:a
|
784
|
+
MODEL_DB.sqls.clear
|
785
|
+
@c2.new(:id => 567).parent
|
786
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.node_id = 567) AND a) LIMIT 1"]
|
787
|
+
end
|
788
|
+
|
789
|
+
it "should support :order, :limit (only for offset), and :dataset options, as well as a block" do
|
790
|
+
c2 = @c2
|
791
|
+
@c2.one_to_one :child_20, :class => @c2, :key=>:id, :dataset=>proc{c2.filter(:parent_id=>pk)}, :limit=>[10,20], :order=>:name do |ds|
|
792
|
+
ds.filter(:x.sql_number > 1)
|
793
|
+
end
|
794
|
+
@c2.load(:id => 100).child_20
|
795
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((parent_id = 100) AND (x > 1)) ORDER BY name LIMIT 1 OFFSET 20"]
|
796
|
+
end
|
797
|
+
|
798
|
+
it "should return nil if primary_key value is nil" do
|
799
|
+
@c2.one_to_one :parent, :class => @c2, :primary_key=>:node_id
|
800
|
+
|
801
|
+
d = @c2.new(:id => 1)
|
802
|
+
d.parent.should == nil
|
803
|
+
MODEL_DB.sqls.should == []
|
804
|
+
end
|
805
|
+
|
806
|
+
it "should cache negative lookup" do
|
807
|
+
@c2.one_to_one :parent, :class => @c2
|
808
|
+
ds = @c2.dataset
|
809
|
+
def ds.fetch_rows(sql, &block)
|
810
|
+
MODEL_DB.sqls << sql
|
811
|
+
end
|
812
|
+
|
813
|
+
d = @c2.new(:id => 555)
|
814
|
+
MODEL_DB.sqls.should == []
|
815
|
+
d.parent.should == nil
|
816
|
+
MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.node_id = 555) LIMIT 1']
|
817
|
+
d.parent.should == nil
|
818
|
+
MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.node_id = 555) LIMIT 1']
|
819
|
+
end
|
820
|
+
|
821
|
+
it "should define a setter method" do
|
822
|
+
@c2.one_to_one :parent, :class => @c2
|
823
|
+
|
824
|
+
d = @c2.new(:id => 1)
|
825
|
+
f = @c2.new(:id => 3, :node_id=> 4321)
|
826
|
+
d.parent = f
|
827
|
+
f.values.should == {:id => 3, :node_id=>1}
|
828
|
+
d.parent.should == f
|
829
|
+
|
830
|
+
d.parent = nil
|
831
|
+
d.parent.should == nil
|
832
|
+
end
|
833
|
+
|
834
|
+
it "should have the setter method respect the :primary_key option" do
|
835
|
+
@c2.one_to_one :parent, :class => @c2, :primary_key=>:blah
|
836
|
+
d = @c2.new(:id => 1, :blah => 3)
|
837
|
+
e = @c2.new(:id => 4321, :node_id=>444)
|
838
|
+
d.parent = e
|
839
|
+
e.values.should == {:id => 4321, :node_id => 3}
|
840
|
+
end
|
841
|
+
|
842
|
+
it "should have the setter method respect the :key option" do
|
843
|
+
@c2.one_to_one :parent, :class => @c2, :key=>:blah
|
844
|
+
d = @c2.new(:id => 3)
|
845
|
+
e = @c2.new(:id => 4321, :blah=>444)
|
846
|
+
d.parent = e
|
847
|
+
e.values.should == {:id => 4321, :blah => 3}
|
848
|
+
end
|
849
|
+
|
850
|
+
it "should persist changes to associated object when the setter is called" do
|
851
|
+
@c2.one_to_one :parent, :class => @c2
|
852
|
+
d = @c2.load(:id => 1)
|
853
|
+
d.parent = @c2.load(:id => 3, :node_id=>345)
|
854
|
+
MODEL_DB.sqls.should == ["UPDATE nodes SET node_id = NULL WHERE ((node_id = 1) AND (id != 3))",
|
855
|
+
"UPDATE nodes SET node_id = 1 WHERE (id = 3)"]
|
856
|
+
end
|
857
|
+
|
858
|
+
it "should set cached instance variable when accessed" do
|
859
|
+
@c2.one_to_one :parent, :class => @c2
|
860
|
+
|
861
|
+
d = @c2.load(:id => 1)
|
862
|
+
d.associations[:parent].should == nil
|
863
|
+
ds = @c2.dataset
|
864
|
+
def ds.fetch_rows(sql, &block); MODEL_DB.sqls << sql; yield({:id=>234}) end
|
865
|
+
e = d.parent
|
866
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.node_id = 1) LIMIT 1"]
|
867
|
+
d.parent
|
868
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.node_id = 1) LIMIT 1"]
|
869
|
+
d.associations[:parent].should == e
|
870
|
+
end
|
871
|
+
|
872
|
+
it "should set cached instance variable when assigned" do
|
873
|
+
@c2.one_to_one :parent, :class => @c2
|
874
|
+
|
875
|
+
d = @c2.load(:id => 1)
|
876
|
+
d.associations[:parent].should == nil
|
877
|
+
e = @c2.load(:id => 234)
|
878
|
+
d.parent = e
|
879
|
+
f = d.parent
|
880
|
+
d.associations[:parent].should == e
|
881
|
+
e.should == f
|
882
|
+
end
|
883
|
+
|
884
|
+
it "should use cached instance variable if available" do
|
885
|
+
@c2.one_to_one :parent, :class => @c2
|
886
|
+
d = @c2.load(:id => 1, :parent_id => 234)
|
887
|
+
d.associations[:parent] = 42
|
888
|
+
d.parent.should == 42
|
889
|
+
MODEL_DB.sqls.should == []
|
890
|
+
end
|
891
|
+
|
892
|
+
it "should not use cached instance variable if asked to reload" do
|
893
|
+
@c2.one_to_one :parent, :class => @c2
|
894
|
+
d = @c2.load(:id => 1)
|
895
|
+
d.associations[:parent] = [42]
|
896
|
+
d.parent(true).should_not == 42
|
897
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.node_id = 1) LIMIT 1"]
|
898
|
+
end
|
899
|
+
|
900
|
+
it "should have the setter set the reciprocal many_to_one cached association" do
|
901
|
+
@c2.one_to_one :parent, :class => @c2, :key=>:parent_id
|
902
|
+
@c2.many_to_one :child, :class => @c2, :key=>:parent_id
|
903
|
+
|
904
|
+
d = @c2.load(:id => 1)
|
905
|
+
e = @c2.load(:id => 2)
|
906
|
+
d.parent = e
|
907
|
+
e.child.should == d
|
908
|
+
MODEL_DB.sqls.should == ["UPDATE nodes SET parent_id = NULL WHERE ((parent_id = 1) AND (id != 2))",
|
909
|
+
"UPDATE nodes SET parent_id = 1 WHERE (id = 2)"]
|
910
|
+
MODEL_DB.reset
|
911
|
+
d.parent = nil
|
912
|
+
e.child.should == nil
|
913
|
+
MODEL_DB.sqls.should == ["UPDATE nodes SET parent_id = NULL WHERE (parent_id = 1)"]
|
914
|
+
end
|
915
|
+
|
916
|
+
it "should have the setter remove the object from the previous associated object's reciprocal many_to_one cached association list if it exists" do
|
917
|
+
@c2.one_to_one :parent, :class => @c2, :key=>:parent_id
|
918
|
+
@c2.many_to_one :child, :class => @c2, :key=>:parent_id
|
919
|
+
ds = @c2.dataset
|
920
|
+
def ds.fetch_rows(sql, &block)
|
921
|
+
MODEL_DB.sqls << sql
|
922
|
+
end
|
923
|
+
|
924
|
+
d = @c2.load(:id => 1)
|
925
|
+
e = @c2.load(:id => 2)
|
926
|
+
f = @c2.load(:id => 3)
|
927
|
+
e.child.should == nil
|
928
|
+
f.child.should == nil
|
929
|
+
MODEL_DB.reset
|
930
|
+
d.parent = e
|
931
|
+
e.child.should == d
|
932
|
+
d.parent = f
|
933
|
+
f.child.should == d
|
934
|
+
e.child.should == nil
|
935
|
+
d.parent = nil
|
936
|
+
f.child.should == nil
|
937
|
+
end
|
938
|
+
|
939
|
+
it "should not add associations methods directly to class" do
|
940
|
+
@c2.one_to_one :parent, :class => @c2
|
941
|
+
@c2.instance_methods.collect{|x| x.to_s}.should(include('parent'))
|
942
|
+
@c2.instance_methods.collect{|x| x.to_s}.should(include('parent='))
|
943
|
+
@c2.instance_methods(false).collect{|x| x.to_s}.should_not(include('parent'))
|
944
|
+
@c2.instance_methods(false).collect{|x| x.to_s}.should_not(include('parent='))
|
945
|
+
end
|
946
|
+
|
947
|
+
it "should raise an error if the current model object that doesn't have a valid primary key" do
|
948
|
+
@c2.one_to_one :parent, :class => @c2
|
949
|
+
p = @c2.new
|
950
|
+
c = @c2.load(:id=>123)
|
951
|
+
proc{p.parent = c}.should raise_error(Sequel::Error)
|
952
|
+
end
|
953
|
+
|
954
|
+
it "should make the change to the foreign_key value inside a _association= method" do
|
955
|
+
@c2.one_to_one :parent, :class => @c2
|
956
|
+
@c2.private_instance_methods.collect{|x| x.to_s}.sort.should(include("_parent="))
|
957
|
+
c = @c2.new
|
958
|
+
p = @c2.load(:id=>123)
|
959
|
+
def p._parent=(x)
|
960
|
+
@x = x
|
961
|
+
end
|
962
|
+
p.should_not_receive(:parent_id=)
|
963
|
+
p.parent = c
|
964
|
+
p.instance_variable_get(:@x).should == c
|
965
|
+
end
|
966
|
+
|
967
|
+
it "should support (before|after)_set callbacks" do
|
968
|
+
h = []
|
969
|
+
@c2.one_to_one :parent, :class => @c2, :before_set=>[proc{|x,y| h << x.pk; h << (y ? -y.pk : :y)}, :blah], :after_set=>proc{h << 3}
|
970
|
+
@c2.class_eval do
|
971
|
+
@@blah = h
|
972
|
+
def blah(x)
|
973
|
+
@@blah << (x ? x.pk : :x)
|
974
|
+
end
|
975
|
+
def blahr(x)
|
976
|
+
@@blah << 6
|
977
|
+
end
|
978
|
+
end
|
979
|
+
p = @c2.load(:id=>10)
|
980
|
+
c = @c2.load(:id=>123)
|
981
|
+
h.should == []
|
982
|
+
p.parent = c
|
983
|
+
h.should == [10, -123, 123, 3]
|
984
|
+
p.parent = nil
|
985
|
+
h.should == [10, -123, 123, 3, 10, :y, :x, 3]
|
986
|
+
end
|
987
|
+
|
988
|
+
it "should support after_load association callback" do
|
989
|
+
h = []
|
990
|
+
@c2.one_to_one :parent, :class => @c2, :after_load=>[proc{|x,y| h << [x.pk, y.pk]}, :al]
|
991
|
+
@c2.class_eval do
|
992
|
+
@@blah = h
|
993
|
+
def al(v)
|
994
|
+
@@blah << v.pk
|
995
|
+
end
|
996
|
+
def @dataset.fetch_rows(sql)
|
997
|
+
yield({:id=>20})
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
p = @c2.load(:id=>10)
|
1001
|
+
parent = p.parent
|
1002
|
+
h.should == [[10, 20], 20]
|
1003
|
+
parent.pk.should == 20
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
|
1007
|
+
# The reason for this is that assignment in ruby always returns the argument instead of the result
|
1008
|
+
# of the method, so we can't return nil to signal that the association callback prevented the modification
|
1009
|
+
p = @c2.new
|
1010
|
+
c = @c2.load(:id=>123)
|
1011
|
+
p.raise_on_save_failure = false
|
1012
|
+
@c2.one_to_one :parent, :class => @c2, :before_set=>:bs
|
1013
|
+
p.meta_def(:bs){|x| false}
|
1014
|
+
p.should_not_receive(:_parent=)
|
1015
|
+
proc{p.parent = c}.should raise_error(Sequel::Error)
|
1016
|
+
|
1017
|
+
p.parent.should == nil
|
1018
|
+
p.associations[:parent] = c
|
1019
|
+
p.parent.should == c
|
1020
|
+
proc{p.parent = nil}.should raise_error(Sequel::Error)
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
it "should raise an error if a callback is not a proc or symbol" do
|
1024
|
+
@c2.one_to_one :parent, :class => @c2, :before_set=>Object.new
|
1025
|
+
proc{@c2.new.parent = @c2.load(:id=>1)}.should raise_error(Sequel::Error)
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
it "should call the set callbacks" do
|
1029
|
+
c = @c2.load(:id=>123)
|
1030
|
+
d = @c2.load(:id=>321)
|
1031
|
+
p = @c2.load(:id=>32)
|
1032
|
+
p.associations[:parent] = [d]
|
1033
|
+
h = []
|
1034
|
+
@c2.one_to_one :parent, :class => @c2, :before_set=>:bs, :after_set=>:as
|
1035
|
+
@c2.class_eval do
|
1036
|
+
@@blah = h
|
1037
|
+
def []=(a, v)
|
1038
|
+
a == :node_id ? (@@blah << 5) : super
|
1039
|
+
end
|
1040
|
+
def bs(x)
|
1041
|
+
@@blah << x.pk
|
1042
|
+
end
|
1043
|
+
def as(x)
|
1044
|
+
@@blah << x.pk * 2
|
549
1045
|
end
|
550
1046
|
end
|
551
1047
|
p.parent = c
|
552
|
-
h.should == [
|
1048
|
+
h.should == [123, 5, 246]
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
it "should work_correctly when used with associate" do
|
1052
|
+
@c2.associate :one_to_one, :parent, :class => @c2
|
1053
|
+
@c2.load(:id => 567).parent.should == @c2.load({})
|
1054
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.node_id = 567) LIMIT 1"]
|
553
1055
|
end
|
554
1056
|
end
|
555
1057
|
|
@@ -791,7 +1293,7 @@ describe Sequel::Model, "one_to_many" do
|
|
791
1293
|
MODEL_DB.reset
|
792
1294
|
@c1.load(:node_id => nil, :y => 5, :id => 234).should == n.remove_attribute([234, 5])
|
793
1295
|
MODEL_DB.sqls.length.should == 2
|
794
|
-
MODEL_DB.sqls.first.should =~ /SELECT \* FROM attributes WHERE \(\(attributes.node_id = 123\) AND \(
|
1296
|
+
MODEL_DB.sqls.first.should =~ /SELECT \* FROM attributes WHERE \(\(attributes.node_id = 123\) AND \((id|y) = (234|5)\) AND \((id|y) = (234|5)\)\) LIMIT 1/
|
795
1297
|
MODEL_DB.sqls.last.should =~ /UPDATE attributes SET node_id = NULL WHERE \(\((id|y) = (234|5)\) AND \((id|y) = (234|5)\)\)/
|
796
1298
|
end
|
797
1299
|
|
@@ -1078,6 +1580,14 @@ describe Sequel::Model, "one_to_many" do
|
|
1078
1580
|
MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)'
|
1079
1581
|
end
|
1080
1582
|
|
1583
|
+
it "should have remove_all method respect association filters" do
|
1584
|
+
@c2.one_to_many :attributes, :class => @c1, :conditions=>{:a=>1} do |ds|
|
1585
|
+
ds.filter(:b=>2)
|
1586
|
+
end
|
1587
|
+
@c2.new(:id => 1234).remove_all_attributes
|
1588
|
+
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (a = 1) AND (b = 2))']
|
1589
|
+
end
|
1590
|
+
|
1081
1591
|
it "should have the remove_all_ method respect the :primary_key option" do
|
1082
1592
|
@c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
|
1083
1593
|
@c2.new(:id => 1234, :xxx=>5).remove_all_attributes
|
@@ -1133,106 +1643,6 @@ describe Sequel::Model, "one_to_many" do
|
|
1133
1643
|
attrib.associations.fetch(:node, 2).should == nil
|
1134
1644
|
end
|
1135
1645
|
|
1136
|
-
it "should add a getter method if the :one_to_one option is true" do
|
1137
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true
|
1138
|
-
att = @c2.new(:id => 1234).attribute
|
1139
|
-
MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
|
1140
|
-
att.should be_a_kind_of(@c1)
|
1141
|
-
att.values.should == {}
|
1142
|
-
end
|
1143
|
-
|
1144
|
-
it "should not add a setter method if the :one_to_one option is true and :read_only option is true" do
|
1145
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :read_only=>true
|
1146
|
-
im = @c2.instance_methods.collect{|x| x.to_s}
|
1147
|
-
im.should(include('attribute'))
|
1148
|
-
im.should_not(include('attribute='))
|
1149
|
-
end
|
1150
|
-
|
1151
|
-
it "should have the getter method raise an error if more than one record is found" do
|
1152
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true
|
1153
|
-
d = @c1.dataset
|
1154
|
-
def d.fetch_rows(s); 2.times{yield Hash.new} end
|
1155
|
-
proc{@c2.new(:id => 1234).attribute}.should raise_error(Sequel::Error)
|
1156
|
-
end
|
1157
|
-
|
1158
|
-
it "should add a setter method if the :one_to_one option is true" do
|
1159
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true
|
1160
|
-
attrib = @c1.new(:id=>3)
|
1161
|
-
d = @c1.dataset
|
1162
|
-
@c1.class_eval{remove_method :_refresh}
|
1163
|
-
def d.fetch_rows(s); yield({:id=>3}) end
|
1164
|
-
@c2.new(:id => 1234).attribute = attrib
|
1165
|
-
['INSERT INTO attributes (node_id, id) VALUES (1234, 3)',
|
1166
|
-
'INSERT INTO attributes (id, node_id) VALUES (3, 1234)'].should(include(MODEL_DB.sqls.first))
|
1167
|
-
MODEL_DB.sqls.last.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))'
|
1168
|
-
MODEL_DB.sqls.length.should == 2
|
1169
|
-
@c2.new(:id => 1234).attribute.should == attrib
|
1170
|
-
MODEL_DB.sqls.clear
|
1171
|
-
attrib = @c1.load(:id=>3)
|
1172
|
-
@c2.new(:id => 1234).attribute = attrib
|
1173
|
-
MODEL_DB.sqls.should == ["UPDATE attributes SET node_id = 1234 WHERE (id = 3)",
|
1174
|
-
'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))']
|
1175
|
-
end
|
1176
|
-
|
1177
|
-
it "should use a transaction in the setter method if the :one_to_one option is true" do
|
1178
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true
|
1179
|
-
@c2.use_transactions = true
|
1180
|
-
MODEL_DB.sqls.clear
|
1181
|
-
attrib = @c1.load(:id=>3)
|
1182
|
-
@c2.new(:id => 1234).attribute = attrib
|
1183
|
-
MODEL_DB.sqls.should == ['BEGIN',
|
1184
|
-
"UPDATE attributes SET node_id = 1234 WHERE (id = 3)",
|
1185
|
-
'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))',
|
1186
|
-
'COMMIT']
|
1187
|
-
end
|
1188
|
-
|
1189
|
-
it "should have the setter method for the :one_to_one option respect the :primary_key option" do
|
1190
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :primary_key=>:xxx
|
1191
|
-
attrib = @c1.new(:id=>3)
|
1192
|
-
d = @c1.dataset
|
1193
|
-
@c1.class_eval{remove_method :_refresh}
|
1194
|
-
def d.fetch_rows(s); yield({:id=>3}) end
|
1195
|
-
@c2.new(:id => 1234, :xxx=>5).attribute = attrib
|
1196
|
-
['INSERT INTO attributes (node_id, id) VALUES (5, 3)',
|
1197
|
-
'INSERT INTO attributes (id, node_id) VALUES (3, 5)'].should(include(MODEL_DB.sqls.first))
|
1198
|
-
MODEL_DB.sqls.last.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))'
|
1199
|
-
MODEL_DB.sqls.length.should == 2
|
1200
|
-
@c2.new(:id => 321, :xxx=>5).attribute.should == attrib
|
1201
|
-
MODEL_DB.sqls.clear
|
1202
|
-
attrib = @c1.load(:id=>3)
|
1203
|
-
@c2.new(:id => 621, :xxx=>5).attribute = attrib
|
1204
|
-
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 5 WHERE (id = 3)',
|
1205
|
-
'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))']
|
1206
|
-
end
|
1207
|
-
|
1208
|
-
it "should have the setter method for the :one_to_one option respect composite keys" do
|
1209
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :key=>[:node_id, :y], :primary_key=>[:id, :x]
|
1210
|
-
attrib = @c1.load(:id=>3, :y=>6)
|
1211
|
-
d = @c1.dataset
|
1212
|
-
def d.fetch_rows(s); yield({:id=>3, :y=>6}) end
|
1213
|
-
@c2.load(:id => 1234, :x=>5).attribute = attrib
|
1214
|
-
MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 3\)/
|
1215
|
-
MODEL_DB.sqls.last.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(\(node_id = 1234\) AND \(y = 5\)\) AND \(id != 3\)\)/
|
1216
|
-
end
|
1217
|
-
|
1218
|
-
it "should raise an error if the one_to_one getter would be the same as the association name" do
|
1219
|
-
proc{@c2.one_to_many :song, :class => @c1, :one_to_one=>true}.should raise_error(Sequel::Error)
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
it "should not create remove_ and remove_all methods if :one_to_one option is used" do
|
1223
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true
|
1224
|
-
@c2.new.should_not(respond_to(:remove_attribute))
|
1225
|
-
@c2.new.should_not(respond_to(:remove_all_attributes))
|
1226
|
-
end
|
1227
|
-
|
1228
|
-
it "should make non getter and setter methods private if :one_to_one option is used" do
|
1229
|
-
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true do |ds| end
|
1230
|
-
meths = @c2.private_instance_methods.collect{|x| x.to_s}
|
1231
|
-
meths.should(include("attributes"))
|
1232
|
-
meths.should(include("add_attribute"))
|
1233
|
-
meths.should(include("attributes_dataset"))
|
1234
|
-
end
|
1235
|
-
|
1236
1646
|
it "should call an _add_ method internally to add attributes" do
|
1237
1647
|
@c2.one_to_many :attributes, :class => @c1
|
1238
1648
|
@c2.private_instance_methods.collect{|x| x.to_s}.sort.should(include("_add_attribute"))
|
@@ -1390,6 +1800,11 @@ describe Sequel::Model, "one_to_many" do
|
|
1390
1800
|
p.remove_attribute(c).should == nil
|
1391
1801
|
p.attributes.should == [c]
|
1392
1802
|
end
|
1803
|
+
|
1804
|
+
it "should raise an error if trying to use the :one_to_one option" do
|
1805
|
+
proc{@c2.one_to_many :attribute, :class => @c1, :one_to_one=>true}.should raise_error(Sequel::Error)
|
1806
|
+
proc{@c2.associate :one_to_many, :attribute, :class => @c1, :one_to_one=>true}.should raise_error(Sequel::Error)
|
1807
|
+
end
|
1393
1808
|
end
|
1394
1809
|
|
1395
1810
|
describe Sequel::Model, "many_to_many" do
|
@@ -1918,6 +2333,14 @@ describe Sequel::Model, "many_to_many" do
|
|
1918
2333
|
MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE (node_id = 1234)'
|
1919
2334
|
end
|
1920
2335
|
|
2336
|
+
it "should have remove_all method respect association filters" do
|
2337
|
+
@c2.many_to_many :attributes, :class => @c1, :conditions=>{:a=>1} do |ds|
|
2338
|
+
ds.filter(:b=>2)
|
2339
|
+
end
|
2340
|
+
@c2.new(:id => 1234).remove_all_attributes
|
2341
|
+
MODEL_DB.sqls.should == ['DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (a = 1) AND (b = 2))']
|
2342
|
+
end
|
2343
|
+
|
1921
2344
|
it "should have the remove_all_ method respect the :left_primary_key option" do
|
1922
2345
|
@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx
|
1923
2346
|
@c2.new(:id => 1234, :xxx=>5).remove_all_attributes
|