sequel 3.5.0 → 3.6.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 +108 -0
 - data/README.rdoc +25 -14
 - data/Rakefile +20 -1
 - data/doc/advanced_associations.rdoc +61 -64
 - data/doc/cheat_sheet.rdoc +16 -7
 - data/doc/opening_databases.rdoc +3 -3
 - data/doc/prepared_statements.rdoc +1 -1
 - data/doc/reflection.rdoc +2 -1
 - data/doc/release_notes/3.6.0.txt +366 -0
 - data/doc/schema.rdoc +19 -14
 - data/lib/sequel/adapters/amalgalite.rb +5 -27
 - data/lib/sequel/adapters/jdbc.rb +13 -3
 - data/lib/sequel/adapters/jdbc/h2.rb +17 -0
 - data/lib/sequel/adapters/jdbc/mysql.rb +20 -7
 - data/lib/sequel/adapters/mysql.rb +4 -3
 - data/lib/sequel/adapters/oracle.rb +1 -1
 - data/lib/sequel/adapters/postgres.rb +87 -28
 - data/lib/sequel/adapters/shared/mssql.rb +47 -6
 - data/lib/sequel/adapters/shared/mysql.rb +12 -31
 - data/lib/sequel/adapters/shared/postgres.rb +15 -12
 - data/lib/sequel/adapters/shared/sqlite.rb +18 -0
 - data/lib/sequel/adapters/sqlite.rb +1 -16
 - data/lib/sequel/connection_pool.rb +1 -1
 - data/lib/sequel/core.rb +1 -1
 - data/lib/sequel/database.rb +1 -1
 - data/lib/sequel/database/schema_generator.rb +2 -0
 - data/lib/sequel/database/schema_sql.rb +1 -1
 - data/lib/sequel/dataset.rb +5 -179
 - data/lib/sequel/dataset/actions.rb +123 -0
 - data/lib/sequel/dataset/convenience.rb +18 -10
 - data/lib/sequel/dataset/features.rb +65 -0
 - data/lib/sequel/dataset/prepared_statements.rb +29 -23
 - data/lib/sequel/dataset/query.rb +429 -0
 - data/lib/sequel/dataset/sql.rb +67 -435
 - data/lib/sequel/model/associations.rb +77 -13
 - data/lib/sequel/model/base.rb +30 -8
 - data/lib/sequel/model/errors.rb +4 -4
 - data/lib/sequel/plugins/caching.rb +38 -15
 - data/lib/sequel/plugins/force_encoding.rb +18 -7
 - data/lib/sequel/plugins/hook_class_methods.rb +4 -0
 - data/lib/sequel/plugins/many_through_many.rb +1 -1
 - data/lib/sequel/plugins/nested_attributes.rb +40 -11
 - data/lib/sequel/plugins/serialization.rb +17 -3
 - data/lib/sequel/plugins/validation_helpers.rb +65 -18
 - data/lib/sequel/sql.rb +23 -1
 - data/lib/sequel/version.rb +1 -1
 - data/spec/adapters/mssql_spec.rb +96 -10
 - data/spec/adapters/mysql_spec.rb +19 -0
 - data/spec/adapters/postgres_spec.rb +65 -2
 - data/spec/adapters/sqlite_spec.rb +10 -0
 - data/spec/core/core_sql_spec.rb +9 -0
 - data/spec/core/database_spec.rb +8 -4
 - data/spec/core/dataset_spec.rb +122 -29
 - data/spec/core/expression_filters_spec.rb +17 -0
 - data/spec/extensions/caching_spec.rb +43 -3
 - data/spec/extensions/force_encoding_spec.rb +43 -1
 - data/spec/extensions/nested_attributes_spec.rb +55 -2
 - data/spec/extensions/validation_helpers_spec.rb +71 -0
 - data/spec/integration/associations_test.rb +281 -0
 - data/spec/integration/dataset_test.rb +383 -9
 - data/spec/integration/eager_loader_test.rb +0 -65
 - data/spec/integration/model_test.rb +110 -0
 - data/spec/integration/plugin_test.rb +306 -0
 - data/spec/integration/prepared_statement_test.rb +32 -0
 - data/spec/integration/schema_test.rb +8 -3
 - data/spec/integration/spec_helper.rb +1 -25
 - data/spec/model/association_reflection_spec.rb +38 -0
 - data/spec/model/associations_spec.rb +184 -8
 - data/spec/model/eager_loading_spec.rb +23 -0
 - data/spec/model/model_spec.rb +8 -0
 - data/spec/model/record_spec.rb +84 -1
 - metadata +9 -2
 
| 
         @@ -23,11 +23,43 @@ describe "Prepared Statements and Bound Arguments" do 
     | 
|
| 
       23 
23 
     | 
    
         
             
                @ds.filter(:number=>@ds.ba(:$n)).call(:all, :n=>10).should == [{:id=>1, :number=>10}]
         
     | 
| 
       24 
24 
     | 
    
         
             
                @ds.filter(:number=>@ds.ba(:$n)).call(:first, :n=>10).should == {:id=>1, :number=>10}
         
     | 
| 
       25 
25 
     | 
    
         
             
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
              specify "should support blocks for select and all" do
         
     | 
| 
      
 28 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).call(:select, :n=>10){|r| r[:number] *= 2}.should == [{:id=>1, :number=>20}]
         
     | 
| 
      
 29 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).call(:all, :n=>10){|r| r[:number] *= 2}.should == [{:id=>1, :number=>20}]
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
              specify "should support binding variables before the call with #bind" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>10).call(:select).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 34 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>10).call(:all).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 35 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>10).call(:first).should == {:id=>1, :number=>10}
         
     | 
| 
      
 36 
     | 
    
         
            +
                
         
     | 
| 
      
 37 
     | 
    
         
            +
                @ds.bind(:n=>10).filter(:number=>@ds.ba(:$n)).call(:select).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 38 
     | 
    
         
            +
                @ds.bind(:n=>10).filter(:number=>@ds.ba(:$n)).call(:all).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 39 
     | 
    
         
            +
                @ds.bind(:n=>10).filter(:number=>@ds.ba(:$n)).call(:first).should == {:id=>1, :number=>10}
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
              
         
     | 
| 
      
 42 
     | 
    
         
            +
              specify "should allow overriding variables specified with #bind" do
         
     | 
| 
      
 43 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>1).call(:select, :n=>10).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 44 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>1).call(:all, :n=>10).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 45 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>1).call(:first, :n=>10).should == {:id=>1, :number=>10}
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>1).bind(:n=>10).call(:select).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 48 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>1).bind(:n=>10).call(:all).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 49 
     | 
    
         
            +
                @ds.filter(:number=>@ds.ba(:$n)).bind(:n=>1).bind(:n=>10).call(:first).should == {:id=>1, :number=>10}
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
       26 
