sequel 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +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
|