sequel 5.19.0 → 5.24.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|