51 
     | 
    
         | 
| 
       27 
52 
     | 
    
         
             
              specify "should support placeholder literal strings" do
         
     | 
| 
       28 
53 
     | 
    
         
             
                @ds.filter("number = ?", @ds.ba(:$n)).call(:select, :n=>10).should == [{:id=>1, :number=>10}]
         
     | 
| 
       29 
54 
     | 
    
         
             
              end
         
     | 
| 
       30 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
              specify "should support named placeholder literal strings and handle multiple named placeholders correctly" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                @ds.filter("number = :n", :n=>@ds.ba(:$n)).call(:select, :n=>10).should == [{:id=>1, :number=>10}]
         
     | 
| 
      
 58 
     | 
    
         
            +
                @ds.insert(:number=>20)
         
     | 
| 
      
 59 
     | 
    
         
            +
                @ds.insert(:number=>30)
         
     | 
| 
      
 60 
     | 
    
         
            +
                @ds.filter("number > :n1 AND number < :n2 AND number = :n3", :n3=>@ds.ba(:$n3), :n2=>@ds.ba(:$n2), :n1=>@ds.ba(:$n1)).call(:select, :n3=>20, :n2=>30, :n1=>10).should == [{:id=>2, :number=>20}]
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       31 
63 
     | 
    
         
             
              specify "should support datasets with static sql and placeholders" do
         
     | 
| 
       32 
64 
     | 
    
         
             
                INTEGRATION_DB["SELECT * FROM items WHERE number = ?", @ds.ba(:$n)].call(:select, :n=>10).should == [{:id=>1, :number=>10}]
         
     | 
| 
       33 
65 
     | 
    
         
             
              end
         
     | 
| 
         @@ -29,10 +29,8 @@ describe "Database schema parser" do 
     | 
|
| 
       29 
29 
     | 
    
         
             
                INTEGRATION_DB.schema(:items, :reload=>true)
         
     | 
| 
       30 
30 
     | 
    
         
             
                clear_sqls
         
     | 
| 
       31 
31 
     | 
    
         
             
                INTEGRATION_DB.schema(:items)
         
     | 
| 
       32 
     | 
    
         
            -
                sqls_should_be
         
     | 
| 
       33 
32 
     | 
    
         
             
                clear_sqls
         
     | 
| 
       34 
33 
     | 
    
         
             
                INTEGRATION_DB.schema(:items, :reload=>true)
         
     | 
| 
       35 
     | 
    
         
            -
                sqls_should_be "PRAGMA table_info('items')"
         
     | 
| 
       36 
34 
     | 
    
         
             
              end
         
     | 
| 
       37 
35 
     | 
    
         | 
| 
       38 
36 
     | 
    
         
             
              specify "should raise an error when the table doesn't exist" do
         
     | 
| 
         @@ -53,7 +51,6 @@ describe "Database schema parser" do 
     | 
|
| 
       53 
51 
     | 
    
         
             
                col_info[:type].should == :integer
         
     | 
| 
       54 
52 
     | 
    
         
             
                clear_sqls
         
     | 
| 
       55 
53 
     | 
    
         
             
                INTEGRATION_DB.schema(:items)
         
     | 
| 
       56 
     | 
    
         
            -
                sqls_should_be
         
     | 
| 
       57 
54 
     | 
    
         
             
              end
         
     | 
| 
       58 
55 
     | 
    
         | 
| 
       59 
56 
     | 
    
         
             
              cspecify "should parse primary keys from the schema properly", [proc{|db| db.class.adapter_scheme != :jdbc}, :mssql] do
         
     | 
| 
         @@ -161,6 +158,14 @@ describe "Database schema modifiers" do 
     | 
|
| 
       161 
158 
     | 
    
         
             
                @ds.insert([10])
         
     | 
| 
       162 
159 
     | 
    
         
             
                @ds.columns!.should == [:number]
         
     | 
| 
       163 
160 
     | 
    
         
             
              end
         
     | 
| 
      
 161 
     | 
    
         
            +
              
         
     | 
| 
      
 162 
     | 
    
         
            +
              specify "should allow creating indexes with tables" do
         
     | 
| 
      
 163 
     | 
    
         
            +
                @db.create_table!(:items){Integer :number; index :number}
         
     | 
| 
      
 164 
     | 
    
         
            +
                @db.table_exists?(:items).should == true
         
     | 
| 
      
 165 
     | 
    
         
            +
                @db.schema(:items, :reload=>true).map{|x| x.first}.should == [:number]
         
     | 
| 
      
 166 
     | 
    
         
            +
                @ds.insert([10])
         
     | 
| 
      
 167 
     | 
    
         
            +
                @ds.columns!.should == [:number]
         
     | 
| 
      
 168 
     | 
    
         
            +
              end
         
     | 
| 
       164 
169 
     | 
    
         | 
| 
       165 
170 
     | 
    
         
             
              specify "should handle foreign keys correctly when creating tables" do
         
     | 
| 
       166 
171 
     | 
    
         
             
                @db.create_table!(:items) do 
         
     | 
