sequel 4.31.0 → 4.32.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/Rakefile +17 -15
- data/doc/association_basics.rdoc +7 -3
- data/doc/opening_databases.rdoc +7 -0
- data/doc/release_notes/4.32.0.txt +132 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +70 -26
- data/doc/testing.rdoc +1 -0
- data/lib/sequel/adapters/jdbc.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +3 -4
- data/lib/sequel/adapters/shared/mysql.rb +14 -1
- data/lib/sequel/adapters/shared/sqlite.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +2 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +2 -0
- data/lib/sequel/extensions/columns_introspection.rb +2 -0
- data/lib/sequel/extensions/connection_validator.rb +2 -0
- data/lib/sequel/extensions/constraint_validations.rb +2 -0
- data/lib/sequel/extensions/core_extensions.rb +1 -5
- data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -0
- data/lib/sequel/extensions/dataset_source_alias.rb +2 -0
- data/lib/sequel/extensions/date_arithmetic.rb +2 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +3 -1
- data/lib/sequel/extensions/error_sql.rb +2 -0
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/filter_having.rb +2 -0
- data/lib/sequel/extensions/from_block.rb +2 -0
- data/lib/sequel/extensions/graph_each.rb +2 -0
- data/lib/sequel/extensions/hash_aliases.rb +2 -0
- data/lib/sequel/extensions/inflector.rb +2 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -1
- data/lib/sequel/extensions/meta_def.rb +2 -0
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +2 -0
- data/lib/sequel/extensions/no_auto_literal_strings.rb +84 -0
- data/lib/sequel/extensions/null_dataset.rb +2 -0
- data/lib/sequel/extensions/pagination.rb +2 -0
- data/lib/sequel/extensions/pg_array.rb +2 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -4
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_inet.rb +2 -4
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -0
- data/lib/sequel/extensions/pg_interval.rb +2 -4
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +3 -0
- data/lib/sequel/extensions/pg_loose_count.rb +2 -0
- data/lib/sequel/extensions/pg_range.rb +2 -4
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -4
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -0
- data/lib/sequel/extensions/pretty_table.rb +2 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/query_literals.rb +7 -5
- data/lib/sequel/extensions/round_timestamps.rb +4 -3
- data/lib/sequel/extensions/schema_caching.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +2 -0
- data/lib/sequel/extensions/select_remove.rb +2 -0
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/server_block.rb +3 -0
- data/lib/sequel/extensions/set_overrides.rb +2 -0
- data/lib/sequel/extensions/split_array_nil.rb +2 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +2 -0
- data/lib/sequel/model/associations.rb +95 -55
- data/lib/sequel/plugins/association_pks.rb +58 -33
- data/lib/sequel/plugins/eager_each.rb +22 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +44 -3
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +34 -6
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/bin_spec.rb +2 -2
- data/spec/core/dataset_spec.rb +7 -0
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +24 -0
- data/spec/extensions/eager_each_spec.rb +25 -1
- data/spec/extensions/no_auto_literal_strings_spec.rb +65 -0
- data/spec/extensions/pg_range_spec.rb +1 -0
- data/spec/extensions/spec_helper.rb +5 -5
- data/spec/extensions/tactical_eager_loading_spec.rb +71 -17
- data/spec/integration/associations_test.rb +77 -62
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/plugin_test.rb +22 -0
- data/spec/integration/prepared_statement_test.rb +8 -8
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/association_reflection_spec.rb +30 -0
- data/spec/model/associations_spec.rb +177 -16
- metadata +6 -2
@@ -1090,9 +1090,9 @@ describe "Sequel::Dataset main SQL methods" do
|
|
1090
1090
|
|
1091
1091
|
it "#filter and #exclude should work with placeholder strings" do
|
1092
1092
|
@ds.insert(20, 30)
|
1093
|
-
@ds.filter("a > ?", 15).all.must_equal [{:a=>20, :b=>30}]
|
1094
|
-
@ds.exclude("b < ?", 15).all.must_equal [{:a=>20, :b=>30}]
|
1095
|
-
@ds.filter("b < ?", 15).invert.all.must_equal [{:a=>20, :b=>30}]
|
1093
|
+
@ds.filter(Sequel.lit("a > ?", 15)).all.must_equal [{:a=>20, :b=>30}]
|
1094
|
+
@ds.exclude(Sequel.lit("b < ?", 15)).all.must_equal [{:a=>20, :b=>30}]
|
1095
|
+
@ds.filter(Sequel.lit("b < ?", 15)).invert.all.must_equal [{:a=>20, :b=>30}]
|
1096
1096
|
end
|
1097
1097
|
|
1098
1098
|
it "#and and #or should work correctly" do
|
@@ -1302,6 +1302,11 @@ describe "AssociationPks plugin" do
|
|
1302
1302
|
album.tag_pks.must_equal [@t1, @t2]
|
1303
1303
|
album.save
|
1304
1304
|
album_class.with_pk!(album.pk).tag_pks.sort.must_equal [@t1, @t2]
|
1305
|
+
|
1306
|
+
album.tag_pks = []
|
1307
|
+
album.tag_pks.must_equal []
|
1308
|
+
album.save
|
1309
|
+
album_class.with_pk!(album.pk).tag_pks.sort.must_equal []
|
1305
1310
|
end
|
1306
1311
|
|
1307
1312
|
it "should handle :delay=>:all association option for existing instances" do
|
@@ -1313,6 +1318,11 @@ describe "AssociationPks plugin" do
|
|
1313
1318
|
album.tag_pks.must_equal [@t1, @t2]
|
1314
1319
|
album.save_changes
|
1315
1320
|
album_class.with_pk!(album.pk).tag_pks.sort.must_equal [@t1, @t2]
|
1321
|
+
|
1322
|
+
album.tag_pks = []
|
1323
|
+
album.tag_pks.must_equal []
|
1324
|
+
album.save_changes
|
1325
|
+
album_class.with_pk!(album.pk).tag_pks.sort.must_equal []
|
1316
1326
|
end
|
1317
1327
|
|
1318
1328
|
it "should set associated pks correctly for a one_to_many association" do
|
@@ -1330,6 +1340,9 @@ describe "AssociationPks plugin" do
|
|
1330
1340
|
Artist[@ar1].album_pks = [@al1, @al2]
|
1331
1341
|
Artist[@ar2].album_pks.must_equal [@al3]
|
1332
1342
|
Album.order(:id).select_map(:artist_id).must_equal [@ar1, @ar1, @ar2]
|
1343
|
+
|
1344
|
+
Artist[@ar1].album_pks = []
|
1345
|
+
Album.order(:id).select_map(:artist_id).must_equal [nil, nil, @ar2]
|
1333
1346
|
end
|
1334
1347
|
|
1335
1348
|
it "should set associated pks correctly for a many_to_many association" do
|
@@ -1369,6 +1382,9 @@ describe "AssociationPks plugin" do
|
|
1369
1382
|
Album[@al1].vocalist_pks = [@v1, @v2]
|
1370
1383
|
Album[@al2].vocalist_pks.must_equal [@v3]
|
1371
1384
|
Vocalist.order(:first, :last).select_map(:album_id).must_equal [@al1, @al1, @al2]
|
1385
|
+
|
1386
|
+
Album[@al1].vocalist_pks = []
|
1387
|
+
Vocalist.order(:first, :last).select_map(:album_id).must_equal [nil, nil, @al2]
|
1372
1388
|
end
|
1373
1389
|
|
1374
1390
|
it "should set associated right-side cpks correctly for a many_to_many association" do
|
@@ -1410,6 +1426,9 @@ describe "AssociationPks plugin" do
|
|
1410
1426
|
Vocalist[@v1].instrument_pks = [@i1, @i2]
|
1411
1427
|
Vocalist[@v2].instrument_pks.must_equal [@i3]
|
1412
1428
|
Instrument.order(:id).select_map([:first, :last]).must_equal [@v1, @v1, @v2]
|
1429
|
+
|
1430
|
+
Vocalist[@v1].instrument_pks = []
|
1431
|
+
Instrument.order(:id).select_map([:first, :last]).must_equal [[nil, nil], [nil, nil], @v2]
|
1413
1432
|
end
|
1414
1433
|
|
1415
1434
|
it "should set associated pks correctly with left-side cpks for a many_to_many association" do
|
@@ -1451,6 +1470,9 @@ describe "AssociationPks plugin" do
|
|
1451
1470
|
Vocalist[@v1].hit_pks = [@h1, @h2]
|
1452
1471
|
Vocalist[@v2].hit_pks.must_equal [@h3]
|
1453
1472
|
Hit.order(:year, :week).select_map([:first, :last]).must_equal [@v1, @v1, @v2]
|
1473
|
+
|
1474
|
+
Vocalist[@v1].hit_pks = []
|
1475
|
+
Hit.order(:year, :week).select_map([:first, :last]).must_equal [[nil, nil], [nil, nil], @v2]
|
1454
1476
|
end
|
1455
1477
|
|
1456
1478
|
it "should set associated right-side cpks correctly with left-side cpks for a many_to_many association" do
|
@@ -55,14 +55,14 @@ describe "Prepared Statements and Bound Arguments" do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it "should support placeholder literal strings with call" do
|
58
|
-
@ds.filter("numb = ?", :$n).call(:select, :n=>10).must_equal [{:id=>1, :numb=>10}]
|
58
|
+
@ds.filter(Sequel.lit("numb = ?", :$n)).call(:select, :n=>10).must_equal [{:id=>1, :numb=>10}]
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should support named placeholder literal strings and handle multiple named placeholders correctly with call" do
|
62
|
-
@ds.filter("numb = :n", :n=>:$n).call(:select, :n=>10).must_equal [{:id=>1, :numb=>10}]
|
62
|
+
@ds.filter(Sequel.lit("numb = :n", :n=>:$n)).call(:select, :n=>10).must_equal [{:id=>1, :numb=>10}]
|
63
63
|
@ds.insert(:numb=>20)
|
64
64
|
@ds.insert(:numb=>30)
|
65
|
-
@ds.filter("numb > :n1 AND numb < :n2 AND numb = :n3", :n3=>:$n3, :n2=>:$n2, :n1=>:$n1).call(:select, :n3=>20, :n2=>30, :n1=>10).must_equal [{:id=>2, :numb=>20}]
|
65
|
+
@ds.filter(Sequel.lit("numb > :n1 AND numb < :n2 AND numb = :n3", :n3=>:$n3, :n2=>:$n2, :n1=>:$n1)).call(:select, :n3=>20, :n2=>30, :n1=>10).must_equal [{:id=>2, :numb=>20}]
|
66
66
|
end
|
67
67
|
|
68
68
|
it "should support datasets with static sql and placeholders with call" do
|
@@ -78,7 +78,7 @@ describe "Prepared Statements and Bound Arguments" do
|
|
78
78
|
end
|
79
79
|
|
80
80
|
it "should support subselects with literal strings with call" do
|
81
|
-
@ds.filter(:id=>:$i, :numb=>@ds.select(:numb).filter("numb = ?", :$n)).call(:select, :n=>10, :i=>1).must_equal [{:id=>1, :numb=>10}]
|
81
|
+
@ds.filter(:id=>:$i, :numb=>@ds.select(:numb).filter(Sequel.lit("numb = ?", :$n))).call(:select, :n=>10, :i=>1).must_equal [{:id=>1, :numb=>10}]
|
82
82
|
end
|
83
83
|
|
84
84
|
it "should support subselects with static sql and placeholders with call" do
|
@@ -186,14 +186,14 @@ describe "Prepared Statements and Bound Arguments" do
|
|
186
186
|
end
|
187
187
|
|
188
188
|
it "should support placeholder literal strings with prepare" do
|
189
|
-
@ds.filter("numb = ?", :$n).prepare(:select, :seq_select).call(:n=>10).must_equal [{:id=>1, :numb=>10}]
|
189
|
+
@ds.filter(Sequel.lit("numb = ?", :$n)).prepare(:select, :seq_select).call(:n=>10).must_equal [{:id=>1, :numb=>10}]
|
190
190
|
end
|
191
191
|
|
192
192
|
it "should support named placeholder literal strings and handle multiple named placeholders correctly with prepare" do
|
193
|
-
@ds.filter("numb = :n", :n=>:$n).prepare(:select, :seq_select).call(:n=>10).must_equal [{:id=>1, :numb=>10}]
|
193
|
+
@ds.filter(Sequel.lit("numb = :n", :n=>:$n)).prepare(:select, :seq_select).call(:n=>10).must_equal [{:id=>1, :numb=>10}]
|
194
194
|
@ds.insert(:numb=>20)
|
195
195
|
@ds.insert(:numb=>30)
|
196
|
-
@ds.filter("numb > :n1 AND numb < :n2 AND numb = :n3", :n3=>:$n3, :n2=>:$n2, :n1=>:$n1).call(:select, :n3=>20, :n2=>30, :n1=>10).must_equal [{:id=>2, :numb=>20}]
|
196
|
+
@ds.filter(Sequel.lit("numb > :n1 AND numb < :n2 AND numb = :n3", :n3=>:$n3, :n2=>:$n2, :n1=>:$n1)).call(:select, :n3=>20, :n2=>30, :n1=>10).must_equal [{:id=>2, :numb=>20}]
|
197
197
|
end
|
198
198
|
|
199
199
|
it "should support datasets with static sql and placeholders with prepare" do
|
@@ -209,7 +209,7 @@ describe "Prepared Statements and Bound Arguments" do
|
|
209
209
|
end
|
210
210
|
|
211
211
|
it "should support subselects with literal strings with prepare" do
|
212
|
-
@ds.filter(:id=>:$i, :numb=>@ds.select(:numb).filter("numb = ?", :$n)).prepare(:select, :seq_select).call(:n=>10, :i=>1).must_equal [{:id=>1, :numb=>10}]
|
212
|
+
@ds.filter(:id=>:$i, :numb=>@ds.select(:numb).filter(Sequel.lit("numb = ?", :$n))).prepare(:select, :seq_select).call(:n=>10, :i=>1).must_equal [{:id=>1, :numb=>10}]
|
213
213
|
end
|
214
214
|
|
215
215
|
it "should support subselects with static sql and placeholders with prepare" do
|
@@ -36,6 +36,10 @@ if DB.adapter_scheme == :ibmdb || (DB.adapter_scheme == :ado && DB.database_type
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
if ENV['SEQUEL_NO_AUTO_LITERAL_STRINGS']
|
40
|
+
DB.extension :no_auto_literal_strings
|
41
|
+
end
|
42
|
+
|
39
43
|
if ENV['SEQUEL_ERROR_SQL']
|
40
44
|
DB.extension :error_sql
|
41
45
|
end
|
@@ -523,3 +523,33 @@ describe Sequel::Model::Associations::AssociationReflection, "with caching disab
|
|
523
523
|
end
|
524
524
|
end
|
525
525
|
|
526
|
+
describe Sequel::Model::Associations::AssociationReflection, "with default association options" do
|
527
|
+
before do
|
528
|
+
@db = Sequel.mock
|
529
|
+
@c = Class.new(Sequel::Model)
|
530
|
+
@c.dataset = @db[:foo]
|
531
|
+
end
|
532
|
+
|
533
|
+
it "should use default_association_options as defaults" do
|
534
|
+
@c.default_association_options = {:foo=>1, :bar=>2}
|
535
|
+
@c.many_to_one :c, :class=>@c, :foo=>3
|
536
|
+
r = @c.association_reflection(:c)
|
537
|
+
r[:foo].must_equal 3
|
538
|
+
r[:bar].must_equal 2
|
539
|
+
end
|
540
|
+
|
541
|
+
it "should inherit default_association_options" do
|
542
|
+
@c.default_association_options = {:foo=>1, :bar=>2}
|
543
|
+
c = Class.new(@c)
|
544
|
+
c.many_to_one :c, :class=>c, :foo=>3
|
545
|
+
r = c.association_reflection(:c)
|
546
|
+
r[:foo].must_equal 3
|
547
|
+
r[:bar].must_equal 2
|
548
|
+
|
549
|
+
@c.default_association_options[:bar] = 4
|
550
|
+
c.many_to_one :d, :class=>c, :foo=>3
|
551
|
+
r = c.association_reflection(:d)
|
552
|
+
r[:foo].must_equal 3
|
553
|
+
r[:bar].must_equal 2
|
554
|
+
end
|
555
|
+
end
|
@@ -448,6 +448,8 @@ describe Sequel::Model, "many_to_one" do
|
|
448
448
|
d.associations[:parent] = 42
|
449
449
|
d.parent(true).wont_equal 42
|
450
450
|
DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 234"]
|
451
|
+
d.parent(:reload=>true).wont_equal 42
|
452
|
+
DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 234"]
|
451
453
|
end
|
452
454
|
|
453
455
|
it "should use a callback if given one as the argument" do
|
@@ -728,7 +730,7 @@ describe Sequel::Model, "one_to_one" do
|
|
728
730
|
DB.reset
|
729
731
|
end
|
730
732
|
|
731
|
-
it "should have the getter method return a single object
|
733
|
+
it "should have the getter method return a single object" do
|
732
734
|
@c2.one_to_one :attribute, :class => @c1
|
733
735
|
att = @c2.new(:id => 1234).attribute
|
734
736
|
DB.sqls.must_equal ['SELECT * FROM attributes WHERE (attributes.node_id = 1234) LIMIT 1']
|
@@ -1122,21 +1124,6 @@ describe Sequel::Model, "one_to_one" do
|
|
1122
1124
|
proc{p.parent = nil}.must_raise(Sequel::HookFailed)
|
1123
1125
|
end
|
1124
1126
|
|
1125
|
-
it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
|
1126
|
-
p = @c2.load(:id=>321)
|
1127
|
-
c = @c2.load(:id=>123)
|
1128
|
-
p.raise_on_save_failure = false
|
1129
|
-
@c2.one_to_one :parent, :class => @c2, :before_set=>:bs
|
1130
|
-
def p.bs(x) cancel_action end
|
1131
|
-
def p._parent=; raise; end
|
1132
|
-
proc{p.parent = c}.must_raise(Sequel::HookFailed)
|
1133
|
-
|
1134
|
-
p.associations[:parent].must_equal nil
|
1135
|
-
p.associations[:parent] = c
|
1136
|
-
p.parent.must_equal c
|
1137
|
-
proc{p.parent = nil}.must_raise(Sequel::HookFailed)
|
1138
|
-
end
|
1139
|
-
|
1140
1127
|
it "should not validate the associated object in setter if the :validate=>false option is used" do
|
1141
1128
|
@c2.one_to_one :parent, :class => @c2, :validate=>false
|
1142
1129
|
n = @c2.new(:id => 1234)
|
@@ -2814,6 +2801,9 @@ describe Sequel::Model, "one_through_one" do
|
|
2814
2801
|
[@c1, @c2].each{|c| c.dataset._fetch = {}}
|
2815
2802
|
DB.reset
|
2816
2803
|
end
|
2804
|
+
after do
|
2805
|
+
DB.fetch = {:id => 1, :x => 1}
|
2806
|
+
end
|
2817
2807
|
|
2818
2808
|
it "should use implicit key values and join table if omitted" do
|
2819
2809
|
@c2.one_through_one :attribute, :class => @c1
|
@@ -3021,6 +3011,177 @@ describe Sequel::Model, "one_through_one" do
|
|
3021
3011
|
@c2.one_through_one :attribute, :class => @c1, :distinct=>true
|
3022
3012
|
@c2.load(:id=>10).attribute_dataset.sql.must_equal "SELECT DISTINCT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 10) LIMIT 1"
|
3023
3013
|
end
|
3014
|
+
|
3015
|
+
it "should not add a setter method if the :read_only option is true" do
|
3016
|
+
@c2.one_through_one :attribute, :class => @c1, :read_only=>true
|
3017
|
+
im = @c2.instance_methods.collect{|x| x.to_s}
|
3018
|
+
im.must_include('attribute')
|
3019
|
+
im.wont_include('attribute=')
|
3020
|
+
end
|
3021
|
+
|
3022
|
+
it "should add a setter method" do
|
3023
|
+
@c2.one_through_one :attribute, :class => @c1
|
3024
|
+
attrib = @c1.new(:id=>3)
|
3025
|
+
DB.fetch = []
|
3026
|
+
o = @c2.load(:id => 1234)
|
3027
|
+
o.attribute = nil
|
3028
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 1234) LIMIT 1"]
|
3029
|
+
|
3030
|
+
o.attribute = attrib
|
3031
|
+
sqls = DB.sqls
|
3032
|
+
["INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (3, 1234)",
|
3033
|
+
"INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 3)"].must_include(sqls.slice! 1)
|
3034
|
+
sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 1234) LIMIT 1"]
|
3035
|
+
|
3036
|
+
DB.fetch = {:node_id=>1234, :attribute_id=>5}
|
3037
|
+
o.attribute = nil
|
3038
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 1234) LIMIT 1",
|
3039
|
+
"DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 5))"]
|
3040
|
+
|
3041
|
+
o.attribute = attrib
|
3042
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 1234) LIMIT 1",
|
3043
|
+
"UPDATE attributes_nodes SET attribute_id = 3 WHERE ((node_id = 1234) AND (attribute_id = 5))"]
|
3044
|
+
|
3045
|
+
@c2.load(:id => 1234).attribute = @c1.new(:id=>5)
|
3046
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 1234) LIMIT 1"]
|
3047
|
+
end
|
3048
|
+
|
3049
|
+
it "should use a transaction in the setter method" do
|
3050
|
+
@c2.one_through_one :attribute, :class => @c1
|
3051
|
+
@c2.use_transactions = true
|
3052
|
+
attrib = @c1.load(:id=>3)
|
3053
|
+
DB.fetch = []
|
3054
|
+
@c2.new(:id => 1234).attribute = nil
|
3055
|
+
DB.sqls.must_equal ['BEGIN',
|
3056
|
+
"SELECT * FROM attributes_nodes WHERE (node_id = 1234) LIMIT 1",
|
3057
|
+
'COMMIT']
|
3058
|
+
end
|
3059
|
+
|
3060
|
+
it "should have setter method respect :join_table_block option" do
|
3061
|
+
@c2.one_through_one :attribute, :class => @c1, :join_table_block=>proc{|ds| ds.where(:a)}
|
3062
|
+
attrib = @c1.new(:id=>3)
|
3063
|
+
DB.fetch = []
|
3064
|
+
o = @c2.new(:id => 1234)
|
3065
|
+
o.attribute = nil
|
3066
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (a AND (node_id = 1234)) LIMIT 1"]
|
3067
|
+
|
3068
|
+
o.attribute = attrib
|
3069
|
+
sqls = DB.sqls
|
3070
|
+
["INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (3, 1234)",
|
3071
|
+
"INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 3)"].must_include(sqls.slice! 1)
|
3072
|
+
sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (a AND (node_id = 1234)) LIMIT 1"]
|
3073
|
+
|
3074
|
+
DB.fetch = {:node_id=>1234, :attribute_id=>5}
|
3075
|
+
o.attribute = nil
|
3076
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (a AND (node_id = 1234)) LIMIT 1",
|
3077
|
+
"DELETE FROM attributes_nodes WHERE (a AND (node_id = 1234) AND (attribute_id = 5))"]
|
3078
|
+
|
3079
|
+
o.attribute = attrib
|
3080
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (a AND (node_id = 1234)) LIMIT 1",
|
3081
|
+
"UPDATE attributes_nodes SET attribute_id = 3 WHERE (a AND (node_id = 1234) AND (attribute_id = 5))"]
|
3082
|
+
end
|
3083
|
+
|
3084
|
+
it "should have the setter method respect the :left_primary_key and :right_primary_key option" do
|
3085
|
+
@c2.one_through_one :attribute, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
|
3086
|
+
attrib = @c1.new(:id=>3, :yyy=>7)
|
3087
|
+
DB.fetch = []
|
3088
|
+
o = @c2.new(:id => 1234, :xxx=>5)
|
3089
|
+
o.attribute = nil
|
3090
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 5) LIMIT 1"]
|
3091
|
+
|
3092
|
+
o.attribute = attrib
|
3093
|
+
sqls = DB.sqls
|
3094
|
+
["INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (7, 5)",
|
3095
|
+
"INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (5, 7)"].must_include(sqls.slice! 1)
|
3096
|
+
sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 5) LIMIT 1"]
|
3097
|
+
|
3098
|
+
DB.fetch = {:node_id=>1234, :attribute_id=>9}
|
3099
|
+
o.attribute = nil
|
3100
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 5) LIMIT 1",
|
3101
|
+
"DELETE FROM attributes_nodes WHERE ((node_id = 5) AND (attribute_id = 9))"]
|
3102
|
+
|
3103
|
+
o.attribute = attrib
|
3104
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE (node_id = 5) LIMIT 1",
|
3105
|
+
"UPDATE attributes_nodes SET attribute_id = 7 WHERE ((node_id = 5) AND (attribute_id = 9))"]
|
3106
|
+
end
|
3107
|
+
|
3108
|
+
it "should have the setter method respect composite keys" do
|
3109
|
+
@c2.one_through_one :attribute, :class => @c1, :left_key=>[:node_id, :y], :left_primary_key=>[:id, :x], :right_key=>[:attribute_id, :z], :right_primary_key=>[:id, :w]
|
3110
|
+
attrib = @c1.load(:id=>3, :w=>7)
|
3111
|
+
@c1.def_column_alias :w, :w
|
3112
|
+
DB.fetch = []
|
3113
|
+
o = @c2.new(:id => 1234, :x=>5)
|
3114
|
+
o.attribute = nil
|
3115
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE ((node_id = 1234) AND (y = 5)) LIMIT 1"]
|
3116
|
+
|
3117
|
+
o.attribute = attrib
|
3118
|
+
sqls = DB.sqls
|
3119
|
+
sqls.slice!(1).must_match(/\AINSERT INTO attributes_nodes \((attribute_id|z|node_id|y), (attribute_id|z|node_id|y), (attribute_id|z|node_id|y), (attribute_id|z|node_id|y)\) VALUES \((3|7|1234|5), (3|7|1234|5), (3|7|1234|5), (3|7|1234|5)\)\z/)
|
3120
|
+
sqls.must_equal ["SELECT * FROM attributes_nodes WHERE ((node_id = 1234) AND (y = 5)) LIMIT 1"]
|
3121
|
+
|
3122
|
+
DB.fetch = {:node_id=>1234, :attribute_id=>10, :y=>6, :z=>8}
|
3123
|
+
o.attribute = nil
|
3124
|
+
DB.sqls.must_equal ["SELECT * FROM attributes_nodes WHERE ((node_id = 1234) AND (y = 5)) LIMIT 1",
|
3125
|
+
"DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (y = 5) AND (attribute_id = 10) AND (z = 8))"]
|
3126
|
+
|
3127
|
+
o.attribute = attrib
|
3128
|
+
sqls = DB.sqls
|
3129
|
+
["UPDATE attributes_nodes SET attribute_id = 3, z = 7 WHERE ((node_id = 1234) AND (y = 5) AND (attribute_id = 10) AND (z = 8))",
|
3130
|
+
"UPDATE attributes_nodes SET z = 7, attribute_id = 3 WHERE ((node_id = 1234) AND (y = 5) AND (attribute_id = 10) AND (z = 8))"].must_include(sqls.slice!(1))
|
3131
|
+
sqls.must_equal ["SELECT * FROM attributes_nodes WHERE ((node_id = 1234) AND (y = 5)) LIMIT 1"]
|
3132
|
+
end
|
3133
|
+
|
3134
|
+
it "should raise an error if the current model object that doesn't have a valid primary key" do
|
3135
|
+
@c2.one_through_one :attribute, :class => @c1
|
3136
|
+
p = @c2.new
|
3137
|
+
c = @c2.load(:id=>123)
|
3138
|
+
proc{c.attribute = p}.must_raise(Sequel::Error)
|
3139
|
+
end
|
3140
|
+
|
3141
|
+
it "should raise an error if the associated object that doesn't have a valid primary key" do
|
3142
|
+
@c2.one_through_one :attribute, :class => @c1
|
3143
|
+
p = @c2.new
|
3144
|
+
c = @c2.load(:id=>123)
|
3145
|
+
proc{p.attribute = c}.must_raise(Sequel::Error)
|
3146
|
+
end
|
3147
|
+
|
3148
|
+
it "should make the change to the foreign_key value inside a _association= method" do
|
3149
|
+
@c2.one_through_one :attribute, :class => @c1
|
3150
|
+
@c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_attribute=")
|
3151
|
+
attrib = @c1.new(:id=>3)
|
3152
|
+
o = @c2.new(:id => 1234)
|
3153
|
+
def o._attribute=(x)
|
3154
|
+
@x = x
|
3155
|
+
end
|
3156
|
+
o.attribute = attrib
|
3157
|
+
o.instance_variable_get(:@x).must_equal attrib
|
3158
|
+
end
|
3159
|
+
|
3160
|
+
it "should have a :setter option define the _association= method" do
|
3161
|
+
@c2.one_through_one :attribute, :class => @c1, :setter=>proc{|x| @x = x}
|
3162
|
+
attrib = @c1.new(:id=>3)
|
3163
|
+
o = @c2.new(:id => 1234)
|
3164
|
+
o.attribute = attrib
|
3165
|
+
o.instance_variable_get(:@x).must_equal attrib
|
3166
|
+
end
|
3167
|
+
|
3168
|
+
it "should support (before|after)_set callbacks" do
|
3169
|
+
h = []
|
3170
|
+
@c2.one_through_one :attribute, :class => @c1, :before_set=>[proc{|x,y| h << x.pk; h << (y ? -y.pk : :y)}, :blah], :after_set=>proc{h << :l}
|
3171
|
+
@c2.class_eval do
|
3172
|
+
self::Foo = h
|
3173
|
+
def blah(x)
|
3174
|
+
model::Foo << (x ? x.pk : :x)
|
3175
|
+
end
|
3176
|
+
end
|
3177
|
+
attrib = @c1.new(:id=>3)
|
3178
|
+
o = @c2.new(:id => 1234)
|
3179
|
+
h.must_equal []
|
3180
|
+
o.attribute = attrib
|
3181
|
+
h.must_equal [1234, -3, 3, :l]
|
3182
|
+
o.attribute = nil
|
3183
|
+
h.must_equal [1234, -3, 3, :l, 1234, :y, :x, :l]
|
3184
|
+
end
|
3024
3185
|
end
|
3025
3186
|
|
3026
3187
|
describe "Filtering by associations" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.32.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -232,6 +232,7 @@ extra_rdoc_files:
|
|
232
232
|
- doc/release_notes/4.29.0.txt
|
233
233
|
- doc/release_notes/4.30.0.txt
|
234
234
|
- doc/release_notes/4.31.0.txt
|
235
|
+
- doc/release_notes/4.32.0.txt
|
235
236
|
files:
|
236
237
|
- CHANGELOG
|
237
238
|
- MIT-LICENSE
|
@@ -352,6 +353,7 @@ files:
|
|
352
353
|
- doc/release_notes/4.3.0.txt
|
353
354
|
- doc/release_notes/4.30.0.txt
|
354
355
|
- doc/release_notes/4.31.0.txt
|
356
|
+
- doc/release_notes/4.32.0.txt
|
355
357
|
- doc/release_notes/4.4.0.txt
|
356
358
|
- doc/release_notes/4.5.0.txt
|
357
359
|
- doc/release_notes/4.6.0.txt
|
@@ -488,6 +490,7 @@ files:
|
|
488
490
|
- lib/sequel/extensions/migration.rb
|
489
491
|
- lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb
|
490
492
|
- lib/sequel/extensions/named_timezones.rb
|
493
|
+
- lib/sequel/extensions/no_auto_literal_strings.rb
|
491
494
|
- lib/sequel/extensions/null_dataset.rb
|
492
495
|
- lib/sequel/extensions/pagination.rb
|
493
496
|
- lib/sequel/extensions/pg_array.rb
|
@@ -697,6 +700,7 @@ files:
|
|
697
700
|
- spec/extensions/mssql_optimistic_locking_spec.rb
|
698
701
|
- spec/extensions/named_timezones_spec.rb
|
699
702
|
- spec/extensions/nested_attributes_spec.rb
|
703
|
+
- spec/extensions/no_auto_literal_strings_spec.rb
|
700
704
|
- spec/extensions/null_dataset_spec.rb
|
701
705
|
- spec/extensions/optimistic_locking_spec.rb
|
702
706
|
- spec/extensions/pagination_spec.rb
|