sequel 5.19.0 → 5.24.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 +102 -0
- data/doc/dataset_filtering.rdoc +15 -0
- data/doc/opening_databases.rdoc +5 -1
- data/doc/release_notes/5.20.0.txt +89 -0
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/release_notes/5.22.0.txt +48 -0
- data/doc/release_notes/5.23.0.txt +56 -0
- data/doc/release_notes/5.24.0.txt +56 -0
- data/doc/sharding.rdoc +2 -0
- data/doc/testing.rdoc +1 -0
- data/doc/transactions.rdoc +38 -0
- data/lib/sequel/adapters/ado.rb +27 -19
- data/lib/sequel/adapters/jdbc.rb +7 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +29 -0
- data/lib/sequel/adapters/mysql2.rb +2 -3
- data/lib/sequel/adapters/shared/mssql.rb +7 -7
- data/lib/sequel/adapters/shared/postgres.rb +37 -19
- data/lib/sequel/adapters/shared/sqlite.rb +27 -3
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +12 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -0
- data/lib/sequel/database/logging.rb +7 -1
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +12 -3
- data/lib/sequel/database/schema_methods.rb +2 -0
- data/lib/sequel/database/transactions.rb +57 -5
- data/lib/sequel/dataset.rb +4 -2
- data/lib/sequel/dataset/actions.rb +3 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +4 -1
- data/lib/sequel/dataset/query.rb +5 -1
- data/lib/sequel/dataset/sql.rb +11 -7
- data/lib/sequel/extensions/named_timezones.rb +52 -8
- data/lib/sequel/extensions/pg_array.rb +4 -0
- data/lib/sequel/extensions/pg_json.rb +387 -123
- data/lib/sequel/extensions/pg_range.rb +3 -2
- data/lib/sequel/extensions/pg_row.rb +3 -1
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/extensions/server_block.rb +15 -4
- data/lib/sequel/model/associations.rb +35 -9
- data/lib/sequel/model/plugins.rb +104 -0
- data/lib/sequel/plugins/association_dependencies.rb +3 -3
- data/lib/sequel/plugins/association_pks.rb +14 -4
- data/lib/sequel/plugins/association_proxies.rb +3 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -0
- data/lib/sequel/plugins/composition.rb +13 -9
- data/lib/sequel/plugins/finder.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +17 -5
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/inverted_subsets.rb +2 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +147 -59
- data/lib/sequel/plugins/rcte_tree.rb +6 -0
- data/lib/sequel/plugins/static_cache.rb +8 -3
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/subset_conditions.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +5 -3
- data/lib/sequel/sql.rb +15 -3
- data/lib/sequel/timezones.rb +50 -11
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +24 -0
- data/spec/adapters/mysql_spec.rb +0 -5
- data/spec/adapters/postgres_spec.rb +319 -1
- data/spec/bin_spec.rb +1 -1
- data/spec/core/database_spec.rb +123 -2
- data/spec/core/dataset_spec.rb +33 -1
- data/spec/core/expression_filters_spec.rb +25 -1
- data/spec/core/schema_spec.rb +24 -0
- data/spec/extensions/class_table_inheritance_spec.rb +30 -8
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/hook_class_methods_spec.rb +22 -0
- data/spec/extensions/insert_conflict_spec.rb +103 -0
- data/spec/extensions/migration_spec.rb +13 -0
- data/spec/extensions/named_timezones_spec.rb +109 -2
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +45 -0
- data/spec/extensions/pg_json_spec.rb +218 -29
- data/spec/extensions/pg_range_spec.rb +76 -9
- data/spec/extensions/rcte_tree_spec.rb +6 -0
- data/spec/extensions/s_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +4 -2
- data/spec/extensions/server_block_spec.rb +38 -0
- data/spec/extensions/spec_helper.rb +8 -1
- data/spec/extensions/static_cache_cache_spec.rb +35 -0
- data/spec/integration/dataset_test.rb +25 -9
- data/spec/integration/plugin_test.rb +42 -0
- data/spec/integration/schema_test.rb +7 -2
- data/spec/integration/transaction_test.rb +50 -0
- data/spec/model/associations_spec.rb +84 -4
- data/spec/model/plugins_spec.rb +111 -0
- metadata +16 -2
|
@@ -17,6 +17,7 @@ describe "pg_range extension" do
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
endless_range_support = RUBY_VERSION >= '2.6'
|
|
20
|
+
startless_range_support = RUBY_VERSION >= '2.7'
|
|
20
21
|
|
|
21
22
|
it "should set up conversion procs correctly" do
|
|
22
23
|
cp = @db.conversion_procs
|
|
@@ -52,8 +53,19 @@ describe "pg_range extension" do
|
|
|
52
53
|
|
|
53
54
|
it "should literalize endless Range instances to strings correctly" do
|
|
54
55
|
@db.literal(eval('1..')).must_equal "'[1,]'"
|
|
56
|
+
@db.literal(eval('1...')).must_equal "'[1,)'"
|
|
55
57
|
end if endless_range_support
|
|
56
58
|
|
|
59
|
+
it "should literalize startless Range instances to strings correctly" do
|
|
60
|
+
@db.literal(eval('..1')).must_equal "'[,1]'"
|
|
61
|
+
@db.literal(eval('...1')).must_equal "'[,1)'"
|
|
62
|
+
end if startless_range_support
|
|
63
|
+
|
|
64
|
+
it "should literalize startless, endless Range instances to strings correctly" do
|
|
65
|
+
@db.literal(eval('nil..nil')).must_equal "'[,]'"
|
|
66
|
+
@db.literal(eval('nil...nil')).must_equal "'[,)'"
|
|
67
|
+
end if startless_range_support
|
|
68
|
+
|
|
57
69
|
it "should literalize PGRange instances to strings correctly" do
|
|
58
70
|
@db.literal(@R.new(1, 2)).must_equal "'[1,2]'"
|
|
59
71
|
@db.literal(@R.new(true, false)).must_equal "'[true,false]'"
|
|
@@ -79,8 +91,19 @@ describe "pg_range extension" do
|
|
|
79
91
|
|
|
80
92
|
it "should support using endless Range instances as bound variables" do
|
|
81
93
|
@db.bound_variable_arg(eval('1..'), nil).must_equal "[1,]"
|
|
94
|
+
@db.bound_variable_arg(eval('1...'), nil).must_equal "[1,)"
|
|
82
95
|
end if endless_range_support
|
|
83
96
|
|
|
97
|
+
it "should support using startless Range instances as bound variables" do
|
|
98
|
+
@db.bound_variable_arg(eval('..1'), nil).must_equal "[,1]"
|
|
99
|
+
@db.bound_variable_arg(eval('...1'), nil).must_equal "[,1)"
|
|
100
|
+
end if startless_range_support
|
|
101
|
+
|
|
102
|
+
it "should support using startless, endless Range instances as bound variables" do
|
|
103
|
+
@db.bound_variable_arg(eval('nil..nil'), nil).must_equal "[,]"
|
|
104
|
+
@db.bound_variable_arg(eval('nil...nil'), nil).must_equal "[,)"
|
|
105
|
+
end if startless_range_support
|
|
106
|
+
|
|
84
107
|
it "should support using PGRange instances as bound variables" do
|
|
85
108
|
@db.bound_variable_arg(@R.new(1, 2), nil).must_equal "[1,2]"
|
|
86
109
|
end
|
|
@@ -406,12 +429,12 @@ describe "pg_range extension" do
|
|
|
406
429
|
@R.new(nil, nil).wont_equal @R.new(nil, nil, :empty=>true)
|
|
407
430
|
end
|
|
408
431
|
|
|
409
|
-
it "should only consider
|
|
432
|
+
it "should only consider PGRanges equal if they have the same bounds" do
|
|
410
433
|
@R.new(1, 2).must_equal @R.new(1, 2)
|
|
411
434
|
@R.new(1, 2).wont_equal @R.new(1, 3)
|
|
412
435
|
end
|
|
413
436
|
|
|
414
|
-
it "should only consider
|
|
437
|
+
it "should only consider PGRanges equal if they have the same bound exclusions" do
|
|
415
438
|
@R.new(1, 2, :exclude_begin=>true).must_equal @R.new(1, 2, :exclude_begin=>true)
|
|
416
439
|
@R.new(1, 2, :exclude_end=>true).must_equal @R.new(1, 2, :exclude_end=>true)
|
|
417
440
|
@R.new(1, 2, :exclude_begin=>true).wont_equal @R.new(1, 2, :exclude_end=>true)
|
|
@@ -427,16 +450,39 @@ describe "pg_range extension" do
|
|
|
427
450
|
|
|
428
451
|
it "should not consider a PGRange equal with a Range if it can't be expressed as a range" do
|
|
429
452
|
@R.new(nil, nil).wont_be :==, (1..2)
|
|
453
|
+
if startless_range_support
|
|
454
|
+
@R.new(nil, nil, :exclude_begin=>true).wont_be :==, eval('nil..nil')
|
|
455
|
+
end
|
|
430
456
|
end
|
|
431
457
|
|
|
432
458
|
it "should consider PGRanges equal with a endless Range they represent" do
|
|
433
459
|
@R.new(1, nil).must_be :==, eval('1..')
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
460
|
+
@R.new(1, nil, :exclude_end=>true).must_be :==, eval('1...')
|
|
461
|
+
@R.new(1, nil).wont_be :==, eval('1...')
|
|
462
|
+
@R.new(1, nil, :exclude_end=>true).wont_be :==, eval('1..')
|
|
437
463
|
@R.new(1, nil).wont_be :==, eval('2..')
|
|
464
|
+
@R.new(1, nil, :exclude_end=>true).wont_be :==, eval('2...')
|
|
438
465
|
end if endless_range_support
|
|
439
466
|
|
|
467
|
+
it "should consider PGRanges equal with a startless Range they represent" do
|
|
468
|
+
@R.new(nil, 1).must_be :==, eval('..1')
|
|
469
|
+
@R.new(nil, 1, :exclude_end=>true).must_be :==, eval('...1')
|
|
470
|
+
@R.new(nil, 1).wont_be :==, eval('...1')
|
|
471
|
+
@R.new(nil, 1, :exclude_end=>true).wont_be :==, eval('..1')
|
|
472
|
+
@R.new(nil, 1).wont_be :==, eval('..2')
|
|
473
|
+
@R.new(nil, 1, :exclude_end=>true).wont_be :==, eval('...2')
|
|
474
|
+
end if startless_range_support
|
|
475
|
+
|
|
476
|
+
it "should consider PGRanges equal with a startless, endless Range they represent" do
|
|
477
|
+
@R.new(nil, nil).must_be :==, eval('nil..nil')
|
|
478
|
+
@R.new(nil, nil, :exclude_end=>true).must_be :==, eval('nil...nil')
|
|
479
|
+
@R.new(nil, nil).wont_be :==, eval('nil...nil')
|
|
480
|
+
@R.new(nil, nil, :exclude_end=>true).wont_be :==, eval('nil..nil')
|
|
481
|
+
@R.new(nil, nil).wont_be :==, eval('nil..1')
|
|
482
|
+
@R.new(nil, nil).wont_be :==, eval('1..nil')
|
|
483
|
+
@R.new(1, nil).wont_be :==, eval('nil..nil')
|
|
484
|
+
end if startless_range_support
|
|
485
|
+
|
|
440
486
|
it "should not consider a PGRange equal to other objects" do
|
|
441
487
|
@R.new(nil, nil).wont_equal 1
|
|
442
488
|
end
|
|
@@ -444,7 +490,6 @@ describe "pg_range extension" do
|
|
|
444
490
|
it "should have #=== be true if given an equal PGRange" do
|
|
445
491
|
@R.new(1, 2).must_be :===, @R.new(1, 2)
|
|
446
492
|
@R.new(1, 2).wont_be :===, @R.new(1, 3)
|
|
447
|
-
|
|
448
493
|
end
|
|
449
494
|
|
|
450
495
|
it "should have #=== be true if it would be true for the Range represented by the PGRange" do
|
|
@@ -453,7 +498,7 @@ describe "pg_range extension" do
|
|
|
453
498
|
end
|
|
454
499
|
|
|
455
500
|
it "should have #=== be false if the PGRange cannot be represented by a Range" do
|
|
456
|
-
@R.new(
|
|
501
|
+
@R.new(1, 2, :exclude_begin=>true).wont_be :===, 1.5
|
|
457
502
|
end
|
|
458
503
|
|
|
459
504
|
it "should have #empty? indicate whether the range is empty" do
|
|
@@ -471,7 +516,6 @@ describe "pg_range extension" do
|
|
|
471
516
|
end
|
|
472
517
|
|
|
473
518
|
it "should have #to_range raise an exception if the PGRange cannot be represented by a Range" do
|
|
474
|
-
proc{@R.new(nil, 1).to_range}.must_raise(Sequel::Error)
|
|
475
519
|
proc{@R.new(0, 1, :exclude_begin=>true).to_range}.must_raise(Sequel::Error)
|
|
476
520
|
proc{@R.empty.to_range}.must_raise(Sequel::Error)
|
|
477
521
|
end
|
|
@@ -488,6 +532,22 @@ describe "pg_range extension" do
|
|
|
488
532
|
proc{@R.new(1, nil).to_range}.must_raise(Sequel::Error)
|
|
489
533
|
end unless endless_range_support
|
|
490
534
|
|
|
535
|
+
it "should have #to_range return the represented range for startless ranges" do
|
|
536
|
+
@R.new(nil, 1).to_range.must_be :==, eval('..1')
|
|
537
|
+
end if startless_range_support
|
|
538
|
+
|
|
539
|
+
it "should have #to_range raise an exception for startless ranges" do
|
|
540
|
+
proc{@R.new(nil, 1).to_range}.must_raise(Sequel::Error)
|
|
541
|
+
end unless startless_range_support
|
|
542
|
+
|
|
543
|
+
it "should have #to_range return the represented range for startless, endless ranges" do
|
|
544
|
+
@R.new(nil, nil).to_range.must_be :==, eval('nil..nil')
|
|
545
|
+
end if startless_range_support
|
|
546
|
+
|
|
547
|
+
it "should have #to_range raise an exception for startless, endless ranges" do
|
|
548
|
+
proc{@R.new(nil, nil).to_range}.must_raise(Sequel::Error)
|
|
549
|
+
end unless startless_range_support
|
|
550
|
+
|
|
491
551
|
it "should have #to_range cache the returned value" do
|
|
492
552
|
@r1.to_range.must_be_same_as(@r1.to_range)
|
|
493
553
|
end
|
|
@@ -507,7 +567,6 @@ describe "pg_range extension" do
|
|
|
507
567
|
end
|
|
508
568
|
|
|
509
569
|
it "should have #valid_ruby_range? return false if the PGRange cannot be represented as a Range" do
|
|
510
|
-
@R.new(nil, 1).valid_ruby_range?.must_equal false
|
|
511
570
|
@R.new(0, 1, :exclude_begin=>true).valid_ruby_range?.must_equal false
|
|
512
571
|
@R.empty.valid_ruby_range?.must_equal false
|
|
513
572
|
end
|
|
@@ -515,5 +574,13 @@ describe "pg_range extension" do
|
|
|
515
574
|
it "should have #valid_ruby_range return #{endless_range_support} for endless ranges" do
|
|
516
575
|
@R.new(1, nil).valid_ruby_range?.must_equal(endless_range_support)
|
|
517
576
|
end
|
|
577
|
+
|
|
578
|
+
it "should have #valid_ruby_range return #{startless_range_support} for endless ranges" do
|
|
579
|
+
@R.new(nil, 1).valid_ruby_range?.must_equal(startless_range_support)
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
it "should have #valid_ruby_range return #{startless_range_support} for startless, endless ranges" do
|
|
583
|
+
@R.new(nil, nil).valid_ruby_range?.must_equal(startless_range_support)
|
|
584
|
+
end
|
|
518
585
|
end
|
|
519
586
|
end
|
|
@@ -254,6 +254,12 @@ describe Sequel::Model, "rcte_tree" do
|
|
|
254
254
|
@db.sqls.must_equal ["SELECT * FROM nodes",
|
|
255
255
|
'WITH t AS (SELECT parent_id AS x_root_x, nodes.* FROM nodes WHERE ((parent_id IN (2, 6, 7)) AND (i = 1)) UNION ALL SELECT t.x_root_x, nodes.* FROM nodes INNER JOIN t ON (t.id = nodes.parent_id) WHERE (i = 1)) SELECT * FROM t AS nodes WHERE (i = 1)']
|
|
256
256
|
end
|
|
257
|
+
|
|
258
|
+
it "should disallow eager graphing of ancestors and descendants" do
|
|
259
|
+
@c.plugin :rcte_tree
|
|
260
|
+
proc{@c.eager_graph(:ancestors)}.must_raise Sequel::Error
|
|
261
|
+
proc{@c.eager_graph(:descendants)}.must_raise Sequel::Error
|
|
262
|
+
end
|
|
257
263
|
end
|
|
258
264
|
|
|
259
265
|
describe Sequel::Model, "rcte_tree with composite keys" do
|
data/spec/extensions/s_spec.rb
CHANGED
|
@@ -29,7 +29,7 @@ describe "s extension as refinement" do
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby')
|
|
32
|
+
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_ENGINE == 'jruby' && (JRUBY_VERSION >= '9.3' || (JRUBY_VERSION.match(/\A9\.2\.(\d+)/) && $1.to_i >= 7)))
|
|
33
33
|
using Sequel::S
|
|
34
34
|
|
|
35
35
|
describe "s extension as refinement" do
|
|
@@ -800,14 +800,16 @@ END_MIG
|
|
|
800
800
|
it "should convert mysql types to ruby types" do
|
|
801
801
|
def @d.schema(t, *o)
|
|
802
802
|
i = 0
|
|
803
|
-
['double(15,2)', 'double(7,1) unsigned'].map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]}
|
|
803
|
+
['float unsigned', 'double(15,2)', 'double(7,1) unsigned'].map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]}
|
|
804
804
|
end
|
|
805
805
|
@d.dump_table_schema(:x).must_equal((<<END_MIG).chomp)
|
|
806
806
|
create_table(:x) do
|
|
807
807
|
Float :c1
|
|
808
808
|
Float :c2
|
|
809
|
+
Float :c3
|
|
809
810
|
|
|
810
|
-
check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:
|
|
811
|
+
check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:c1), 0)
|
|
812
|
+
check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:c3), 0)
|
|
811
813
|
end
|
|
812
814
|
END_MIG
|
|
813
815
|
end
|
|
@@ -95,3 +95,41 @@ describe "Database#with_server multi threaded" do
|
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
describe "Database#with_server with invalid servers" do
|
|
99
|
+
def sqls(server)
|
|
100
|
+
@db.with_server(server) do
|
|
101
|
+
@db[:t].all
|
|
102
|
+
@db[:t].insert
|
|
103
|
+
@db[:t].update(:a=>1)
|
|
104
|
+
@db[:t].delete
|
|
105
|
+
end
|
|
106
|
+
@db.sqls
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "when single threaded and no servers_hash" do
|
|
110
|
+
@db = Sequel.mock(:single_threaded=>true, :servers=>{:a=>{}}).extension(:server_block)
|
|
111
|
+
sqls(:a).must_equal ["SELECT * FROM t -- a", "INSERT INTO t DEFAULT VALUES -- a", "UPDATE t SET a = 1 -- a", "DELETE FROM t -- a"]
|
|
112
|
+
sqls(:c).must_equal ["SELECT * FROM t", "INSERT INTO t DEFAULT VALUES", "UPDATE t SET a = 1", "DELETE FROM t"]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "when multi-threaded and no servers_hash" do
|
|
116
|
+
@db = Sequel.mock(:servers=>{:a=>{}}).extension(:server_block)
|
|
117
|
+
sqls(:a).must_equal ["SELECT * FROM t -- a", "INSERT INTO t DEFAULT VALUES -- a", "UPDATE t SET a = 1 -- a", "DELETE FROM t -- a"]
|
|
118
|
+
sqls(:c).must_equal ["SELECT * FROM t", "INSERT INTO t DEFAULT VALUES", "UPDATE t SET a = 1", "DELETE FROM t"]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "when single threaded and servers_hash" do
|
|
122
|
+
@db = Sequel.mock(:single_threaded=>true, :servers=>{:a=>{}, :b=>{}}, :servers_hash=>Hash.new{|_,k| raise}.merge!(:c=>:b)).extension(:server_block)
|
|
123
|
+
sqls(:a).must_equal ["SELECT * FROM t -- a", "INSERT INTO t DEFAULT VALUES -- a", "UPDATE t SET a = 1 -- a", "DELETE FROM t -- a"]
|
|
124
|
+
sqls(:c).must_equal ["SELECT * FROM t -- b", "INSERT INTO t DEFAULT VALUES -- b", "UPDATE t SET a = 1 -- b", "DELETE FROM t -- b"]
|
|
125
|
+
proc{sqls(:d)}.must_raise(RuntimeError)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "when multi-threaded and servers_hash" do
|
|
129
|
+
@db = Sequel.mock(:servers=>{:a=>{}, :b=>{}}, :servers_hash=>Hash.new{|_,k| raise}.merge!(:c=>:b)).extension(:server_block)
|
|
130
|
+
sqls(:a).must_equal ["SELECT * FROM t -- a", "INSERT INTO t DEFAULT VALUES -- a", "UPDATE t SET a = 1 -- a", "DELETE FROM t -- a"]
|
|
131
|
+
sqls(:c).must_equal ["SELECT * FROM t -- b", "INSERT INTO t DEFAULT VALUES -- b", "UPDATE t SET a = 1 -- b", "DELETE FROM t -- b"]
|
|
132
|
+
proc{sqls(:d)}.must_raise(RuntimeError)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
@@ -16,6 +16,11 @@ require_relative "../../lib/sequel"
|
|
|
16
16
|
|
|
17
17
|
require_relative '../deprecation_helper'
|
|
18
18
|
|
|
19
|
+
if ENV['SEQUEL_TZINFO_VERSION']
|
|
20
|
+
# Allow forcing specific TZInfo versions, useful when testing
|
|
21
|
+
gem 'tzinfo', ENV['SEQUEL_TZINFO_VERSION']
|
|
22
|
+
end
|
|
23
|
+
|
|
19
24
|
begin
|
|
20
25
|
# Attempt to load ActiveSupport blank extension and inflector first, so Sequel
|
|
21
26
|
# can override them.
|
|
@@ -26,7 +31,9 @@ rescue LoadError
|
|
|
26
31
|
nil
|
|
27
32
|
end
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_ENGINE == 'jruby' && (JRUBY_VERSION >= '9.3' || (JRUBY_VERSION.match(/\A9\.2\.(\d+)/) && $1.to_i >= 7)))
|
|
35
|
+
Sequel.extension :core_refinements
|
|
36
|
+
end
|
|
30
37
|
|
|
31
38
|
class << Sequel::Model
|
|
32
39
|
attr_writer :db_schema
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require_relative "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "static_cache_cache plugin" do
|
|
4
|
+
before do
|
|
5
|
+
@db = Sequel.mock
|
|
6
|
+
@db.fetch = [{:id=>1, :name=>'A'}, {:id=>2, :name=>'B'}]
|
|
7
|
+
@c = Class.new(Sequel::Model(@db[:t]))
|
|
8
|
+
def @c.name; 'Foo' end
|
|
9
|
+
@c.columns :id, :name
|
|
10
|
+
@file = "spec/files/static_cache_cache-spec-#{$$}.cache"
|
|
11
|
+
end
|
|
12
|
+
after do
|
|
13
|
+
File.delete(@file) if File.file?(@file)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should allow dumping and loading static cache rows from a cache file" do
|
|
17
|
+
@c.plugin :static_cache_cache, @file
|
|
18
|
+
@db.sqls
|
|
19
|
+
@c.plugin :static_cache
|
|
20
|
+
@db.sqls.must_equal ['SELECT * FROM t']
|
|
21
|
+
@c.all.must_equal [@c.load(:id=>1, :name=>'A'), @c.load(:id=>2, :name=>'B')]
|
|
22
|
+
|
|
23
|
+
@c.dump_static_cache_cache
|
|
24
|
+
|
|
25
|
+
@db.fetch = []
|
|
26
|
+
c = Class.new(Sequel::Model(@db[:t]))
|
|
27
|
+
def c.name; 'Foo' end
|
|
28
|
+
c.columns :id, :name
|
|
29
|
+
@c.plugin :static_cache_cache, @file
|
|
30
|
+
@db.sqls
|
|
31
|
+
@c.plugin :static_cache
|
|
32
|
+
@db.sqls.must_be_empty
|
|
33
|
+
@c.all.must_equal [@c.load(:id=>1, :name=>'A'), @c.load(:id=>2, :name=>'B')]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -957,7 +957,7 @@ if DB.dataset.supports_window_functions?
|
|
|
957
957
|
must_equal [{:sum=>110, :id=>1}, {:sum=>1100, :id=>2}, {:sum=>11000, :id=>3}, {:sum=>110000, :id=>4}, {:sum=>100000, :id=>5}, {:sum=>nil, :id=>6}]
|
|
958
958
|
end
|
|
959
959
|
|
|
960
|
-
cspecify "should give correct results for aggregate window functions with offsets for RANGES", :mssql, :sqlite, [proc{DB.server_version < 110000}, :postgres] do
|
|
960
|
+
cspecify "should give correct results for aggregate window functions with offsets for RANGES", :mssql, [proc{DB.sqlite_version < 32800}, :sqlite], [proc{DB.server_version < 110000}, :postgres] do
|
|
961
961
|
@ds.select(:id){sum(:amount).over(:order=>:group_id, :frame=>{:type=>:range, :start=>1}).as(:sum)}.all.
|
|
962
962
|
must_equal [{:sum=>111, :id=>1}, {:sum=>111, :id=>2}, {:sum=>111, :id=>3}, {:sum=>111111, :id=>4}, {:sum=>111111, :id=>5}, {:sum=>111111, :id=>6}]
|
|
963
963
|
@ds.select(:id){sum(:amount).over(:order=>:group_id, :frame=>{:type=>:range, :start=>0, :end=>1}).as(:sum)}.all.
|
|
@@ -1109,6 +1109,12 @@ describe "Sequel::Dataset#import and #multi_insert :return=>:primary_key " do
|
|
|
1109
1109
|
@ds.order(:id).map([:id, :i]).must_equal [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
|
|
1110
1110
|
end
|
|
1111
1111
|
|
|
1112
|
+
it "should handle dataset with row_proc" do
|
|
1113
|
+
ds = @ds.with_row_proc(lambda{|h| Object.new})
|
|
1114
|
+
ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key).must_equal [1, 2, 3]
|
|
1115
|
+
ds.import([:i], [[40], [50], [60]], :return=>:primary_key).must_equal [4, 5, 6]
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1112
1118
|
it "should return primary key values when :slice is used" do
|
|
1113
1119
|
@ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key, :slice=>2).must_equal [1, 2, 3]
|
|
1114
1120
|
@ds.import([:i], [[40], [50], [60]], :return=>:primary_key, :slice=>2).must_equal [4, 5, 6]
|
|
@@ -1545,15 +1551,25 @@ describe "Sequel::Dataset DSL support" do
|
|
|
1545
1551
|
@ds.exclude(:a=>[20, 10]).all.must_equal []
|
|
1546
1552
|
end
|
|
1547
1553
|
|
|
1548
|
-
it "should work with ranges as hash values" do
|
|
1554
|
+
it "should work with endless ranges as hash values" do
|
|
1549
1555
|
@ds.insert(20, 10)
|
|
1550
|
-
@ds.filter(:a=>(
|
|
1551
|
-
@ds.filter(:a=>(
|
|
1552
|
-
@ds.filter(:a=>(
|
|
1553
|
-
@ds.
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1556
|
+
@ds.filter(:a=>eval('30..')).all.must_equal []
|
|
1557
|
+
@ds.filter(:a=>eval('20...')).all.must_equal [{:a=>20, :b=>10}]
|
|
1558
|
+
@ds.filter(:a=>eval('20..')).all.must_equal [{:a=>20, :b=>10}]
|
|
1559
|
+
@ds.filter(:a=>eval('10..')).all.must_equal [{:a=>20, :b=>10}]
|
|
1560
|
+
end if RUBY_VERSION >= '2.6'
|
|
1561
|
+
|
|
1562
|
+
it "should work with startless ranges as hash values" do
|
|
1563
|
+
@ds.insert(20, 10)
|
|
1564
|
+
@ds.filter(:a=>eval('..30')).all.must_equal [{:a=>20, :b=>10}]
|
|
1565
|
+
@ds.filter(:a=>eval('...30')).all.must_equal [{:a=>20, :b=>10}]
|
|
1566
|
+
@ds.filter(:a=>eval('..20')).all.must_equal [{:a=>20, :b=>10}]
|
|
1567
|
+
@ds.filter(:a=>eval('...20')).all.must_equal []
|
|
1568
|
+
@ds.filter(:a=>eval('..10')).all.must_equal []
|
|
1569
|
+
@ds.filter(:a=>eval('...10')).all.must_equal []
|
|
1570
|
+
|
|
1571
|
+
@ds.filter(:a=>eval('nil..nil')).all.must_equal [{:a=>20, :b=>10}]
|
|
1572
|
+
end if RUBY_VERSION >= '2.7'
|
|
1557
1573
|
|
|
1558
1574
|
it "should work with CASE statements" do
|
|
1559
1575
|
@ds.insert(20, 10)
|
|
@@ -30,6 +30,7 @@ describe "Class Table Inheritance Plugin" do
|
|
|
30
30
|
end
|
|
31
31
|
class ::Manager < Employee
|
|
32
32
|
one_to_many :staff_members, :class=>:Staff
|
|
33
|
+
one_to_one :first_staff_member, :clone=>:staff_members, :order=>:id
|
|
33
34
|
end
|
|
34
35
|
class ::Executive < Manager
|
|
35
36
|
end
|
|
@@ -150,6 +151,8 @@ describe "Class Table Inheritance Plugin" do
|
|
|
150
151
|
m = Staff.first.manager
|
|
151
152
|
m.must_equal Manager[@i4]
|
|
152
153
|
m.must_be_kind_of(Executive)
|
|
154
|
+
Staff.first.update(:manager => Manager[@i3])
|
|
155
|
+
Staff.first.manager.must_equal Manager[@i3]
|
|
153
156
|
end
|
|
154
157
|
|
|
155
158
|
it "should handle eagerly loading many_to_one relationships" do
|
|
@@ -164,6 +167,18 @@ describe "Class Table Inheritance Plugin" do
|
|
|
164
167
|
|
|
165
168
|
it "should handle one_to_many relationships" do
|
|
166
169
|
Executive.first(:name=>'Ex').staff_members.must_equal [Staff[@i2]]
|
|
170
|
+
i6 = @db[:employees].insert(:name=>'S2', :kind=>'Staff')
|
|
171
|
+
@db[:staff].insert(:id=>i6, :manager_id=>@i4)
|
|
172
|
+
Executive.first(:name=>'Ex').add_staff_member(i6)
|
|
173
|
+
Executive.first(:name=>'Ex').staff_members{|ds| ds.order(:id)}.must_equal [Staff[@i2], Staff[i6]]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "should handle one_to_many relationships" do
|
|
177
|
+
Executive.first(:name=>'Ex').first_staff_member.must_equal Staff[@i2]
|
|
178
|
+
i6 = @db[:employees].insert(:name=>'S2', :kind=>'Staff')
|
|
179
|
+
@db[:staff].insert(:id=>i6, :manager_id=>@i4)
|
|
180
|
+
Executive.first(:name=>'Ex').first_staff_member = Staff[i6]
|
|
181
|
+
Executive.first(:name=>'Ex').staff_members.must_equal [Staff[i6]]
|
|
167
182
|
end
|
|
168
183
|
|
|
169
184
|
it "should handle eagerly loading one_to_many relationships" do
|
|
@@ -2379,3 +2394,30 @@ describe "string_agg extension" do
|
|
|
2379
2394
|
@ds.select_group(:id).select_append(Sequel.string_agg(:s).order(:s).distinct.as(:v)).map([:id, :v]).must_equal [[1, 'a,b,c'], [2, 'aa,bb']]
|
|
2380
2395
|
end
|
|
2381
2396
|
end
|
|
2397
|
+
|
|
2398
|
+
describe "insert_conflict plugin" do
|
|
2399
|
+
before(:all) do
|
|
2400
|
+
@db = DB
|
|
2401
|
+
@db.create_table!(:ic_test) do
|
|
2402
|
+
primary_key :id
|
|
2403
|
+
String :s, :unique=>true
|
|
2404
|
+
Integer :o
|
|
2405
|
+
end
|
|
2406
|
+
@model = Class.new(Sequel::Model)
|
|
2407
|
+
@model.set_dataset @db[:ic_test]
|
|
2408
|
+
@model.plugin :insert_conflict
|
|
2409
|
+
end
|
|
2410
|
+
after(:all) do
|
|
2411
|
+
@db.drop_table?(:ic_test)
|
|
2412
|
+
end
|
|
2413
|
+
|
|
2414
|
+
it "should allow Model#insert_conflict to work" do
|
|
2415
|
+
ic_opts = {:target=>:s, :update => {:o => Sequel[:excluded][:o]}}
|
|
2416
|
+
@model.new(:s=>'A', :o=>1).insert_conflict(ic_opts).save
|
|
2417
|
+
@model.select_order_map([:s, :o]).must_equal [['A', 1]]
|
|
2418
|
+
@model.new(:s=>'A', :o=>2).insert_conflict(ic_opts).save
|
|
2419
|
+
@model.select_order_map([:s, :o]).must_equal [['A', 2]]
|
|
2420
|
+
@model.new(:s=>'B', :o=>3).insert_conflict(ic_opts).save
|
|
2421
|
+
@model.select_order_map([:s, :o]).must_equal [['A', 2], ['B', 3]]
|
|
2422
|
+
end
|
|
2423
|
+
end if (DB.database_type == :postgres && DB.server_version >= 90500) || (DB.database_type == :sqlite && DB.sqlite_version >= 32400)
|
|
@@ -750,10 +750,15 @@ describe "Database schema modifiers" do
|
|
|
750
750
|
@db.create_table!(:items) do
|
|
751
751
|
primary_key :id
|
|
752
752
|
Integer :i, :default=>20
|
|
753
|
+
Integer :j, :default=>10
|
|
754
|
+
String :s, :default=>'a'
|
|
753
755
|
end
|
|
754
|
-
@ds.insert(:i=>10)
|
|
756
|
+
@ds.insert(:i=>10, :j=>20, :s=>'b')
|
|
755
757
|
@db.drop_column(:items, :i)
|
|
756
|
-
@db.schema(:items, :reload=>true).map{|x| x.first}.must_equal [:id]
|
|
758
|
+
@db.schema(:items, :reload=>true).map{|x| x.first}.must_equal [:id, :j, :s]
|
|
759
|
+
@ds.first.must_equal(:id=>1, :j=>20, :s=>'b')
|
|
760
|
+
@ds.insert
|
|
761
|
+
@ds.first(:id=>2).must_equal(:id=>2, :j=>10, :s=>'a')
|
|
757
762
|
end
|
|
758
763
|
|
|
759
764
|
it "should remove foreign key columns from tables correctly" do
|