| 
         @@ -64,30 +64,6 @@ if defined?(INTEGRATION_DB) || defined?(INTEGRATION_URL) || ENV['SEQUEL_INTEGRAT 
     | 
|
| 
       64 
64 
     | 
    
         
             
                INTEGRATION_DB = Sequel.connect(url)
         
     | 
| 
       65 
65 
     | 
    
         
             
                #INTEGRATION_DB.instance_variable_set(:@server_version, 80100)
         
     | 
| 
       66 
66 
     | 
    
         
             
              end
         
     | 
| 
       67 
     | 
    
         
            -
              class Spec::Example::ExampleGroup
         
     | 
| 
       68 
     | 
    
         
            -
                def sqls_should_be(*args)
         
     | 
| 
       69 
     | 
    
         
            -
                end 
         
     | 
| 
       70 
     | 
    
         
            -
              end
         
     | 
| 
       71 
67 
     | 
    
         
             
            else
         
     | 
| 
       72 
     | 
    
         
            -
               
     | 
| 
       73 
     | 
    
         
            -
              def sql_logger.info(str)
         
     | 
| 
       74 
     | 
    
         
            -
                $sqls << str 
         
     | 
| 
       75 
     | 
    
         
            -
              end
         
     | 
| 
       76 
     | 
    
         
            -
              INTEGRATION_DB = Sequel.sqlite('', :loggers=>[sql_logger], :quote_identifiers=>false)
         
     | 
| 
       77 
     | 
    
         
            -
              class Spec::Example::ExampleGroup
         
     | 
| 
       78 
     | 
    
         
            -
                def sqls_should_be(*sqls)
         
     | 
| 
       79 
     | 
    
         
            -
                  sqls.zip($sqls).each do |should_be, is|
         
     | 
| 
       80 
     | 
    
         
            -
                    case should_be
         
     | 
| 
       81 
     | 
    
         
            -
                    when String
         
     | 
| 
       82 
     | 
    
         
            -
                      is.should == should_be
         
     | 
| 
       83 
     | 
    
         
            -
                    when Regexp
         
     | 
| 
       84 
     | 
    
         
            -
                      is.should =~ should_be
         
     | 
| 
       85 
     | 
    
         
            -
                    else
         
     | 
| 
       86 
     | 
    
         
            -
                      raise ArgumentError, "need String or RegExp"
         
     | 
| 
       87 
     | 
    
         
            -
                    end
         
     | 
| 
       88 
     | 
    
         
            -
                  end
         
     | 
| 
       89 
     | 
    
         
            -
                  $sqls.length.should == sqls.length
         
     | 
| 
       90 
     | 
    
         
            -
                  clear_sqls
         
     | 
| 
       91 
     | 
    
         
            -
                end 
         
     | 
| 
       92 
     | 
    
         
            -
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
              INTEGRATION_DB = Sequel.sqlite('', :quote_identifiers=>false)
         
     | 
| 
       93 
69 
     | 
    
         
             
            end
         
     | 
| 
         @@ -135,3 +135,41 @@ describe Sequel::Model::Associations::AssociationReflection, "#select" do 
     | 
|
| 
       135 
135 
     | 
    
         
             
              end
         
     | 
| 
       136 
136 
     | 
    
         
             
            end
         
     | 
| 
       137 
137 
     | 
    
         | 
| 
      
 138 
     | 
    
         
            +
            describe Sequel::Model::Associations::AssociationReflection, "#can_have_associated_objects?" do
         
     | 
| 
      
 139 
     | 
    
         
            +
              it "should be true for any given object (for backward compatibility)" do
         
     | 
| 
      
 140 
     | 
    
         
            +
                Sequel::Model::Associations::AssociationReflection.new.can_have_associated_objects?(Object.new).should == true
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
            end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            describe Sequel::Model::Associations::AssociationReflection, "#associated_object_keys" do
         
     | 
| 
      
 145 
     | 
    
         
            +
              before do
         
     | 
| 
      
 146 
     | 
    
         
            +
                @c = Class.new(Sequel::Model)
         
     | 
| 
      
 147 
     | 
    
         
            +
                class ::ParParent < Sequel::Model; end
         
     | 
| 
      
 148 
     | 
    
         
            +
              end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
              it "should use the primary keys for a many_to_one association" do
         
     | 
| 
      
 151 
     | 
    
         
            +
                @c.many_to_one :c, :class=>ParParent
         
     | 
| 
      
 152 
     | 
    
         
            +
                @c.association_reflection(:c).associated_object_keys.should == [:id]
         
     | 
| 
      
 153 
     | 
    
         
            +
                @c.many_to_one :c, :class=>ParParent, :primary_key=>:d_id
         
     | 
| 
      
 154 
     | 
    
         
            +
                @c.association_reflection(:c).associated_object_keys.should == [:d_id]
         
     | 
| 
      
 155 
     | 
    
         
            +
                @c.many_to_one :c, :class=>ParParent, :key=>[:c_id1, :c_id2], :primary_key=>[:id1, :id2]
         
     | 
| 
      
 156 
     | 
    
         
            +
                @c.association_reflection(:c).associated_object_keys.should == [:id1, :id2]
         
     | 
| 
      
 157 
     | 
    
         
            +
              end
         
     | 
| 
      
 158 
     | 
    
         
            +
              it "should use the keys for a one_to_many association" do
         
     | 
| 
      
 159 
     | 
    
         
            +
                ParParent.one_to_many :cs, :class=>ParParent
         
     | 
| 
      
 160 
     | 
    
         
            +
                ParParent.association_reflection(:cs).associated_object_keys.should == [:par_parent_id]
         
     | 
| 
      
 161 
     | 
    
         
            +
                @c.one_to_many :cs, :class=>ParParent, :key=>:d_id
         
     | 
| 
      
 162 
     | 
    
         
            +
                @c.association_reflection(:cs).associated_object_keys.should == [:d_id]
         
     | 
| 
      
 163 
     | 
    
         
            +
                @c.one_to_many :cs, :class=>ParParent, :key=>[:c_id1, :c_id2], :primary_key=>[:id1, :id2]
         
     | 
| 
      
 164 
     | 
    
         
            +
                @c.association_reflection(:cs).associated_object_keys.should == [:c_id1, :c_id2]
         
     | 
| 
      
 165 
     | 
    
         
            +
              end
         
     | 
| 
      
 166 
     | 
    
         
            +
              it "should use the right primary keys for a many_to_many association" do
         
     | 
| 
      
 167 
     | 
    
         
            +
                @c.many_to_many :cs, :class=>ParParent
         
     | 
| 
      
 168 
     | 
    
         
            +
                @c.association_reflection(:cs).associated_object_keys.should == [:id]
         
     | 
| 
      
 169 
     | 
    
         
            +
                @c.many_to_many :cs, :class=>ParParent, :right_primary_key=>:d_id
         
     | 
| 
      
 170 
     | 
    
         
            +
                @c.association_reflection(:cs).associated_object_keys.should == [:d_id]
         
     | 
| 
      
 171 
     | 
    
         
            +
                @c.many_to_many :cs, :class=>ParParent, :right_key=>[:c_id1, :c_id2], :right_primary_key=>[:id1, :id2]
         
     | 
| 
      
 172 
     | 
    
         
            +
                @c.association_reflection(:cs).associated_object_keys.should == [:id1, :id2]
         
     | 
| 
      
 173 
     | 
    
         
            +
              end
         
     | 
| 
      
 174 
     | 
    
         
            +
            end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
         @@ -193,6 +193,12 @@ describe Sequel::Model, "many_to_one" do 
     | 
|
| 
       193 
193 
     | 
    
         
             
                MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.parent_id = 1) AND (nodes.id = 234)) LIMIT 1"]
         
     | 
| 
       194 
194 
     | 
    
         
             
              end
         
     | 
| 
       195 
195 
     | 
    
         | 
| 
      
 196 
     | 
    
         
            +
              it "should not issue query if not all keys have values" do
         
     | 
| 
      
 197 
     | 
    
         
            +
                @c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
         
     | 
