sequel 3.4.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +84 -0
- data/Rakefile +1 -1
- data/doc/cheat_sheet.rdoc +5 -2
- data/doc/opening_databases.rdoc +2 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/lib/sequel/adapters/ado.rb +3 -1
- data/lib/sequel/adapters/ado/mssql.rb +2 -2
- data/lib/sequel/adapters/do.rb +2 -11
- data/lib/sequel/adapters/do/mysql.rb +7 -0
- data/lib/sequel/adapters/do/postgres.rb +2 -2
- data/lib/sequel/adapters/firebird.rb +3 -3
- data/lib/sequel/adapters/informix.rb +3 -3
- data/lib/sequel/adapters/jdbc/h2.rb +3 -3
- data/lib/sequel/adapters/jdbc/mssql.rb +7 -0
- data/lib/sequel/adapters/mysql.rb +60 -21
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +3 -3
- data/lib/sequel/adapters/oracle.rb +1 -5
- data/lib/sequel/adapters/postgres.rb +3 -3
- data/lib/sequel/adapters/shared/mssql.rb +142 -33
- data/lib/sequel/adapters/shared/mysql.rb +54 -31
- data/lib/sequel/adapters/shared/oracle.rb +17 -6
- data/lib/sequel/adapters/shared/postgres.rb +7 -7
- data/lib/sequel/adapters/shared/progress.rb +3 -3
- data/lib/sequel/adapters/shared/sqlite.rb +3 -17
- data/lib/sequel/connection_pool.rb +4 -6
- data/lib/sequel/core.rb +29 -113
- data/lib/sequel/database.rb +14 -12
- data/lib/sequel/dataset.rb +8 -21
- data/lib/sequel/dataset/convenience.rb +1 -1
- data/lib/sequel/dataset/graph.rb +9 -2
- data/lib/sequel/dataset/sql.rb +170 -104
- data/lib/sequel/exceptions.rb +3 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/schema_dumper.rb +7 -1
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +4 -4
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/model/associations.rb +105 -45
- data/lib/sequel/model/base.rb +37 -28
- data/lib/sequel/plugins/active_model.rb +35 -0
- data/lib/sequel/plugins/association_dependencies.rb +96 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/force_encoding.rb +61 -0
- data/lib/sequel/plugins/many_through_many.rb +32 -11
- data/lib/sequel/plugins/nested_attributes.rb +7 -2
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +61 -0
- data/lib/sequel/sql.rb +31 -30
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +262 -0
- data/spec/adapters/mysql_spec.rb +46 -8
- data/spec/adapters/postgres_spec.rb +6 -3
- data/spec/adapters/spec_helper.rb +21 -0
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/core/connection_pool_spec.rb +1 -1
- data/spec/core/database_spec.rb +27 -1
- data/spec/core/dataset_spec.rb +63 -1
- data/spec/core/object_graph_spec.rb +1 -1
- data/spec/core/schema_spec.rb +1 -0
- data/spec/extensions/active_model_spec.rb +47 -0
- data/spec/extensions/association_dependencies_spec.rb +108 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/force_encoding_spec.rb +75 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +60 -2
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +29 -1
- data/spec/extensions/schema_dumper_spec.rb +10 -0
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +60 -0
- data/spec/integration/database_test.rb +8 -0
- data/spec/integration/dataset_test.rb +9 -9
- data/spec/integration/plugin_test.rb +139 -0
- data/spec/integration/schema_test.rb +7 -7
- data/spec/integration/spec_helper.rb +32 -1
- data/spec/integration/timezone_test.rb +3 -3
- data/spec/integration/transaction_test.rb +1 -1
- data/spec/integration/type_test.rb +6 -6
- data/spec/model/association_reflection_spec.rb +18 -0
- data/spec/model/associations_spec.rb +169 -9
- data/spec/model/base_spec.rb +2 -0
- data/spec/model/eager_loading_spec.rb +82 -2
- data/spec/model/model_spec.rb +8 -1
- data/spec/model/record_spec.rb +52 -9
- metadata +33 -23
@@ -56,7 +56,7 @@ describe "Database schema parser" do
|
|
56
56
|
sqls_should_be
|
57
57
|
end
|
58
58
|
|
59
|
-
|
59
|
+
cspecify "should parse primary keys from the schema properly", [proc{|db| db.class.adapter_scheme != :jdbc}, :mssql] do
|
60
60
|
INTEGRATION_DB.create_table!(:items){Integer :number}
|
61
61
|
INTEGRATION_DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == []
|
62
62
|
INTEGRATION_DB.create_table!(:items){primary_key :number}
|
@@ -81,7 +81,7 @@ describe "Database schema parser" do
|
|
81
81
|
INTEGRATION_DB.schema(:items).first.last[:ruby_default].should == 'blah'
|
82
82
|
end
|
83
83
|
|
84
|
-
|
84
|
+
cspecify "should parse types from the schema properly", [:do, :mysql], [:jdbc, :mysql] do
|
85
85
|
INTEGRATION_DB.create_table!(:items){Integer :number}
|
86
86
|
INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
|
87
87
|
INTEGRATION_DB.create_table!(:items){Fixnum :number}
|
@@ -183,7 +183,7 @@ describe "Database schema modifiers" do
|
|
183
183
|
@ds.all.should == [{:number=>10, :name=>nil}]
|
184
184
|
end
|
185
185
|
|
186
|
-
|
186
|
+
cspecify "should add primary key columns to tables correctly", :h2 do
|
187
187
|
@db.create_table!(:items){Integer :number}
|
188
188
|
@ds.insert(:number=>10)
|
189
189
|
@db.alter_table(:items){add_primary_key :id}
|
@@ -220,7 +220,7 @@ describe "Database schema modifiers" do
|
|
220
220
|
@ds.all.should == [{:n2=>'blah'}, {:n2=>'blah'}]
|
221
221
|
end
|
222
222
|
|
223
|
-
|
223
|
+
cspecify "should rename columns with not null constraints", [:mysql, :mysql] do
|
224
224
|
@db.create_table!(:items){String :n, :null=>false}
|
225
225
|
@ds.insert(:n=>'blah')
|
226
226
|
@db.alter_table(:items){rename_column :n, :n2}
|
@@ -231,7 +231,7 @@ describe "Database schema modifiers" do
|
|
231
231
|
proc{@ds.insert}.should raise_error(Sequel::DatabaseError)
|
232
232
|
end
|
233
233
|
|
234
|
-
|
234
|
+
cspecify "should set column NULL/NOT NULL correctly", [:mysql, :mysql] do
|
235
235
|
@db.create_table!(:items){Integer :id}
|
236
236
|
@ds.insert(:id=>10)
|
237
237
|
@db.alter_table(:items){set_column_allow_null :id, false}
|
@@ -263,7 +263,7 @@ describe "Database schema modifiers" do
|
|
263
263
|
@ds.all.should == [{:id=>"10"}, {:id=>"20"}]
|
264
264
|
end
|
265
265
|
|
266
|
-
|
266
|
+
cspecify "should add unique constraints and foreign key table constraints correctly", :sqlite do
|
267
267
|
@db.create_table!(:items){Integer :id; Integer :item_id}
|
268
268
|
@db.alter_table(:items) do
|
269
269
|
add_unique_constraint [:item_id, :id]
|
@@ -273,7 +273,7 @@ describe "Database schema modifiers" do
|
|
273
273
|
@ds.columns!.should == [:id, :item_id]
|
274
274
|
end
|
275
275
|
|
276
|
-
|
276
|
+
cspecify "should remove columns from tables correctly", :h2, :mssql do
|
277
277
|
@db.create_table!(:items) do
|
278
278
|
primary_key :id
|
279
279
|
String :name
|
@@ -22,7 +22,38 @@ class Spec::Example::ExampleGroup
|
|
22
22
|
INTEGRATION_DB.loggers << Logger.new(STDOUT)
|
23
23
|
yield
|
24
24
|
ensure
|
25
|
-
INTEGRATION_DB.loggers.
|
25
|
+
INTEGRATION_DB.loggers.pop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.cspecify(message, *checked, &block)
|
30
|
+
pending = false
|
31
|
+
checked.each do |c|
|
32
|
+
case c
|
33
|
+
when INTEGRATION_DB.database_type
|
34
|
+
pending = c
|
35
|
+
when Array
|
36
|
+
case c.length
|
37
|
+
when 1
|
38
|
+
pending = c if c.first == INTEGRATION_DB.class.adapter_scheme
|
39
|
+
when 2
|
40
|
+
if c.first.is_a?(Proc)
|
41
|
+
pending = c if c.first.call(INTEGRATION_DB) && c.last == INTEGRATION_DB.database_type
|
42
|
+
elsif c.last.is_a?(Proc)
|
43
|
+
pending = c if c.first == INTEGRATION_DB.class.adapter_scheme && c.last.call(INTEGRATION_DB)
|
44
|
+
else
|
45
|
+
pending = c if c.first == INTEGRATION_DB.class.adapter_scheme && c.last == INTEGRATION_DB.database_type
|
46
|
+
end
|
47
|
+
when 3
|
48
|
+
pending = c if c[0] == INTEGRATION_DB.class.adapter_scheme && c[1] == INTEGRATION_DB.database_type && c[2].call(INTEGRATION_DB)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
break if pending
|
52
|
+
end
|
53
|
+
if pending
|
54
|
+
specify(message){pending("Not yet working on #{Array(pending).join(', ')}", &block)}
|
55
|
+
else
|
56
|
+
specify(message, &block)
|
26
57
|
end
|
27
58
|
end
|
28
59
|
end
|
@@ -31,19 +31,19 @@ describe "Sequel timezone support" do
|
|
31
31
|
Sequel.datetime_class = Time
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
cspecify "should support using UTC for database storage and local time for the application", [:do, proc{|db| db.database_type != :sqlite}] do
|
35
35
|
Sequel.database_timezone = :utc
|
36
36
|
Sequel.application_timezone = :local
|
37
37
|
test_timezone
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
cspecify "should support using local time for database storage and UTC for the application", [:do, proc{|db| db.database_type != :sqlite}] do
|
41
41
|
Sequel.database_timezone = :local
|
42
42
|
Sequel.application_timezone = :utc
|
43
43
|
test_timezone
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
cspecify "should support using UTC for both database storage and for application", [:do, proc{|db| db.database_type != :sqlite}] do
|
47
47
|
Sequel.default_timezone = :utc
|
48
48
|
test_timezone
|
49
49
|
end
|
@@ -71,7 +71,7 @@ describe "Database transactions" do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
if INTEGRATION_DB.supports_savepoints?
|
74
|
-
|
74
|
+
cspecify "should support nested transactions through savepoints using the savepoint option", [:jdbc, :sqlite] do
|
75
75
|
@db = INTEGRATION_DB
|
76
76
|
@db.transaction do
|
77
77
|
@d << {:name => '1'}
|
@@ -6,7 +6,7 @@ describe "Supported types" do
|
|
6
6
|
INTEGRATION_DB[:items]
|
7
7
|
end
|
8
8
|
|
9
|
-
|
9
|
+
cspecify "should support casting correctly", [:sqlite, :sqlite] do
|
10
10
|
ds = create_items_table_with_column(:number, Integer)
|
11
11
|
ds.insert(:number => 1)
|
12
12
|
ds.select(:number.cast_string.as(:n)).map(:n).should == %w'1'
|
@@ -45,7 +45,7 @@ describe "Supported types" do
|
|
45
45
|
ds.all.should == [{:number=>2.1}]
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
cspecify "should support generic numeric type", [:odbc, :mssql] do
|
49
49
|
ds = create_items_table_with_column(:number, Numeric, :size=>[15, 10])
|
50
50
|
ds.insert(:number => BigDecimal.new('2.123456789'))
|
51
51
|
ds.all.should == [{:number=>BigDecimal.new('2.123456789')}]
|
@@ -60,14 +60,14 @@ describe "Supported types" do
|
|
60
60
|
ds.all.should == [{:name=>'Test User'}]
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
cspecify "should support generic date type", [:do, :sqlite], [:jdbc, :sqlite], :mssql do
|
64
64
|
ds = create_items_table_with_column(:dat, Date)
|
65
65
|
d = Date.today
|
66
66
|
ds.insert(:dat => d)
|
67
67
|
ds.first[:dat].should == d
|
68
68
|
end
|
69
69
|
|
70
|
-
|
70
|
+
cspecify "should support generic datetime type", [:do, :sqlite], [:jdbc, :sqlite] do
|
71
71
|
ds = create_items_table_with_column(:tim, DateTime)
|
72
72
|
t = DateTime.now
|
73
73
|
ds.insert(:tim => t)
|
@@ -78,14 +78,14 @@ describe "Supported types" do
|
|
78
78
|
ds.first[:tim].strftime('%Y%m%d%H%M%S').should == t.strftime('%Y%m%d%H%M%S')
|
79
79
|
end
|
80
80
|
|
81
|
-
|
81
|
+
cspecify "should support generic file type", [:do], :h2, [:odbc, :mssql] do
|
82
82
|
ds = create_items_table_with_column(:name, File)
|
83
83
|
ds.insert(:name => ("a\0"*300).to_sequel_blob)
|
84
84
|
ds.all.should == [{:name=>("a\0"*300).to_sequel_blob}]
|
85
85
|
ds.first[:name].should be_a_kind_of(::Sequel::SQL::Blob)
|
86
86
|
end
|
87
87
|
|
88
|
-
|
88
|
+
cspecify "should support generic boolean type", [:do, :sqlite], [:jdbc, :sqlite], [:odbc, :mssql] do
|
89
89
|
ds = create_items_table_with_column(:number, TrueClass)
|
90
90
|
ds.insert(:number => true)
|
91
91
|
ds.all.should == [{:number=>true}]
|
@@ -73,6 +73,24 @@ describe Sequel::Model::Associations::AssociationReflection, "#reciprocal" do
|
|
73
73
|
ParParentTwo.association_reflection(:par_parents).reciprocal.should == :par_parent_twos
|
74
74
|
ParParentThree.association_reflection(:par_parents).reciprocal.should == :par_parent_threes
|
75
75
|
end
|
76
|
+
|
77
|
+
it "should handle composite keys" do
|
78
|
+
ParParent.many_to_one :par_parent_two, :key=>[:a, :b], :primary_key=>[:c, :b]
|
79
|
+
ParParent.many_to_one :par_parent_three, :key=>[:d, :e], :primary_key=>[:c, :b]
|
80
|
+
ParParentTwo.one_to_many :par_parents, :primary_key=>[:c, :b], :key=>[:a, :b]
|
81
|
+
ParParentThree.one_to_many :par_parents, :primary_key=>[:c, :b], :key=>[:d, :e]
|
82
|
+
|
83
|
+
ParParentTwo.association_reflection(:par_parents).reciprocal.should == :par_parent_two
|
84
|
+
ParParentThree.association_reflection(:par_parents).reciprocal.should == :par_parent_three
|
85
|
+
|
86
|
+
ParParent.many_to_many :par_parent_twos, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:pl1, :pl2], :right_primary_key=>[:pr1, :pr2], :join_table=>:jt
|
87
|
+
ParParent.many_to_many :par_parent_threes, :right_key=>[:l1, :l2], :left_key=>[:r1, :r2], :left_primary_key=>[:pl1, :pl2], :right_primary_key=>[:pr1, :pr2], :join_table=>:jt
|
88
|
+
ParParentTwo.many_to_many :par_parents, :right_key=>[:l1, :l2], :left_key=>[:r1, :r2], :right_primary_key=>[:pl1, :pl2], :left_primary_key=>[:pr1, :pr2], :join_table=>:jt
|
89
|
+
ParParentThree.many_to_many :par_parents, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :right_primary_key=>[:pl1, :pl2], :left_primary_key=>[:pr1, :pr2], :join_table=>:jt
|
90
|
+
|
91
|
+
ParParentTwo.association_reflection(:par_parents).reciprocal.should == :par_parent_twos
|
92
|
+
ParParentThree.association_reflection(:par_parents).reciprocal.should == :par_parent_threes
|
93
|
+
end
|
76
94
|
|
77
95
|
it "should figure out the reciprocal if the :reciprocal value is not present" do
|
78
96
|
ParParent.many_to_one :par_parent_two
|
@@ -186,6 +186,19 @@ describe Sequel::Model, "many_to_one" do
|
|
186
186
|
@c2.new(:id => 1, :blah => 567).parent
|
187
187
|
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.pk = 567) LIMIT 1"]
|
188
188
|
end
|
189
|
+
|
190
|
+
it "should support composite keys" do
|
191
|
+
@c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
|
192
|
+
@c2.new(:id => 1, :parent_id => 234).parent
|
193
|
+
MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.parent_id = 1) AND (nodes.id = 234)) LIMIT 1"]
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should raise an Error unless same number of composite keys used" do
|
197
|
+
proc{@c2.many_to_one :parent, :class => @c2, :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
198
|
+
proc{@c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>:id}.should raise_error(Sequel::Error)
|
199
|
+
proc{@c2.many_to_one :parent, :class => @c2, :key=>:id, :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
200
|
+
proc{@c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id, :blah], :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
201
|
+
end
|
189
202
|
|
190
203
|
it "should use :select option if given" do
|
191
204
|
@c2.many_to_one :parent, :class => @c2, :key => :blah, :select=>[:id, :name]
|
@@ -265,6 +278,21 @@ describe Sequel::Model, "many_to_one" do
|
|
265
278
|
d.values.should == {:id => 1, :parent_id => 8}
|
266
279
|
end
|
267
280
|
|
281
|
+
it "should have the setter method respect composite keys" do
|
282
|
+
@c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
|
283
|
+
|
284
|
+
d = @c2.new(:id => 1, :parent_id=> 234)
|
285
|
+
d.parent = @c2.new(:id => 4, :parent_id=>52)
|
286
|
+
d.values.should == {:id => 52, :parent_id => 4}
|
287
|
+
|
288
|
+
d.parent = nil
|
289
|
+
d.values.should == {:id => nil, :parent_id => nil}
|
290
|
+
|
291
|
+
e = @c2.new(:id => 6677, :parent_id=>8)
|
292
|
+
d.parent = e
|
293
|
+
d.values.should == {:id => 8, :parent_id => 6677}
|
294
|
+
end
|
295
|
+
|
268
296
|
it "should not persist changes until saved" do
|
269
297
|
@c2.many_to_one :parent, :class => @c2
|
270
298
|
|
@@ -520,13 +548,12 @@ describe Sequel::Model, "many_to_one" do
|
|
520
548
|
end
|
521
549
|
|
522
550
|
describe Sequel::Model, "one_to_many" do
|
523
|
-
|
524
|
-
before(:each) do
|
551
|
+
before do
|
525
552
|
MODEL_DB.reset
|
526
553
|
|
527
554
|
@c1 = Class.new(Sequel::Model(:attributes)) do
|
528
555
|
unrestrict_primary_key
|
529
|
-
columns :id, :node_id
|
556
|
+
columns :id, :node_id, :y
|
530
557
|
end
|
531
558
|
|
532
559
|
@c2 = Class.new(Sequel::Model(:nodes)) do
|
@@ -535,7 +562,7 @@ describe Sequel::Model, "one_to_many" do
|
|
535
562
|
|
536
563
|
def self.name; 'Node'; end
|
537
564
|
def self.to_s; 'Node'; end
|
538
|
-
columns :id
|
565
|
+
columns :id, :x
|
539
566
|
end
|
540
567
|
@dataset = @c2.dataset
|
541
568
|
|
@@ -599,6 +626,19 @@ describe Sequel::Model, "one_to_many" do
|
|
599
626
|
a.should be_a_kind_of(Sequel::Dataset)
|
600
627
|
a.sql.should == 'SELECT * FROM attributes WHERE (attributes.nodeid = 1234)'
|
601
628
|
end
|
629
|
+
|
630
|
+
it "should support_composite keys" do
|
631
|
+
@c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :id], :primary_key=>[:id, :x]
|
632
|
+
@c2.load(:id => 1234, :x=>234).attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.id = 234))'
|
633
|
+
end
|
634
|
+
|
635
|
+
it "should raise an Error unless same number of composite keys used" do
|
636
|
+
proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
637
|
+
proc{@c2.one_to_many :attributes, :class => @c1, :primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
638
|
+
proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id], :primary_key=>:id}.should raise_error(Sequel::Error)
|
639
|
+
proc{@c2.one_to_many :attributes, :class => @c1, :key=>:id, :primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
640
|
+
proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id, :x], :primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
641
|
+
end
|
602
642
|
|
603
643
|
it "should define an add_ method" do
|
604
644
|
@c2.one_to_many :attributes, :class => @c1
|
@@ -633,6 +673,23 @@ describe Sequel::Model, "one_to_many" do
|
|
633
673
|
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 5 WHERE (id = 2345)']
|
634
674
|
end
|
635
675
|
|
676
|
+
it "should have add_ method respect composite keys" do
|
677
|
+
@c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :y], :primary_key=>[:id, :x]
|
678
|
+
|
679
|
+
n = @c2.load(:id => 1234, :x=>5)
|
680
|
+
a = @c1.load(:id => 2345)
|
681
|
+
a.should == n.add_attribute(a)
|
682
|
+
MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 2345\)/
|
683
|
+
end
|
684
|
+
|
685
|
+
it "should have remove_ method respect composite keys" do
|
686
|
+
@c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :y], :primary_key=>[:id, :x]
|
687
|
+
|
688
|
+
n = @c2.load(:id => 1234, :x=>5)
|
689
|
+
a = @c1.load(:id => 2345, :node_id=>1234, :y=>5)
|
690
|
+
a.should == n.remove_attribute(a)
|
691
|
+
MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(id = 2345\)/
|
692
|
+
end
|
636
693
|
|
637
694
|
it "should raise an error in add_ and remove_ if the passed object returns false to save (is not valid)" do
|
638
695
|
@c2.one_to_many :attributes, :class => @c1
|
@@ -643,6 +700,15 @@ describe Sequel::Model, "one_to_many" do
|
|
643
700
|
proc{n.remove_attribute(a)}.should raise_error(Sequel::Error)
|
644
701
|
end
|
645
702
|
|
703
|
+
it "should not validate the associated object in add_ and remove_ if the :validate=>false option is used" do
|
704
|
+
@c2.one_to_many :attributes, :class => @c1, :validate=>false
|
705
|
+
n = @c2.new(:id => 1234)
|
706
|
+
a = @c1.new(:id => 2345)
|
707
|
+
def a.valid?; false; end
|
708
|
+
n.add_attribute(a).should == a
|
709
|
+
n.remove_attribute(a).should == a
|
710
|
+
end
|
711
|
+
|
646
712
|
it "should raise an error if the model object doesn't have a valid primary key" do
|
647
713
|
@c2.one_to_many :attributes, :class => @c1
|
648
714
|
a = @c2.new
|
@@ -914,6 +980,12 @@ describe Sequel::Model, "one_to_many" do
|
|
914
980
|
@c2.new(:id => 1234, :xxx=>5).remove_all_attributes
|
915
981
|
MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE (node_id = 5)'
|
916
982
|
end
|
983
|
+
|
984
|
+
it "should have the remove_all_ method respect composite keys" do
|
985
|
+
@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :y], :primary_key=>[:id, :x]
|
986
|
+
@c2.new(:id => 1234, :x=>5).remove_all_attributes
|
987
|
+
MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\)\)/
|
988
|
+
end
|
917
989
|
|
918
990
|
it "remove_all should set the cached instance variable to []" do
|
919
991
|
@c2.one_to_many :attributes, :class => @c1
|
@@ -929,7 +1001,7 @@ describe Sequel::Model, "one_to_many" do
|
|
929
1001
|
d = @c1.dataset
|
930
1002
|
def d.fetch_rows(s); end
|
931
1003
|
node.attributes.should == []
|
932
|
-
def attrib.save; self end
|
1004
|
+
def attrib.save(*); self end
|
933
1005
|
node.add_attribute(attrib)
|
934
1006
|
node.associations[:attributes].should == [attrib]
|
935
1007
|
node.remove_all_attributes.should == [attrib]
|
@@ -951,7 +1023,7 @@ describe Sequel::Model, "one_to_many" do
|
|
951
1023
|
node = @c2.new(:id => 1234)
|
952
1024
|
node.attributes.should == []
|
953
1025
|
attrib.node.should == nil
|
954
|
-
def attrib.save; self end
|
1026
|
+
def attrib.save(*); self end
|
955
1027
|
node.add_attribute(attrib)
|
956
1028
|
attrib.associations[:node].should == node
|
957
1029
|
node.remove_all_attributes
|
@@ -1026,6 +1098,16 @@ describe Sequel::Model, "one_to_many" do
|
|
1026
1098
|
@c2.new(:id => 621, :xxx=>5).attribute = attrib
|
1027
1099
|
MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 5 WHERE (id = 3)',
|
1028
1100
|
'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))']
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
it "should have the setter method for the :one_to_one option respect composite keys" do
|
1104
|
+
@c2.one_to_many :attributes, :class => @c1, :one_to_one=>true, :key=>[:node_id, :y], :primary_key=>[:id, :x]
|
1105
|
+
attrib = @c1.load(:id=>3, :y=>6)
|
1106
|
+
d = @c1.dataset
|
1107
|
+
def d.fetch_rows(s); yield({:id=>3, :y=>6}) end
|
1108
|
+
@c2.load(:id => 1234, :x=>5).attribute = attrib
|
1109
|
+
MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 3\)/
|
1110
|
+
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\)\)/
|
1029
1111
|
end
|
1030
1112
|
|
1031
1113
|
it "should raise an error if the one_to_one getter would be the same as the association name" do
|
@@ -1215,7 +1297,7 @@ describe Sequel::Model, "many_to_many" do
|
|
1215
1297
|
attr_accessor :yyy
|
1216
1298
|
def self.name; 'Attribute'; end
|
1217
1299
|
def self.to_s; 'Attribute'; end
|
1218
|
-
columns :id
|
1300
|
+
columns :id, :y
|
1219
1301
|
def _refresh(ds)
|
1220
1302
|
self.id = 1
|
1221
1303
|
self
|
@@ -1228,7 +1310,7 @@ describe Sequel::Model, "many_to_many" do
|
|
1228
1310
|
|
1229
1311
|
def self.name; 'Node'; end
|
1230
1312
|
def self.to_s; 'Node'; end
|
1231
|
-
columns :id
|
1313
|
+
columns :id, :x
|
1232
1314
|
end
|
1233
1315
|
@dataset = @c2.dataset
|
1234
1316
|
|
@@ -1323,6 +1405,24 @@ describe Sequel::Model, "many_to_many" do
|
|
1323
1405
|
@c2.new(:id => 1234, :xxx=>5).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.yyy) AND (attributes_nodes.node_id = 5))'
|
1324
1406
|
end
|
1325
1407
|
|
1408
|
+
it "should support composite keys" do
|
1409
|
+
@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]
|
1410
|
+
@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
|
+
end
|
1412
|
+
|
1413
|
+
it "should raise an Error unless same number of composite keys used" do
|
1414
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
1415
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
1416
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>[:node_id, :id], :left_primary_key=>:id}.should raise_error(Sequel::Error)
|
1417
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>:id, :left_primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
1418
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>[:node_id, :id, :x], :left_primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
1419
|
+
|
1420
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :right_primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
1421
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :right_key=>[:node_id, :id], :right_primary_key=>:id}.should raise_error(Sequel::Error)
|
1422
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :right_key=>:id, :left_primary_key=>[:node_id, :id]}.should raise_error(Sequel::Error)
|
1423
|
+
proc{@c2.many_to_many :attributes, :class => @c1, :right_key=>[:node_id, :id, :x], :right_primary_key=>[:parent_id, :id]}.should raise_error(Sequel::Error)
|
1424
|
+
end
|
1425
|
+
|
1326
1426
|
it "should support a select option" do
|
1327
1427
|
@c2.many_to_many :attributes, :class => @c1, :select => :blah
|
1328
1428
|
|
@@ -1434,6 +1534,26 @@ describe Sequel::Model, "many_to_many" do
|
|
1434
1534
|
'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (8, 5)'
|
1435
1535
|
].should(include(MODEL_DB.sqls.first))
|
1436
1536
|
end
|
1537
|
+
|
1538
|
+
it "should have the add_ method respect composite keys" do
|
1539
|
+
@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
|
+
n = @c2.load(:id => 1234, :x=>5)
|
1541
|
+
a = @c1.load(:id => 2345, :y=>8)
|
1542
|
+
a.should == n.add_attribute(a)
|
1543
|
+
m = /INSERT INTO attributes_nodes \((\w+), (\w+), (\w+), (\w+)\) VALUES \((\d+), (\d+), (\d+), (\d+)\)/.match(MODEL_DB.sqls.first)
|
1544
|
+
m.should_not == nil
|
1545
|
+
map = {'l1'=>1234, 'l2'=>5, 'r1'=>2345, 'r2'=>8}
|
1546
|
+
%w[l1 l2 r1 r2].each do |x|
|
1547
|
+
v = false
|
1548
|
+
4.times do |i| i += 1
|
1549
|
+
if m[i] == x
|
1550
|
+
m[i+4].should == map[x].to_s
|
1551
|
+
v = true
|
1552
|
+
end
|
1553
|
+
end
|
1554
|
+
v.should == true
|
1555
|
+
end
|
1556
|
+
end
|
1437
1557
|
|
1438
1558
|
it "should have the remove_ method respect the :left_primary_key and :right_primary_key options" do
|
1439
1559
|
@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
|
@@ -1443,6 +1563,14 @@ describe Sequel::Model, "many_to_many" do
|
|
1443
1563
|
a.should == n.remove_attribute(a)
|
1444
1564
|
MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 5) AND (attribute_id = 8))'
|
1445
1565
|
end
|
1566
|
+
|
1567
|
+
it "should have the remove_ method respect composite keys" do
|
1568
|
+
@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]
|
1569
|
+
n = @c2.load(:id => 1234, :x=>5)
|
1570
|
+
a = @c1.load(:id => 2345, :y=>8)
|
1571
|
+
a.should == n.remove_attribute(a)
|
1572
|
+
MODEL_DB.sqls.should == ["DELETE FROM attributes_nodes WHERE ((l1 = 1234) AND (l2 = 5) AND (r1 = 2345) AND (r2 = 8))"]
|
1573
|
+
end
|
1446
1574
|
|
1447
1575
|
it "should raise an error if the model object doesn't have a valid primary key" do
|
1448
1576
|
@c2.many_to_many :attributes, :class => @c1
|
@@ -1455,7 +1583,7 @@ describe Sequel::Model, "many_to_many" do
|
|
1455
1583
|
proc{a.remove_all_attributes}.should raise_error(Sequel::Error)
|
1456
1584
|
end
|
1457
1585
|
|
1458
|
-
it "should save the associated object first if passed a new model object" do
|
1586
|
+
it "should save the associated object first in add_ if passed a new model object" do
|
1459
1587
|
@c2.many_to_many :attributes, :class => @c1
|
1460
1588
|
n = @c1.new
|
1461
1589
|
a = @c2.load(:id=>123)
|
@@ -1464,6 +1592,32 @@ describe Sequel::Model, "many_to_many" do
|
|
1464
1592
|
n.new?.should == false
|
1465
1593
|
end
|
1466
1594
|
|
1595
|
+
it "should raise a ValidationFailed in add_ if the associated object is new and invalid" do
|
1596
|
+
@c2.many_to_many :attributes, :class => @c1
|
1597
|
+
n = @c1.new
|
1598
|
+
a = @c2.load(:id=>123)
|
1599
|
+
def n.valid?; false; end
|
1600
|
+
proc{a.add_attribute(n)}.should raise_error(Sequel::ValidationFailed)
|
1601
|
+
end
|
1602
|
+
|
1603
|
+
it "should raise an Error in add_ if the associated object is new and invalid and raise_on_save_failure is false" do
|
1604
|
+
@c2.many_to_many :attributes, :class => @c1
|
1605
|
+
n = @c1.new
|
1606
|
+
n.raise_on_save_failure = false
|
1607
|
+
a = @c2.load(:id=>123)
|
1608
|
+
def n.valid?; false; end
|
1609
|
+
proc{a.add_attribute(n)}.should raise_error(Sequel::Error)
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
it "should not attempt to validate the associated object in add_ if the :validate=>false option is used" do
|
1613
|
+
@c2.many_to_many :attributes, :class => @c1, :validate=>false
|
1614
|
+
n = @c1.new
|
1615
|
+
a = @c2.load(:id=>123)
|
1616
|
+
def n.valid?; false; end
|
1617
|
+
a.add_attribute(n)
|
1618
|
+
n.new?.should == false
|
1619
|
+
end
|
1620
|
+
|
1467
1621
|
it "should raise an error if trying to remove a model object that doesn't have a valid primary key" do
|
1468
1622
|
@c2.many_to_many :attributes, :class => @c1
|
1469
1623
|
n = @c1.new
|
@@ -1597,6 +1751,12 @@ describe Sequel::Model, "many_to_many" do
|
|
1597
1751
|
@c2.new(:id => 1234, :xxx=>5).remove_all_attributes
|
1598
1752
|
MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE (node_id = 5)'
|
1599
1753
|
end
|
1754
|
+
|
1755
|
+
it "should have the remove_all_ method respect composite keys" do
|
1756
|
+
@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>[:id, :x], :left_key=>[:l1, :l2]
|
1757
|
+
@c2.load(:id => 1234, :x=>5).remove_all_attributes
|
1758
|
+
MODEL_DB.sqls.should == ['DELETE FROM attributes_nodes WHERE ((l1 = 1234) AND (l2 = 5))']
|
1759
|
+
end
|
1600
1760
|
|
1601
1761
|
it "remove_all should set the cached instance variable to []" do
|
1602
1762
|
@c2.many_to_many :attributes, :class => @c1
|