sequel 4.10.0 → 4.11.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 +58 -0
- data/doc/association_basics.rdoc +1 -1
- data/doc/cheat_sheet.rdoc +0 -1
- data/doc/core_extensions.rdoc +2 -2
- data/doc/dataset_filtering.rdoc +5 -5
- data/doc/model_hooks.rdoc +9 -0
- data/doc/object_model.rdoc +7 -13
- data/doc/opening_databases.rdoc +3 -1
- data/doc/querying.rdoc +8 -8
- data/doc/release_notes/4.11.0.txt +147 -0
- data/doc/sql.rdoc +11 -7
- data/doc/virtual_rows.rdoc +4 -5
- data/lib/sequel/adapters/ibmdb.rb +24 -16
- data/lib/sequel/adapters/jdbc/h2.rb +5 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
- data/lib/sequel/adapters/mock.rb +14 -2
- data/lib/sequel/adapters/shared/access.rb +6 -9
- data/lib/sequel/adapters/shared/cubrid.rb +5 -0
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/firebird.rb +5 -0
- data/lib/sequel/adapters/shared/mssql.rb +23 -16
- data/lib/sequel/adapters/shared/mysql.rb +12 -2
- data/lib/sequel/adapters/shared/oracle.rb +31 -15
- data/lib/sequel/adapters/shared/postgres.rb +28 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +5 -0
- data/lib/sequel/adapters/shared/sqlite.rb +12 -1
- data/lib/sequel/ast_transformer.rb +9 -7
- data/lib/sequel/connection_pool.rb +10 -4
- data/lib/sequel/database/features.rb +15 -0
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +21 -3
- data/lib/sequel/database/transactions.rb +8 -4
- data/lib/sequel/dataset/actions.rb +13 -7
- data/lib/sequel/dataset/features.rb +7 -0
- data/lib/sequel/dataset/query.rb +28 -11
- data/lib/sequel/dataset/sql.rb +90 -14
- data/lib/sequel/extensions/constraint_validations.rb +2 -2
- data/lib/sequel/extensions/date_arithmetic.rb +1 -1
- data/lib/sequel/extensions/eval_inspect.rb +12 -6
- data/lib/sequel/extensions/pg_array_ops.rb +11 -2
- data/lib/sequel/extensions/pg_json.rb +130 -23
- data/lib/sequel/extensions/pg_json_ops.rb +196 -28
- data/lib/sequel/extensions/to_dot.rb +5 -7
- data/lib/sequel/model/associations.rb +0 -50
- data/lib/sequel/plugins/class_table_inheritance.rb +49 -21
- data/lib/sequel/plugins/many_through_many.rb +10 -11
- data/lib/sequel/plugins/serialization.rb +4 -1
- data/lib/sequel/plugins/sharding.rb +0 -9
- data/lib/sequel/plugins/single_table_inheritance.rb +4 -2
- data/lib/sequel/plugins/timestamps.rb +2 -2
- data/lib/sequel/sql.rb +166 -44
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +199 -133
- data/spec/core/connection_pool_spec.rb +6 -0
- data/spec/core/database_spec.rb +12 -0
- data/spec/core/dataset_spec.rb +58 -3
- data/spec/core/expression_filters_spec.rb +67 -5
- data/spec/core/mock_adapter_spec.rb +8 -4
- data/spec/core/schema_spec.rb +7 -0
- data/spec/core_extensions_spec.rb +14 -0
- data/spec/extensions/class_table_inheritance_spec.rb +23 -3
- data/spec/extensions/core_refinements_spec.rb +14 -0
- data/spec/extensions/eval_inspect_spec.rb +8 -4
- data/spec/extensions/pg_array_ops_spec.rb +6 -0
- data/spec/extensions/pg_json_ops_spec.rb +99 -0
- data/spec/extensions/pg_json_spec.rb +104 -4
- data/spec/extensions/serialization_spec.rb +19 -0
- data/spec/extensions/single_table_inheritance_spec.rb +11 -3
- data/spec/extensions/timestamps_spec.rb +10 -0
- data/spec/extensions/to_dot_spec.rb +8 -4
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +9 -0
- data/spec/integration/schema_test.rb +27 -0
- metadata +4 -2
@@ -390,6 +390,22 @@ describe "Blockless Ruby Filters" do
|
|
390
390
|
it "should handled emulated trim function" do
|
391
391
|
@d.lit(Sequel.trim(:a)).should == 'trim(a)'
|
392
392
|
end
|
393
|
+
|
394
|
+
it "should handled emulated function where only name is emulated" do
|
395
|
+
dsc = Class.new(Sequel::Dataset)
|
396
|
+
dsc::EMULATED_FUNCTION_MAP[:trim] = :foo
|
397
|
+
dsc.new(@d.db).literal(Sequel.trim(:a)).should == 'foo(a)'
|
398
|
+
end
|
399
|
+
|
400
|
+
it "should handled emulated function needing full emulation" do
|
401
|
+
dsc = Class.new(Sequel::Dataset) do
|
402
|
+
def emulate_function?(n) n == :trim end
|
403
|
+
def emulate_function_sql_append(sql, f)
|
404
|
+
sql << "#{f.name}FOO(lower(#{f.args.first}))"
|
405
|
+
end
|
406
|
+
end
|
407
|
+
dsc.new(@d.db).literal(Sequel.trim(:a)).should == 'trimFOO(lower(a))'
|
408
|
+
end
|
393
409
|
end
|
394
410
|
|
395
411
|
describe Sequel::SQL::VirtualRow do
|
@@ -419,15 +435,17 @@ describe Sequel::SQL::VirtualRow do
|
|
419
435
|
@d.l{version{}}.should == 'version()'
|
420
436
|
end
|
421
437
|
|
422
|
-
it "should treat methods with a block and a leading argument :* as a function call
|
438
|
+
it "should treat methods with a block and a leading argument :* as a function call with the SQL wildcard" do
|
423
439
|
@d.l{count(:*){}}.should == 'count(*)'
|
424
|
-
@d.l{count(:*, 1){}}.should == 'count(*, 1)'
|
425
440
|
end
|
426
441
|
|
427
|
-
it "should support * method on functions to
|
442
|
+
it "should support * method on functions to raise error if function already has an argument" do
|
443
|
+
proc{@d.l{count(1).*}}.should raise_error(Sequel::Error)
|
444
|
+
end
|
445
|
+
|
446
|
+
it "should support * method on functions to use * as the argument" do
|
428
447
|
@d.l{count{}.*}.should == 'count(*)'
|
429
|
-
@d.
|
430
|
-
@d.literal(Sequel.expr{count(1) * 2}).should == '(count(1) * 2)'
|
448
|
+
@d.literal(Sequel.expr{sum(1) * 2}).should == '(sum(1) * 2)'
|
431
449
|
end
|
432
450
|
|
433
451
|
it "should treat methods with a block and a leading argument :distinct as a function call with DISTINCT and the additional method arguments" do
|
@@ -496,6 +514,14 @@ describe Sequel::SQL::VirtualRow do
|
|
496
514
|
@d.l{sum(c).over(:partition=>a, :order=>b, :window=>:win, :frame=>:rows)}.should == 'sum("c") OVER ("win" PARTITION BY "a" ORDER BY "b" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)'
|
497
515
|
end
|
498
516
|
|
517
|
+
it "should support over method with a Window argument" do
|
518
|
+
@d.l{sum(c).over(Sequel::SQL::Window.new(:partition=>a, :order=>b, :window=>:win, :frame=>:rows))}.should == 'sum("c") OVER ("win" PARTITION BY "a" ORDER BY "b" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)'
|
519
|
+
end
|
520
|
+
|
521
|
+
it "should raise error if over is called on a function that already has a window " do
|
522
|
+
proc{@d.l{rank{}.over.over}}.should raise_error(Sequel::Error)
|
523
|
+
end
|
524
|
+
|
499
525
|
it "should raise an error if window functions are not supported" do
|
500
526
|
class << @d; remove_method :supports_window_functions? end
|
501
527
|
meta_def(@d, :supports_window_functions?){false}
|
@@ -503,6 +529,30 @@ describe Sequel::SQL::VirtualRow do
|
|
503
529
|
proc{Sequel.mock.dataset.filter{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}.sql}.should raise_error(Sequel::Error)
|
504
530
|
end
|
505
531
|
|
532
|
+
it "should handle lateral function calls" do
|
533
|
+
@d.l{rank{}.lateral}.should == 'LATERAL rank()'
|
534
|
+
end
|
535
|
+
|
536
|
+
it "should handle ordered-set and hypothetical-set function calls" do
|
537
|
+
@d.l{mode{}.within_group(:a)}.should == 'mode() WITHIN GROUP (ORDER BY "a")'
|
538
|
+
@d.l{mode{}.within_group(:a, :b)}.should == 'mode() WITHIN GROUP (ORDER BY "a", "b")'
|
539
|
+
end
|
540
|
+
|
541
|
+
it "should handle filtered aggregate function calls" do
|
542
|
+
@d.l{count{}.*.filter(:a, :b)}.should == 'count(*) FILTER (WHERE ("a" AND "b"))'
|
543
|
+
@d.l{count{}.*.filter(:a=>1)}.should == 'count(*) FILTER (WHERE ("a" = 1))'
|
544
|
+
@d.l{count{}.*.filter{b > 1}}.should == 'count(*) FILTER (WHERE ("b" > 1))'
|
545
|
+
@d.l{count{}.*.filter(:a=>1){b > 1}}.should == 'count(*) FILTER (WHERE (("a" = 1) AND ("b" > 1)))'
|
546
|
+
end
|
547
|
+
|
548
|
+
it "should handle fitlered ordered-set and hypothetical-set function calls" do
|
549
|
+
@d.l{mode{}.within_group(:a).filter(:a=>1)}.should == 'mode() WITHIN GROUP (ORDER BY "a") FILTER (WHERE ("a" = 1))'
|
550
|
+
end
|
551
|
+
|
552
|
+
it "should handle function calls with ordinality" do
|
553
|
+
@d.l{foo{}.with_ordinality}.should == 'foo() WITH ORDINALITY'
|
554
|
+
end
|
555
|
+
|
506
556
|
it "should support function method on identifiers to create functions" do
|
507
557
|
@d.l{rank.function}.should == 'rank()'
|
508
558
|
@d.l{sum.function(c)}.should == 'sum("c")'
|
@@ -522,6 +572,18 @@ describe Sequel::SQL::VirtualRow do
|
|
522
572
|
@d.l{sch__rank.function}.should == '"sch"."rank"()'
|
523
573
|
end
|
524
574
|
|
575
|
+
it "should quote function names if a quoted function is used and database supports quoted function names" do
|
576
|
+
def @d.supports_quoted_function_names?; true; end
|
577
|
+
@d.l{rank{}.quoted}.should == '"rank"()'
|
578
|
+
@d.l{sch__rank{}.quoted}.should == '"sch__rank"()'
|
579
|
+
end
|
580
|
+
|
581
|
+
it "should not quote function names if an unquoted function is used" do
|
582
|
+
def @d.supports_quoted_function_names?; true; end
|
583
|
+
@d.l{rank.function.unquoted}.should == 'rank()'
|
584
|
+
@d.l{sch__rank.function.unquoted}.should == 'sch.rank()'
|
585
|
+
end
|
586
|
+
|
525
587
|
it "should deal with classes without requiring :: prefix" do
|
526
588
|
@d.l{date < Date.today}.should == "(\"date\" < '#{Date.today}')"
|
527
589
|
@d.l{date < Sequel::CURRENT_DATE}.should == "(\"date\" < CURRENT_DATE)"
|
@@ -424,13 +424,15 @@ describe "Sequel Mock Adapter" do
|
|
424
424
|
class Sequel::Database; @identifier_input_method=nil; end
|
425
425
|
class Sequel::Database; @identifier_output_method=nil; end
|
426
426
|
Sequel.mock(:host=>'access').select(Date.new(2011, 12, 13)).sql.should == 'SELECT #2011-12-13#'
|
427
|
+
Sequel.mock(:host=>'cubrid').from(:a).offset(1).sql.should == 'SELECT * FROM "a" LIMIT 1,4294967295'
|
427
428
|
Sequel.mock(:host=>'db2').select(1).sql.should == 'SELECT 1 FROM "SYSIBM"."SYSDUMMY1"'
|
428
429
|
Sequel.mock(:host=>'firebird')[:a].distinct.limit(1, 2).sql.should == 'SELECT DISTINCT FIRST 1 SKIP 2 * FROM "A"'
|
429
430
|
Sequel.mock(:host=>'informix')[:a].distinct.limit(1, 2).sql.should == 'SELECT SKIP 2 FIRST 1 DISTINCT * FROM A'
|
430
431
|
Sequel.mock(:host=>'mssql')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM [A] WHERE (CONTAINS ([B], 'c'))"
|
431
432
|
Sequel.mock(:host=>'mysql')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM `a` WHERE (MATCH (`b`) AGAINST ('c'))"
|
432
433
|
Sequel.mock(:host=>'oracle')[:a].limit(1).sql.should == 'SELECT * FROM (SELECT * FROM "A") "T1" WHERE (ROWNUM <= 1)'
|
433
|
-
Sequel.mock(:host=>'postgres')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector('simple'
|
434
|
+
Sequel.mock(:host=>'postgres')[:a].full_text_search(:b, 'c').sql.should == "SELECT * FROM \"a\" WHERE (to_tsvector(CAST('simple' AS regconfig), (COALESCE(\"b\", ''))) @@ to_tsquery(CAST('simple' AS regconfig), 'c'))"
|
435
|
+
Sequel.mock(:host=>'sqlanywhere').from(:a).offset(1).sql.should == 'SELECT TOP 2147483647 START AT (1 + 1) * FROM "A"'
|
434
436
|
Sequel.mock(:host=>'sqlite')[:a___b].sql.should == "SELECT * FROM `a` AS 'b'"
|
435
437
|
ensure
|
436
438
|
Sequel.quote_identifiers = qi
|
@@ -439,9 +441,11 @@ describe "Sequel Mock Adapter" do
|
|
439
441
|
end
|
440
442
|
end
|
441
443
|
|
442
|
-
specify "should automatically set version for
|
443
|
-
Sequel.mock(:host=>'postgres').server_version.should ==
|
444
|
-
Sequel.mock(:host=>'mssql').server_version.should ==
|
444
|
+
specify "should automatically set version for adapters nedding versions" do
|
445
|
+
Sequel.mock(:host=>'postgres').server_version.should == 90400
|
446
|
+
Sequel.mock(:host=>'mssql').server_version.should == 11000000
|
447
|
+
Sequel.mock(:host=>'mysql').server_version.should == 50617
|
448
|
+
Sequel.mock(:host=>'sqlite').sqlite_version.should == 30804
|
445
449
|
end
|
446
450
|
|
447
451
|
specify "should stub out the primary_key method for postgres" do
|
data/spec/core/schema_spec.rb
CHANGED
@@ -1399,6 +1399,13 @@ describe "Database#create_view" do
|
|
1399
1399
|
@db.sqls.should == ['CREATE VIEW test (d, e) AS SELECT a, b FROM items ORDER BY c']
|
1400
1400
|
end
|
1401
1401
|
|
1402
|
+
specify "should handle :check option" do
|
1403
|
+
@db.create_view :test, @db[:items].select(:a, :b).order(:c), :check=>true
|
1404
|
+
@db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c WITH CHECK OPTION']
|
1405
|
+
@db.create_view :test, @db[:items].select(:a, :b).order(:c), :check=>:local
|
1406
|
+
@db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c WITH LOCAL CHECK OPTION']
|
1407
|
+
end
|
1408
|
+
|
1402
1409
|
specify "should handle create_or_replace_view" do
|
1403
1410
|
@db.create_or_replace_view :sch__test, "SELECT * FROM xyz"
|
1404
1411
|
@db.sqls.should == ['DROP VIEW sch.test', 'CREATE VIEW sch.test AS SELECT * FROM xyz']
|
@@ -647,6 +647,12 @@ describe "Postgres extensions integration" do
|
|
647
647
|
|
648
648
|
it "Symbol#pg_json should return an JSONOp" do
|
649
649
|
@db.literal(:a.pg_json[%w'a b']).should == "(a #> ARRAY['a','b'])"
|
650
|
+
@db.literal(:a.pg_json.extract('a')).should == "json_extract_path(a, 'a')"
|
651
|
+
end
|
652
|
+
|
653
|
+
it "Symbol#pg_jsonb should return an JSONBOp" do
|
654
|
+
@db.literal(:a.pg_jsonb[%w'a b']).should == "(a #> ARRAY['a','b'])"
|
655
|
+
@db.literal(:a.pg_jsonb.extract('a')).should == "jsonb_extract_path(a, 'a')"
|
650
656
|
end
|
651
657
|
|
652
658
|
it "Symbol#pg_range should return a RangeOp" do
|
@@ -662,6 +668,10 @@ describe "Postgres extensions integration" do
|
|
662
668
|
@db.literal([1].pg_json).should == "'[1]'::json"
|
663
669
|
end
|
664
670
|
|
671
|
+
it "Array#pg_jsonb should return a JSONBArray" do
|
672
|
+
@db.literal([1].pg_jsonb).should == "'[1]'::jsonb"
|
673
|
+
end
|
674
|
+
|
665
675
|
it "Array#pg_row should return a ArrayRow" do
|
666
676
|
@db.literal([1].pg_row).should == "ROW(1)"
|
667
677
|
end
|
@@ -674,6 +684,10 @@ describe "Postgres extensions integration" do
|
|
674
684
|
@db.literal({'a'=>'b'}.pg_json).should == "'{\"a\":\"b\"}'::json"
|
675
685
|
end
|
676
686
|
|
687
|
+
it "Hash#pg_jsonb should return an JSONBHash" do
|
688
|
+
@db.literal({'a'=>'b'}.pg_jsonb).should == "'{\"a\":\"b\"}'::jsonb"
|
689
|
+
end
|
690
|
+
|
677
691
|
it "Range#pg_range should return an PGRange" do
|
678
692
|
@db.literal((1..2).pg_range).should == "'[1,2]'"
|
679
693
|
@db.literal((1..2).pg_range(:int4range)).should == "'[1,2]'::int4range"
|
@@ -94,6 +94,18 @@ describe "class_table_inheritance plugin" do
|
|
94
94
|
Manager.all.collect{|x| x.class}.should == [Manager, Manager]
|
95
95
|
end
|
96
96
|
|
97
|
+
it "should handle a model map with integer values" do
|
98
|
+
Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive})
|
99
|
+
Object.send(:remove_const, :Executive)
|
100
|
+
Object.send(:remove_const, :Manager)
|
101
|
+
class ::Manager < Employee; end
|
102
|
+
class ::Executive < Manager; end
|
103
|
+
Employee.dataset._fetch = [{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}]
|
104
|
+
Employee.all.collect{|x| x.class}.should == [Employee, Employee, Manager, Executive]
|
105
|
+
Manager.dataset._fetch = [{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}]
|
106
|
+
Manager.all.collect{|x| x.class}.should == [Manager, Employee, Manager, Executive]
|
107
|
+
end
|
108
|
+
|
97
109
|
it "should fallback to the main class if the given class does not exist" do
|
98
110
|
@ds._fetch = [{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Blah'}, {:kind=>'Staff'}]
|
99
111
|
Employee.all.collect{|x| x.class}.should == [Employee, Manager, Employee, Staff]
|
@@ -104,19 +116,19 @@ describe "class_table_inheritance plugin" do
|
|
104
116
|
Manager.all.collect{|x| x.class}.should == [Manager, Executive, Manager]
|
105
117
|
end
|
106
118
|
|
107
|
-
it "should
|
119
|
+
it "should sets the model class name for the key when creating new parent class records" do
|
108
120
|
Employee.create
|
109
121
|
@db.sqls.should == ["INSERT INTO employees (kind) VALUES ('Employee')"]
|
110
122
|
end
|
111
123
|
|
112
|
-
it "should
|
124
|
+
it "should sets the model class name for the key when creating new subclass records" do
|
113
125
|
Executive.create
|
114
126
|
@db.sqls.should == ["INSERT INTO employees (kind) VALUES ('Executive')",
|
115
127
|
"INSERT INTO managers (id) VALUES (1)",
|
116
128
|
"INSERT INTO executives (id) VALUES (1)"]
|
117
129
|
end
|
118
130
|
|
119
|
-
it "should ignore existing cti_key value" do
|
131
|
+
it "should ignore existing cti_key value when creating new records" do
|
120
132
|
Employee.create(:kind=>'Manager')
|
121
133
|
@db.sqls.should == ["INSERT INTO employees (kind) VALUES ('Employee')"]
|
122
134
|
end
|
@@ -127,6 +139,14 @@ describe "class_table_inheritance plugin" do
|
|
127
139
|
"INSERT INTO managers (id) VALUES (1)"]
|
128
140
|
end
|
129
141
|
|
142
|
+
it "should handle validations on the type column field" do
|
143
|
+
o = Employee.new
|
144
|
+
def o.validate
|
145
|
+
errors.add(:kind, 'not present') unless kind
|
146
|
+
end
|
147
|
+
o.valid?.should == true
|
148
|
+
end
|
149
|
+
|
130
150
|
it "should raise an error if attempting to create an anonymous subclass" do
|
131
151
|
proc{Class.new(Manager)}.should raise_error(Sequel::Error)
|
132
152
|
end
|
@@ -468,6 +468,12 @@ describe "Postgres extensions integration" do
|
|
468
468
|
|
469
469
|
it "Symbol#pg_json should return an JSONOp" do
|
470
470
|
@db.literal(:a.pg_json[%w'a b']).should == "(a #> ARRAY['a','b'])"
|
471
|
+
@db.literal(:a.pg_json.extract('a')).should == "json_extract_path(a, 'a')"
|
472
|
+
end
|
473
|
+
|
474
|
+
it "Symbol#pg_jsonb should return an JSONBOp" do
|
475
|
+
@db.literal(:a.pg_jsonb[%w'a b']).should == "(a #> ARRAY['a','b'])"
|
476
|
+
@db.literal(:a.pg_jsonb.extract('a')).should == "jsonb_extract_path(a, 'a')"
|
471
477
|
end
|
472
478
|
|
473
479
|
it "Symbol#pg_range should return a RangeOp" do
|
@@ -483,6 +489,10 @@ describe "Postgres extensions integration" do
|
|
483
489
|
@db.literal([1].pg_json).should == "'[1]'::json"
|
484
490
|
end
|
485
491
|
|
492
|
+
it "Array#pg_jsonb should return a JSONBArray" do
|
493
|
+
@db.literal([1].pg_jsonb).should == "'[1]'::jsonb"
|
494
|
+
end
|
495
|
+
|
486
496
|
it "Array#pg_row should return a ArrayRow" do
|
487
497
|
@db.literal([1].pg_row).should == "ROW(1)"
|
488
498
|
end
|
@@ -495,6 +505,10 @@ describe "Postgres extensions integration" do
|
|
495
505
|
@db.literal({'a'=>'b'}.pg_json).should == "'{\"a\":\"b\"}'::json"
|
496
506
|
end
|
497
507
|
|
508
|
+
it "Hash#pg_jsonb should return an JSONBHash" do
|
509
|
+
@db.literal({'a'=>'b'}.pg_jsonb).should == "'{\"a\":\"b\"}'::jsonb"
|
510
|
+
end
|
511
|
+
|
498
512
|
it "Range#pg_range should return an PGRange" do
|
499
513
|
@db.literal((1..2).pg_range).should == "'[1,2]'"
|
500
514
|
@db.literal((1..2).pg_range(:int4range)).should == "'[1,2]'::int4range"
|
@@ -13,6 +13,7 @@ describe "eval_inspect extension" do
|
|
13
13
|
[
|
14
14
|
# Objects with components where eval(inspect) == self
|
15
15
|
Sequel::SQL::AliasedExpression.new(:b, :a),
|
16
|
+
Sequel::SQL::AliasedExpression.new(:b, :a, [:c, :d]),
|
16
17
|
Sequel::SQL::CaseExpression.new({:b=>:a}, :c),
|
17
18
|
Sequel::SQL::CaseExpression.new({:b=>:a}, :c, :d),
|
18
19
|
Sequel::SQL::Cast.new(:a, :b),
|
@@ -28,9 +29,12 @@ describe "eval_inspect extension" do
|
|
28
29
|
Sequel::NOTNULL,
|
29
30
|
Sequel::SQL::Function.new(:a, :b, :c),
|
30
31
|
Sequel::SQL::Identifier.new(:a),
|
31
|
-
Sequel::SQL::JoinClause.new(:inner, :b
|
32
|
-
Sequel::SQL::JoinOnClause.new({:d=>:a}, :inner, :b
|
33
|
-
Sequel::SQL::JoinUsingClause.new([:a], :inner, :b
|
32
|
+
Sequel::SQL::JoinClause.new(:inner, :b),
|
33
|
+
Sequel::SQL::JoinOnClause.new({:d=>:a}, :inner, :b),
|
34
|
+
Sequel::SQL::JoinUsingClause.new([:a], :inner, :b),
|
35
|
+
Sequel::SQL::JoinClause.new(:inner, Sequel.as(:b, :c, [:d, :e])),
|
36
|
+
Sequel::SQL::JoinOnClause.new({:d=>:a}, :inner, Sequel.as(:b, :c, [:d, :e])),
|
37
|
+
Sequel::SQL::JoinUsingClause.new([:a], :inner, Sequel.as(:b, :c, [:d, :e])),
|
34
38
|
Sequel::SQL::PlaceholderLiteralString.new('? = ?', [:a, :b]),
|
35
39
|
Sequel::SQL::PlaceholderLiteralString.new(':a = :b', [{:a=>:b, :b=>42}]),
|
36
40
|
Sequel::SQL::OrderedExpression.new(:a),
|
@@ -40,7 +44,7 @@ describe "eval_inspect extension" do
|
|
40
44
|
Sequel::SQL::QualifiedIdentifier.new(:b, :a),
|
41
45
|
Sequel::SQL::Subscript.new(:a, [1, 2]),
|
42
46
|
Sequel::SQL::Window.new(:order=>:a, :partition=>:b),
|
43
|
-
Sequel::SQL::
|
47
|
+
Sequel::SQL::Function.new(:a, :b, :c).over(:order=>:a, :partition=>:b),
|
44
48
|
Sequel::SQL::Wrapper.new(:a),
|
45
49
|
|
46
50
|
# Objects with components where eval(inspect) != self
|
@@ -63,6 +63,10 @@ describe "Sequel::Postgres::ArrayOp" do
|
|
63
63
|
@db.literal(@a.unshift(:b)).should == "(b || a)"
|
64
64
|
end
|
65
65
|
|
66
|
+
it "#cardinality should use the cardinality function" do
|
67
|
+
@db.literal(@a.cardinality).should == "cardinality(a)"
|
68
|
+
end
|
69
|
+
|
66
70
|
it "#dims should use the array_dims function" do
|
67
71
|
@db.literal(@a.dims).should == "array_dims(a)"
|
68
72
|
end
|
@@ -95,6 +99,8 @@ describe "Sequel::Postgres::ArrayOp" do
|
|
95
99
|
|
96
100
|
it "#unnest should use the unnest function" do
|
97
101
|
@db.literal(@a.unnest).should == "unnest(a)"
|
102
|
+
@db.literal(@a.unnest(:b, :c)).should == "unnest(a, b, c)"
|
103
|
+
@db.literal(@a.unnest([1])).should == "unnest(a, ARRAY[1])"
|
98
104
|
end
|
99
105
|
|
100
106
|
it "#pg_array should return self" do
|
@@ -6,6 +6,7 @@ describe "Sequel::Postgres::JSONOp" do
|
|
6
6
|
before do
|
7
7
|
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
8
8
|
@j = Sequel.pg_json_op(:j)
|
9
|
+
@jb = Sequel.pg_jsonb_op(:j)
|
9
10
|
@l = proc{|o| @db.literal(o)}
|
10
11
|
end
|
11
12
|
|
@@ -48,77 +49,167 @@ describe "Sequel::Postgres::JSONOp" do
|
|
48
49
|
|
49
50
|
it "should have #array_length use the json_array_length function" do
|
50
51
|
@l[@j.array_length].should == "json_array_length(j)"
|
52
|
+
@l[@jb.array_length].should == "jsonb_array_length(j)"
|
51
53
|
end
|
52
54
|
|
53
55
|
it "should have #array_length return a numeric expression" do
|
54
56
|
@l[@j.array_length & 1].should == "(json_array_length(j) & 1)"
|
57
|
+
@l[@jb.array_length & 1].should == "(jsonb_array_length(j) & 1)"
|
55
58
|
end
|
56
59
|
|
57
60
|
it "should have #each use the json_each function" do
|
58
61
|
@l[@j.each].should == "json_each(j)"
|
62
|
+
@l[@jb.each].should == "jsonb_each(j)"
|
59
63
|
end
|
60
64
|
|
61
65
|
it "should have #each_text use the json_each_text function" do
|
62
66
|
@l[@j.each_text].should == "json_each_text(j)"
|
67
|
+
@l[@jb.each_text].should == "jsonb_each_text(j)"
|
63
68
|
end
|
64
69
|
|
65
70
|
it "should have #extract use the json_extract_path function" do
|
66
71
|
@l[@j.extract('a')].should == "json_extract_path(j, 'a')"
|
67
72
|
@l[@j.extract('a', 'b')].should == "json_extract_path(j, 'a', 'b')"
|
73
|
+
@l[@jb.extract('a')].should == "jsonb_extract_path(j, 'a')"
|
74
|
+
@l[@jb.extract('a', 'b')].should == "jsonb_extract_path(j, 'a', 'b')"
|
68
75
|
end
|
69
76
|
|
70
77
|
it "should have #extract return a JSONOp" do
|
71
78
|
@l[@j.extract('a')[1]].should == "(json_extract_path(j, 'a') -> 1)"
|
79
|
+
@l[@jb.extract('a')[1]].should == "(jsonb_extract_path(j, 'a') -> 1)"
|
72
80
|
end
|
73
81
|
|
74
82
|
it "should have #extract_text use the json_extract_path_text function" do
|
75
83
|
@l[@j.extract_text('a')].should == "json_extract_path_text(j, 'a')"
|
76
84
|
@l[@j.extract_text('a', 'b')].should == "json_extract_path_text(j, 'a', 'b')"
|
85
|
+
@l[@jb.extract_text('a')].should == "jsonb_extract_path_text(j, 'a')"
|
86
|
+
@l[@jb.extract_text('a', 'b')].should == "jsonb_extract_path_text(j, 'a', 'b')"
|
77
87
|
end
|
78
88
|
|
79
89
|
it "should have #extract_text return an SQL::StringExpression" do
|
80
90
|
@l[@j.extract_text('a') + 'a'].should == "(json_extract_path_text(j, 'a') || 'a')"
|
91
|
+
@l[@jb.extract_text('a') + 'a'].should == "(jsonb_extract_path_text(j, 'a') || 'a')"
|
81
92
|
end
|
82
93
|
|
83
94
|
it "should have #keys use the json_object_keys function" do
|
84
95
|
@l[@j.keys].should == "json_object_keys(j)"
|
96
|
+
@l[@jb.keys].should == "jsonb_object_keys(j)"
|
85
97
|
end
|
86
98
|
|
87
99
|
it "should have #array_elements use the json_array_elements function" do
|
88
100
|
@l[@j.array_elements].should == "json_array_elements(j)"
|
101
|
+
@l[@jb.array_elements].should == "jsonb_array_elements(j)"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should have #array_elements use the json_array_elements_text function" do
|
105
|
+
@l[@j.array_elements_text].should == "json_array_elements_text(j)"
|
106
|
+
@l[@jb.array_elements_text].should == "jsonb_array_elements_text(j)"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should have #typeof use the json_typeof function" do
|
110
|
+
@l[@j.typeof].should == "json_typeof(j)"
|
111
|
+
@l[@jb.typeof].should == "jsonb_typeof(j)"
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should have #to_record use the json_to_record function" do
|
115
|
+
@l[@j.to_record].should == "json_to_record(j, false)"
|
116
|
+
@l[@jb.to_record].should == "jsonb_to_record(j, false)"
|
117
|
+
@l[@j.to_record(true)].should == "json_to_record(j, true)"
|
118
|
+
@l[@jb.to_record(true)].should == "jsonb_to_record(j, true)"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should have #to_recordset use the json_to_recordsetfunction" do
|
122
|
+
@l[@j.to_recordset].should == "json_to_recordset(j, false)"
|
123
|
+
@l[@jb.to_recordset].should == "jsonb_to_recordset(j, false)"
|
124
|
+
@l[@j.to_recordset(true)].should == "json_to_recordset(j, true)"
|
125
|
+
@l[@jb.to_recordset(true)].should == "jsonb_to_recordset(j, true)"
|
89
126
|
end
|
90
127
|
|
91
128
|
it "should have #populate use the json_populate_record function" do
|
92
129
|
@l[@j.populate(:a)].should == "json_populate_record(a, j)"
|
130
|
+
@l[@jb.populate(:a)].should == "jsonb_populate_record(a, j)"
|
93
131
|
end
|
94
132
|
|
95
133
|
it "should have #populate_set use the json_populate_record function" do
|
96
134
|
@l[@j.populate_set(:a)].should == "json_populate_recordset(a, j)"
|
135
|
+
@l[@jb.populate_set(:a)].should == "jsonb_populate_recordset(a, j)"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "#contain_all should use the ?& operator" do
|
139
|
+
@l[@jb.contain_all(:h1)].should == "(j ?& h1)"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "#contain_all handle arrays" do
|
143
|
+
@l[@jb.contain_all(%w'h1')].should == "(j ?& ARRAY['h1'])"
|
144
|
+
end
|
145
|
+
|
146
|
+
it "#contain_any should use the ?| operator" do
|
147
|
+
@l[@jb.contain_any(:h1)].should == "(j ?| h1)"
|
148
|
+
end
|
149
|
+
|
150
|
+
it "#contain_any should handle arrays" do
|
151
|
+
@l[@jb.contain_any(%w'h1')].should == "(j ?| ARRAY['h1'])"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "#contains should use the @> operator" do
|
155
|
+
@l[@jb.contains(:h1)].should == "(j @> h1)"
|
156
|
+
end
|
157
|
+
|
158
|
+
it "#contains should handle hashes" do
|
159
|
+
@l[@jb.contains('a'=>'b')].should == "(j @> '{\"a\":\"b\"}'::jsonb)"
|
160
|
+
end
|
161
|
+
|
162
|
+
it "#contains should handle arrays" do
|
163
|
+
@l[@jb.contains([1, 2])].should == "(j @> '[1,2]'::jsonb)"
|
164
|
+
end
|
165
|
+
|
166
|
+
it "#contained_by should use the <@ operator" do
|
167
|
+
@l[@jb.contained_by(:h1)].should == "(j <@ h1)"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "#contained_by should handle hashes" do
|
171
|
+
@l[@jb.contained_by('a'=>'b')].should == "(j <@ '{\"a\":\"b\"}'::jsonb)"
|
172
|
+
end
|
173
|
+
|
174
|
+
it "#contained_by should handle arrays" do
|
175
|
+
@l[@jb.contained_by([1, 2])].should == "(j <@ '[1,2]'::jsonb)"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "#has_key? and aliases should use the ? operator" do
|
179
|
+
@l[@jb.has_key?('a')].should == "(j ? 'a')"
|
180
|
+
@l[@jb.include?('a')].should == "(j ? 'a')"
|
97
181
|
end
|
98
182
|
|
99
183
|
it "#pg_json should return self" do
|
100
184
|
@j.pg_json.should equal(@j)
|
185
|
+
@jb.pg_jsonb.should equal(@jb)
|
101
186
|
end
|
102
187
|
|
103
188
|
it "Sequel.pg_json_op should return arg for JSONOp" do
|
104
189
|
Sequel.pg_json_op(@j).should equal(@j)
|
190
|
+
Sequel.pg_jsonb_op(@jb).should equal(@jb)
|
105
191
|
end
|
106
192
|
|
107
193
|
it "should be able to turn expressions into json ops using pg_json" do
|
108
194
|
@db.literal(Sequel.qualify(:b, :a).pg_json[1]).should == "(b.a -> 1)"
|
109
195
|
@db.literal(Sequel.function(:a, :b).pg_json[1]).should == "(a(b) -> 1)"
|
196
|
+
@db.literal(Sequel.qualify(:b, :a).pg_jsonb[1]).should == "(b.a -> 1)"
|
197
|
+
@db.literal(Sequel.function(:a, :b).pg_jsonb[1]).should == "(a(b) -> 1)"
|
110
198
|
end
|
111
199
|
|
112
200
|
it "should be able to turn literal strings into json ops using pg_json" do
|
113
201
|
@db.literal(Sequel.lit('a').pg_json[1]).should == "(a -> 1)"
|
202
|
+
@db.literal(Sequel.lit('a').pg_jsonb[1]).should == "(a -> 1)"
|
114
203
|
end
|
115
204
|
|
116
205
|
it "should be able to turn symbols into json ops using Sequel.pg_json_op" do
|
117
206
|
@db.literal(Sequel.pg_json_op(:a)[1]).should == "(a -> 1)"
|
207
|
+
@db.literal(Sequel.pg_jsonb_op(:a)[1]).should == "(a -> 1)"
|
118
208
|
end
|
119
209
|
|
120
210
|
it "should be able to turn symbols into json ops using Sequel.pg_json" do
|
121
211
|
@db.literal(Sequel.pg_json(:a)[1]).should == "(a -> 1)"
|
212
|
+
@db.literal(Sequel.pg_jsonb(:a)[1]).should == "(a -> 1)"
|
122
213
|
end
|
123
214
|
|
124
215
|
it "should allow transforming JSONArray instances into ArrayOp instances" do
|
@@ -128,4 +219,12 @@ describe "Sequel::Postgres::JSONOp" do
|
|
128
219
|
it "should allow transforming JSONHash instances into ArrayOp instances" do
|
129
220
|
@db.literal(Sequel.pg_json('a'=>1).op['a']).should == "('{\"a\":1}'::json -> 'a')"
|
130
221
|
end
|
222
|
+
|
223
|
+
it "should allow transforming JSONBArray instances into ArrayOp instances" do
|
224
|
+
@db.literal(Sequel.pg_jsonb([1,2]).op[1]).should == "('[1,2]'::jsonb -> 1)"
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should allow transforming JSONBHash instances into ArrayOp instances" do
|
228
|
+
@db.literal(Sequel.pg_jsonb('a'=>1).op['a']).should == "('{\"a\":1}'::jsonb -> 'a')"
|
229
|
+
end
|
131
230
|
end
|