| 
      
 198 
     | 
    
         
            +
                @c2.new(:id => 1, :parent_id => nil).parent.should == nil
         
     | 
| 
      
 199 
     | 
    
         
            +
                MODEL_DB.sqls.should == []
         
     | 
| 
      
 200 
     | 
    
         
            +
              end
         
     | 
| 
      
 201 
     | 
    
         
            +
              
         
     | 
| 
       196 
202 
     | 
    
         
             
              it "should raise an Error unless same number of composite keys used" do
         
     | 
| 
       197 
203 
     | 
    
         
             
                proc{@c2.many_to_one :parent, :class => @c2, :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
         
     | 
| 
       198 
204 
     | 
    
         
             
                proc{@c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>:id}.should raise_error(Sequel::Error)
         
     | 
| 
         @@ -552,11 +558,13 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       552 
558 
     | 
    
         
             
                MODEL_DB.reset
         
     | 
| 
       553 
559 
     | 
    
         | 
| 
       554 
560 
     | 
    
         
             
                @c1 = Class.new(Sequel::Model(:attributes)) do
         
     | 
| 
      
 561 
     | 
    
         
            +
                  def _refresh(ds); end
         
     | 
| 
       555 
562 
     | 
    
         
             
                  unrestrict_primary_key
         
     | 
| 
       556 
563 
     | 
    
         
             
                  columns :id, :node_id, :y
         
     | 
| 
       557 
564 
     | 
    
         
             
                end
         
     | 
| 
       558 
565 
     | 
    
         | 
| 
       559 
566 
     | 
    
         
             
                @c2 = Class.new(Sequel::Model(:nodes)) do
         
     | 
| 
      
 567 
     | 
    
         
            +
                  def _refresh(ds); end
         
     | 
| 
       560 
568 
     | 
    
         
             
                  unrestrict_primary_key
         
     | 
| 
       561 
569 
     | 
    
         
             
                  attr_accessor :xxx
         
     | 
| 
       562 
570 
     | 
    
         | 
| 
         @@ -567,6 +575,7 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       567 
575 
     | 
    
         
             
                @dataset = @c2.dataset
         
     | 
| 
       568 
576 
     | 
    
         | 
| 
       569 
577 
     | 
    
         
             
                @c2.dataset.extend(Module.new {
         
     | 
| 
      
 578 
     | 
    
         
            +
                  def empty?; false; end
         
     | 
| 
       570 
579 
     | 
    
         
             
                  def fetch_rows(sql)
         
     | 
| 
       571 
580 
     | 
    
         
             
                    @db << sql
         
     | 
| 
       572 
581 
     | 
    
         
             
                    yield Hash.new
         
     | 
| 
         @@ -574,6 +583,7 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       574 
583 
     | 
    
         
             
                })
         
     | 
| 
       575 
584 
     | 
    
         | 
| 
       576 
585 
     | 
    
         
             
                @c1.dataset.extend(Module.new {
         
     | 
| 
      
 586 
     | 
    
         
            +
                  def empty?; opts.has_key?(:empty) ? (super; true) : false; end
         
     | 
| 
       577 
587 
     | 
    
         
             
                  def fetch_rows(sql)
         
     | 
| 
       578 
588 
     | 
    
         
             
                    @db << sql
         
     | 
| 
       579 
589 
     | 
    
         
             
                    yield Hash.new
         
     | 
| 
         @@ -632,6 +642,12 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       632 
642 
     | 
    
         
             
                @c2.load(:id => 1234, :x=>234).attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.id = 234))'
         
     | 
| 
       633 
643 
     | 
    
         
             
              end
         
     | 
| 
       634 
644 
     | 
    
         | 
| 
      
 645 
     | 
    
         
            +
              it "should not issue query if not all keys have values" do
         
     | 
| 
      
 646 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :id], :primary_key=>[:id, :x]
         
     | 
| 
      
 647 
     | 
    
         
            +
                @c2.load(:id => 1234, :x=>nil).attributes.should == []
         
     | 
| 
      
 648 
     | 
    
         
            +
                MODEL_DB.sqls.should == []
         
     | 
| 
      
 649 
     | 
    
         
            +
              end
         
     | 
| 
      
 650 
     | 
    
         
            +
              
         
     | 
| 
       635 
651 
     | 
    
         
             
              it "should raise an Error unless same number of composite keys used" do
         
     | 
| 
       636 
652 
     | 
    
         
             
                proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id]}.should raise_error(Sequel::Error)
         
     | 
| 
       637 
653 
     | 
    
         
             
                proc{@c2.one_to_many :attributes, :class => @c1, :primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
         
     | 
| 
         @@ -640,7 +656,7 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       640 
656 
     | 
    
         
             
                proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id, :x], :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
         
     | 
| 
       641 
657 
     | 
    
         
             
              end
         
     | 
| 
       642 
658 
     | 
    
         | 
| 
       643 
     | 
    
         
            -
              it "should define an add_ method" do
         
     | 
| 
      
 659 
     | 
    
         
            +
              it "should define an add_ method that works on existing records" do
         
     | 
| 
       644 
660 
     | 
    
         
             
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
       645 
661 
     | 
    
         | 
| 
       646 
662 
     | 
    
         
             
                n = @c2.new(:id => 1234)
         
     | 
| 
         @@ -648,20 +664,77 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       648 
664 
     | 
    
         
             
                a.save
         
     | 
| 
       649 
665 
     | 
    
         
             
                MODEL_DB.reset
         
     | 
| 
       650 
666 
     | 
    
         
             
                a.should == n.add_attribute(a)
         
     | 
| 
      
 667 
     | 
    
         
            +
                a.values.should == {:node_id => 1234, :id => 2345}
         
     | 
| 
       651 
668 
     | 
    
         
             
                MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 1234 WHERE (id = 2345)']
         
     | 
| 
       652 
669 
     | 
    
         
             
              end
         
     | 
| 
       653 
670 
     | 
    
         | 
| 
       654 
     | 
    
         
            -
              it "should define  
     | 
| 
      
 671 
     | 
    
         
            +
              it "should define an add_ method that works on new records" do
         
     | 
| 
       655 
672 
     | 
    
         
             
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
       656 
673 
     | 
    
         | 
| 
       657 
674 
     | 
    
         
             
                n = @c2.new(:id => 1234)
         
     | 
