sequel 4.31.0 → 4.32.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.
- 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
|