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
         |