| 
       658 
     | 
    
         
            -
                a = @c1.new(:id =>  
     | 
| 
      
 675 
     | 
    
         
            +
                a = @c1.new(:id => 234)
         
     | 
| 
      
 676 
     | 
    
         
            +
                # do not save
         
     | 
| 
      
 677 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 678 
     | 
    
         
            +
                a.should == n.add_attribute(a)
         
     | 
| 
      
 679 
     | 
    
         
            +
                MODEL_DB.sqls.first.should =~ /INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/
         
     | 
| 
      
 680 
     | 
    
         
            +
                a.values.should == {:node_id => 1234, :id => 234}
         
     | 
| 
      
 681 
     | 
    
         
            +
              end
         
     | 
| 
      
 682 
     | 
    
         
            +
             
     | 
| 
      
 683 
     | 
    
         
            +
              it "should define a remove_ method that works on existing records" do
         
     | 
| 
      
 684 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
      
 685 
     | 
    
         
            +
                
         
     | 
| 
      
 686 
     | 
    
         
            +
                n = @c2.new(:id => 1234)
         
     | 
| 
      
 687 
     | 
    
         
            +
                a = @c1.new(:id => 2345, :node_id => 1234)
         
     | 
| 
       659 
688 
     | 
    
         
             
                a.save
         
     | 
| 
       660 
689 
     | 
    
         
             
                MODEL_DB.reset
         
     | 
| 
       661 
690 
     | 
    
         
             
                a.should == n.remove_attribute(a)
         
     | 
| 
      
 691 
     | 
    
         
            +
                a.values.should == {:node_id => nil, :id => 2345}
         
     | 
| 
       662 
692 
     | 
    
         
             
                MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
         
     | 
| 
       663 
693 
     | 
    
         
             
              end
         
     | 
| 
      
 694 
     | 
    
         
            +
             
     | 
| 
      
 695 
     | 
    
         
            +
              it "should have the remove_ method raise an error if the passed object is not already associated" do
         
     | 
| 
      
 696 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
      
 697 
     | 
    
         
            +
                @c1.dataset.opts[:empty] = true
         
     | 
| 
      
 698 
     | 
    
         
            +
                
         
     | 
| 
      
 699 
     | 
    
         
            +
                n = @c2.new(:id => 1234)
         
     | 
| 
      
 700 
     | 
    
         
            +
                a = @c1.load(:id => 2345, :node_id => 1234)
         
     | 
| 
      
 701 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 702 
     | 
    
         
            +
                proc{n.remove_attribute(a)}.should raise_error(Sequel::Error)
         
     | 
| 
      
 703 
     | 
    
         
            +
                MODEL_DB.sqls.should == ["SELECT 1 FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1"]
         
     | 
| 
      
 704 
     | 
    
         
            +
              end
         
     | 
| 
      
 705 
     | 
    
         
            +
             
     | 
| 
      
 706 
     | 
    
         
            +
              it "should accept a hash for the add_ method and create a new record" do
         
     | 
| 
      
 707 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
      
 708 
     | 
    
         
            +
                n = @c2.new(:id => 1234)
         
     | 
| 
      
 709 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 710 
     | 
    
         
            +
                @c1.load(:node_id => 1234, :id => 234).should == n.add_attribute(:id => 234)
         
     | 
| 
      
 711 
     | 
    
         
            +
                MODEL_DB.sqls.first.should =~ /INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/
         
     | 
| 
      
 712 
     | 
    
         
            +
              end
         
     | 
| 
      
 713 
     | 
    
         
            +
             
     | 
| 
      
 714 
     | 
    
         
            +
              it "should raise an error in the add_ method if the passed associated object is not of the correct type" do
         
     | 
| 
      
 715 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
      
 716 
     | 
    
         
            +
                proc{@c2.new(:id => 1234).add_attribute(@c2.new)}.should raise_error(Sequel::Error)
         
     | 
| 
      
 717 
     | 
    
         
            +
              end
         
     | 
| 
      
 718 
     | 
    
         
            +
             
     | 
| 
      
 719 
     | 
    
         
            +
              it "should accept a primary key for the remove_ method and remove an existing record" do
         
     | 
| 
      
 720 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
      
 721 
     | 
    
         
            +
                n = @c2.new(:id => 1234)
         
     | 
| 
      
 722 
     | 
    
         
            +
                ds = @c1.dataset
         
     | 
| 
      
 723 
     | 
    
         
            +
                def ds.fetch_rows(sql)
         
     | 
| 
      
 724 
     | 
    
         
            +
                  db << sql
         
     | 
| 
      
 725 
     | 
    
         
            +
                  yield({:id=>234, :node_id=>1234})
         
     | 
| 
      
 726 
     | 
    
         
            +
                end
         
     | 
| 
      
 727 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 728 
     | 
    
         
            +
                @c1.load(:node_id => nil, :id => 234).should == n.remove_attribute(234)
         
     | 
| 
      
 729 
     | 
    
         
            +
                MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 234)) LIMIT 1',
         
     | 
| 
      
 730 
     | 
    
         
            +
                  'UPDATE attributes SET node_id = NULL WHERE (id = 234)']
         
     | 
| 
      
 731 
     | 
    
         
            +
              end
         
     | 
| 
       664 
732 
     | 
    
         | 
| 
      
 733 
     | 
    
         
            +
              it "should raise an error in the remove_ method if the passed associated object is not of the correct type" do
         
     | 
| 
      
 734 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
      
 735 
     | 
    
         
            +
                proc{@c2.new(:id => 1234).remove_attribute(@c2.new)}.should raise_error(Sequel::Error)
         
     | 
| 
      
 736 
     | 
    
         
            +
              end
         
     | 
| 
      
 737 
     | 
    
         
            +
             
     | 
| 
       665 
738 
     | 
    
         
             
              it "should have add_ method respect the :primary_key option" do
         
     | 
| 
       666 
739 
     | 
    
         
             
                @c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
         
     | 
| 
       667 
740 
     | 
    
         | 
| 
         @@ -672,6 +745,21 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       672 
745 
     | 
    
         
             
                a.should == n.add_attribute(a)
         
     | 
| 
       673 
746 
     | 
    
         
             
                MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 5 WHERE (id = 2345)']
         
     | 
| 
       674 
747 
     | 
    
         
             
              end
         
     | 
| 
      
 748 
     | 
    
         
            +
              
         
     | 
| 
      
 749 
     | 
    
         
            +
              it "should have add_ method not add the same object to the cached association array if the object is already in the array" do
         
     | 
| 
      
 750 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
      
 751 
     | 
    
         
            +
                
         
     | 
| 
      
 752 
     | 
    
         
            +
                n = @c2.new(:id => 1234)
         
     | 
| 
      
 753 
     | 
    
         
            +
                a = @c1.new(:id => 2345)
         
     | 
| 
      
 754 
     | 
    
         
            +
                a.save
         
     | 
| 
      
 755 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 756 
     | 
    
         
            +
                n.associations[:attributes] = []
         
     | 
| 
      
 757 
     | 
    
         
            +
                a.should == n.add_attribute(a)
         
     | 
| 
      
 758 
     | 
    
         
            +
                a.should == n.add_attribute(a)
         
     | 
| 
      
 759 
     | 
    
         
            +
                a.values.should == {:node_id => 1234, :id => 2345}
         
     | 
| 
      
 760 
     | 
    
         
            +
                MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 1234 WHERE (id = 2345)'] * 2
         
     | 
| 
      
 761 
     | 
    
         
            +
                n.attributes.should == [a]
         
     | 
| 
      
 762 
     | 
    
         
            +
              end
         
     | 
| 
       675 
763 
     | 
    
         | 
| 
       676 
764 
     | 
    
         
             
              it "should have add_ method respect composite keys" do
         
     | 
| 
       677 
765 
     | 
    
         
             
                @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :y], :primary_key=>[:id, :x]
         
     | 
| 
         @@ -691,6 +779,22 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       691 
779 
     | 
    
         
             
                MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(id = 2345\)/
         
     | 
| 
       692 
780 
     | 
    
         
             
              end
         
     | 
| 
       693 
781 
     | 
    
         | 
| 
      
 782 
     | 
    
         
            +
              it "should accept a array of composite primary key values for the remove_ method and remove an existing record" do
         
     | 
| 
      
 783 
     | 
    
         
            +
                @c1.set_primary_key :id, :y
         
     | 
| 
      
 784 
     | 
    
         
            +
                @c2.one_to_many :attributes, :class => @c1, :key=>:node_id, :primary_key=>:id
         
     | 
| 
      
 785 
     | 
    
         
            +
                n = @c2.new(:id => 123)
         
     | 
| 
      
 786 
     | 
    
         
            +
                ds = @c1.dataset
         
     | 
| 
      
 787 
     | 
    
         
            +
                def ds.fetch_rows(sql)
         
     | 
| 
      
 788 
     | 
    
         
            +
                  db << sql
         
     | 
| 
      
 789 
     | 
    
         
            +
                  yield({:id=>234, :node_id=>123, :y=>5})
         
     | 
| 
      
 790 
     | 
    
         
            +
                end
         
     | 
| 
      
 791 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 792 
     | 
    
         
            +
                @c1.load(:node_id => nil, :y => 5, :id => 234).should == n.remove_attribute([234, 5])
         
     | 
| 
      
 793 
     | 
    
         
            +
                MODEL_DB.sqls.length.should == 2
         
     | 
| 
      
 794 
     | 
    
         
            +
                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 
     | 
    
         
            +
                MODEL_DB.sqls.last.should =~ /UPDATE attributes SET node_id = NULL WHERE \(\((id|y) = (234|5)\) AND \((id|y) = (234|5)\)\)/
         
     | 
| 
      
 796 
     | 
    
         
            +
              end
         
     | 
| 
      
 797 
     | 
    
         
            +
              
         
     | 
| 
       694 
798 
     | 
    
         
             
              it "should raise an error in add_ and remove_ if the passed object returns false to save (is not valid)" do
         
     | 
| 
       695 
799 
     | 
    
         
             
                @c2.one_to_many :attributes, :class => @c1
         
     | 
| 
       696 
800 
     | 
    
         
             
                n = @c2.new(:id => 1234)
         
     | 
| 
         @@ -714,7 +818,6 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       714 
818 
     | 
    
         
             
                a = @c2.new
         
     | 
| 
       715 
819 
     | 
    
         
             
                n = @c1.load(:id=>123)
         
     | 
| 
       716 
820 
     | 
    
         
             
                proc{a.attributes_dataset}.should raise_error(Sequel::Error)
         
     | 
| 
       717 
     | 
    
         
            -
                proc{a.attributes}.should raise_error(Sequel::Error)
         
     | 
| 
       718 
821 
     | 
    
         
             
                proc{a.add_attribute(n)}.should raise_error(Sequel::Error)
         
     | 
| 
       719 
822 
     | 
    
         
             
                proc{a.remove_attribute(n)}.should raise_error(Sequel::Error)
         
     | 
| 
       720 
823 
     | 
    
         
             
                proc{a.remove_all_attributes}.should raise_error(Sequel::Error)
         
     | 
| 
         @@ -1056,6 +1159,7 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       1056 
1159 
     | 
    
         
             
                @c2.one_to_many :attributes, :class => @c1, :one_to_one=>true
         
     | 
| 
       1057 
1160 
     | 
    
         
             
                attrib = @c1.new(:id=>3)
         
     | 
| 
       1058 
1161 
     | 
    
         
             
                d = @c1.dataset
         
     | 
| 
      
 1162 
     | 
    
         
            +
                @c1.class_eval{remove_method :_refresh}
         
     | 
| 
       1059 
1163 
     | 
    
         
             
                def d.fetch_rows(s); yield({:id=>3}) end
         
     | 
| 
       1060 
1164 
     | 
    
         
             
                @c2.new(:id => 1234).attribute = attrib
         
     | 
| 
       1061 
1165 
     | 
    
         
             
                ['INSERT INTO attributes (node_id, id) VALUES (1234, 3)',
         
     | 
| 
         @@ -1086,6 +1190,7 @@ describe Sequel::Model, "one_to_many" do 
     | 
|
| 
       1086 
1190 
     | 
    
         
             
                @c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :primary_key=>:xxx
         
     | 
| 
       1087 
1191 
     | 
    
         
             
                attrib = @c1.new(:id=>3)
         
     | 
| 
       1088 
1192 
     | 
    
         
             
                d = @c1.dataset
         
     | 
| 
      
 1193 
     | 
    
         
            +
                @c1.class_eval{remove_method :_refresh}
         
     | 
| 
       1089 
1194 
     | 
    
         
             
                def d.fetch_rows(s); yield({:id=>3}) end
         
     | 
| 
       1090 
1195 
     | 
    
         
             
                @c2.new(:id => 1234, :xxx=>5).attribute = attrib
         
     | 
| 
       1091 
1196 
     | 
    
         
             
                ['INSERT INTO attributes (node_id, id) VALUES (5, 3)',
         
     | 
| 
         @@ -1410,6 +1515,12 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1410 
1515 
     | 
    
         
             
                @c2.load(:id => 1234, :x=>5).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.r1 = attributes.id) AND (attributes_nodes.r2 = attributes.y) AND (attributes_nodes.l1 = 1234) AND (attributes_nodes.l2 = 5))'
         
     | 
| 
       1411 
1516 
     | 
    
         
             
              end
         
     | 
| 
       1412 
1517 
     | 
    
         | 
| 
      
 1518 
     | 
    
         
            +
              it "should not issue query if not all keys have values" do
         
     | 
| 
      
 1519 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
         
     | 
| 
      
 1520 
     | 
    
         
            +
                @c2.load(:id => 1234, :x=>nil).attributes.should == []
         
     | 
| 
      
 1521 
     | 
    
         
            +
                MODEL_DB.sqls.should == []
         
     | 
| 
      
 1522 
     | 
    
         
            +
              end
         
     | 
| 
      
 1523 
     | 
    
         
            +
              
         
     | 
| 
       1413 
1524 
     | 
    
         
             
              it "should raise an Error unless same number of composite keys used" do
         
     | 
| 
       1414 
1525 
     | 
    
         
             
                proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
         
     | 
| 
       1415 
1526 
     | 
    
         
             
                proc{@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
         
     | 
| 
         @@ -1504,7 +1615,7 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1504 
1615 
     | 
    
         
             
                @c2.new(:id => 1234).attributes_dataset.opts[:eager].should == {:attributes=>nil}
         
     | 
| 
       1505 
1616 
     | 
    
         
             
              end
         
     | 
| 
       1506 
1617 
     | 
    
         | 
| 
       1507 
     | 
    
         
            -
              it "should define an add_ method" do
         
     | 
| 
      
 1618 
     | 
    
         
            +
              it "should define an add_ method that works on existing records" do
         
     | 
| 
       1508 
1619 
     | 
    
         
             
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
       1509 
1620 
     | 
    
         | 
| 
       1510 
1621 
     | 
    
         
             
                n = @c2.load(:id => 1234)
         
     | 
| 
         @@ -1515,7 +1626,18 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1515 
1626 
     | 
    
         
             
                ].should(include(MODEL_DB.sqls.first))
         
     | 
| 
       1516 
1627 
     | 
    
         
             
              end
         
     | 
| 
       1517 
1628 
     | 
    
         | 
| 
       1518 
     | 
    
         
            -
              it "should  
     | 
| 
      
 1629 
     | 
    
         
            +
              it "should allow passing a hash to the add_ method which creates a new record" do
         
     | 
| 
      
 1630 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
      
 1631 
     | 
    
         
            +
                
         
     | 
| 
      
 1632 
     | 
    
         
            +
                n = @c2.load(:id => 1234)
         
     | 
| 
      
 1633 
     | 
    
         
            +
                @c1.load(:id => 1).should == n.add_attribute(:id => 1)
         
     | 
| 
      
 1634 
     | 
    
         
            +
                MODEL_DB.sqls.first.should == 'INSERT INTO attributes (id) VALUES (1)'
         
     | 
| 
      
 1635 
     | 
    
         
            +
                ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 1)',
         
     | 
| 
      
 1636 
     | 
    
         
            +
                 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (1, 1234)'
         
     | 
| 
      
 1637 
     | 
    
         
            +
                ].should(include(MODEL_DB.sqls.last))
         
     | 
| 
      
 1638 
     | 
    
         
            +
              end
         
     | 
| 
      
 1639 
     | 
    
         
            +
             
     | 
| 
      
 1640 
     | 
    
         
            +
              it "should define a remove_ method that works on existing records" do
         
     | 
| 
       1519 
1641 
     | 
    
         
             
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
       1520 
1642 
     | 
    
         | 
| 
       1521 
1643 
     | 
    
         
             
                n = @c2.new(:id => 1234)
         
     | 
| 
         @@ -1524,6 +1646,30 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1524 
1646 
     | 
    
         
             
                MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 2345))'
         
     | 
| 
       1525 
1647 
     | 
    
         
             
              end
         
     | 
| 
       1526 
1648 
     | 
    
         | 
| 
      
 1649 
     | 
    
         
            +
              it "should raise an error in the add_ method if the passed associated object is not of the correct type" do
         
     | 
| 
      
 1650 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
      
 1651 
     | 
    
         
            +
                proc{@c2.new(:id => 1234).add_attribute(@c2.new)}.should raise_error(Sequel::Error)
         
     | 
| 
      
 1652 
     | 
    
         
            +
              end
         
     | 
| 
      
 1653 
     | 
    
         
            +
             
     | 
| 
      
 1654 
     | 
    
         
            +
              it "should accept a primary key for the remove_ method and remove an existing record" do
         
     | 
| 
      
 1655 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
      
 1656 
     | 
    
         
            +
                n = @c2.new(:id => 1234)
         
     | 
| 
      
 1657 
     | 
    
         
            +
                ds = @c1.dataset
         
     | 
| 
      
 1658 
     | 
    
         
            +
                def ds.fetch_rows(sql)
         
     | 
| 
      
 1659 
     | 
    
         
            +
                  db << sql
         
     | 
| 
      
 1660 
     | 
    
         
            +
                  yield({:id=>234})
         
     | 
| 
      
 1661 
     | 
    
         
            +
                end
         
     | 
| 
      
 1662 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 1663 
     | 
    
         
            +
                @c1.load(:id => 234).should == n.remove_attribute(234)
         
     | 
| 
      
 1664 
     | 
    
         
            +
                MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (id = 234) LIMIT 1',
         
     | 
| 
      
 1665 
     | 
    
         
            +
                  'DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 234))']
         
     | 
| 
      
 1666 
     | 
    
         
            +
              end
         
     | 
| 
      
 1667 
     | 
    
         
            +
                
         
     | 
| 
      
 1668 
     | 
    
         
            +
              it "should raise an error in the remove_ method if the passed associated object is not of the correct type" do
         
     | 
| 
      
 1669 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
      
 1670 
     | 
    
         
            +
                proc{@c2.new(:id => 1234).remove_attribute(@c2.new)}.should raise_error(Sequel::Error)
         
     | 
| 
      
 1671 
     | 
    
         
            +
              end
         
     | 
| 
      
 1672 
     | 
    
         
            +
             
     | 
| 
       1527 
1673 
     | 
    
         
             
              it "should have the add_ method respect the :left_primary_key and :right_primary_key options" do
         
     | 
| 
       1528 
1674 
     | 
    
         
             
                @c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
         
     | 
| 
       1529 
1675 
     | 
    
         | 
| 
         @@ -1535,6 +1681,17 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1535 
1681 
     | 
    
         
             
                ].should(include(MODEL_DB.sqls.first))
         
     | 
| 
       1536 
1682 
     | 
    
         
             
              end
         
     | 
| 
       1537 
1683 
     | 
    
         | 
| 
      
 1684 
     | 
    
         
            +
              it "should have add_ method not add the same object to the cached association array if the object is already in the array" do
         
     | 
| 
      
 1685 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
      
 1686 
     | 
    
         
            +
                
         
     | 
| 
      
 1687 
     | 
    
         
            +
                n = @c2.load(:id => 1234).set(:xxx=>5)
         
     | 
| 
      
 1688 
     | 
    
         
            +
                a = @c1.load(:id => 2345).set(:yyy=>8)
         
     | 
| 
      
 1689 
     | 
    
         
            +
                n.associations[:attributes] = []
         
     | 
| 
      
 1690 
     | 
    
         
            +
                a.should == n.add_attribute(a)
         
     | 
| 
      
 1691 
     | 
    
         
            +
                a.should == n.add_attribute(a)
         
     | 
| 
      
 1692 
     | 
    
         
            +
                n.attributes.should == [a]
         
     | 
| 
      
 1693 
     | 
    
         
            +
              end
         
     | 
| 
      
 1694 
     | 
    
         
            +
              
         
     | 
| 
       1538 
1695 
     | 
    
         
             
              it "should have the add_ method respect composite keys" do
         
     | 
| 
       1539 
1696 
     | 
    
         
             
                @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
         
     | 
| 
       1540 
1697 
     | 
    
         
             
                n = @c2.load(:id => 1234, :x=>5)
         
     | 
| 
         @@ -1572,12 +1729,27 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1572 
1729 
     | 
    
         
             
                MODEL_DB.sqls.should == ["DELETE FROM attributes_nodes WHERE ((l1 = 1234) AND (l2 = 5) AND (r1 = 2345) AND (r2 = 8))"]
         
     | 
| 
       1573 
1730 
     | 
    
         
             
              end
         
     | 
| 
       1574 
1731 
     | 
    
         | 
| 
      
 1732 
     | 
    
         
            +
              it "should accept a array of composite primary key values for the remove_ method and remove an existing record" do
         
     | 
| 
      
 1733 
     | 
    
         
            +
                @c1.set_primary_key [:id, :y]
         
     | 
| 
      
 1734 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1
         
     | 
| 
      
 1735 
     | 
    
         
            +
                n = @c2.new(:id => 1234)
         
     | 
| 
      
 1736 
     | 
    
         
            +
                ds = @c1.dataset
         
     | 
| 
      
 1737 
     | 
    
         
            +
                def ds.fetch_rows(sql)
         
     | 
| 
      
 1738 
     | 
    
         
            +
                  db << sql
         
     | 
| 
      
 1739 
     | 
    
         
            +
                  yield({:id=>234, :y=>8})
         
     | 
| 
      
 1740 
     | 
    
         
            +
                end
         
     | 
| 
      
 1741 
     | 
    
         
            +
                MODEL_DB.reset
         
     | 
| 
      
 1742 
     | 
    
         
            +
                @c1.load(:id => 234, :y=>8).should == n.remove_attribute([234, 8])
         
     | 
| 
      
 1743 
     | 
    
         
            +
                MODEL_DB.sqls.length.should == 2
         
     | 
| 
      
 1744 
     | 
    
         
            +
                MODEL_DB.sqls.first.should =~ /SELECT \* FROM attributes WHERE \(\((id|y) = (234|8)\) AND \((id|y) = (234|8)\)\) LIMIT 1/
         
     | 
| 
      
 1745 
     | 
    
         
            +
                MODEL_DB.sqls.last.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 234))'
         
     | 
| 
      
 1746 
     | 
    
         
            +
              end
         
     | 
| 
      
 1747 
     | 
    
         
            +
                
         
     | 
| 
       1575 
1748 
     | 
    
         
             
              it "should raise an error if the model object doesn't have a valid primary key" do
         
     | 
| 
       1576 
1749 
     | 
    
         
             
                @c2.many_to_many :attributes, :class => @c1 
         
     | 
| 
       1577 
1750 
     | 
    
         
             
                a = @c2.new
         
     | 
| 
       1578 
1751 
     | 
    
         
             
                n = @c1.load(:id=>123)
         
     | 
| 
       1579 
1752 
     | 
    
         
             
                proc{a.attributes_dataset}.should raise_error(Sequel::Error)
         
     | 
| 
       1580 
     | 
    
         
            -
                proc{a.attributes}.should raise_error(Sequel::Error)
         
     | 
| 
       1581 
1753 
     | 
    
         
             
                proc{a.add_attribute(n)}.should raise_error(Sequel::Error)
         
     | 
| 
       1582 
1754 
     | 
    
         
             
                proc{a.remove_attribute(n)}.should raise_error(Sequel::Error)
         
     | 
| 
       1583 
1755 
     | 
    
         
             
                proc{a.remove_all_attributes}.should raise_error(Sequel::Error)
         
     | 
| 
         @@ -1957,7 +2129,6 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1957 
2129 
     | 
    
         
             
              end
         
     | 
| 
       1958 
2130 
     | 
    
         | 
| 
       1959 
2131 
     | 
    
         
             
              it "should support a :uniq option that removes duplicates from the association" do
         
     | 
| 
       1960 
     | 
    
         
            -
                h = []
         
     | 
| 
       1961 
2132 
     | 
    
         
             
                @c2.many_to_many :attributes, :class => @c1, :uniq=>true
         
     | 
| 
       1962 
2133 
     | 
    
         
             
                @c1.class_eval do
         
     | 
| 
       1963 
2134 
     | 
    
         
             
                  def @dataset.fetch_rows(sql)
         
     | 
| 
         @@ -1969,6 +2140,11 @@ describe Sequel::Model, "many_to_many" do 
     | 
|
| 
       1969 
2140 
     | 
    
         
             
                end
         
     | 
| 
       1970 
2141 
     | 
    
         
             
                @c2.load(:id=>10, :parent_id=>20).attributes.should == [@c1.load(:id=>20), @c1.load(:id=>30)]
         
     | 
| 
       1971 
2142 
     | 
    
         
             
              end
         
     | 
| 
      
 2143 
     | 
    
         
            +
              
         
     | 
| 
      
 2144 
     | 
    
         
            +
              it "should support a :distinct option that uses the DISTINCT clause" do
         
     | 
| 
      
 2145 
     | 
    
         
            +
                @c2.many_to_many :attributes, :class => @c1, :distinct=>true
         
     | 
| 
      
 2146 
     | 
    
         
            +
                @c2.load(:id=>10).attributes_dataset.sql.should == "SELECT DISTINCT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 10))"
         
     | 
| 
      
 2147 
     | 
    
         
            +
              end
         
     | 
| 
       1972 
2148 
     | 
    
         
             
            end
         
     | 
| 
       1973 
2149 
     | 
    
         | 
| 
       1974 
2150 
     | 
    
         
             
            describe Sequel::Model, " association reflection methods" do
         
     |