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
data/lib/sequel/version.rb
CHANGED
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
MAJOR = 4
|
4
4
|
# The minor version of Sequel. Bumped for every non-patch level
|
5
5
|
# release, generally around once a month.
|
6
|
-
MINOR =
|
6
|
+
MINOR = 11
|
7
7
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
8
8
|
# releases that fix regressions from previous versions.
|
9
9
|
TINY = 0
|
@@ -117,8 +117,8 @@ end
|
|
117
117
|
describe "PostgreSQL views" do
|
118
118
|
before do
|
119
119
|
@db = DB
|
120
|
-
@db.
|
121
|
-
@db.create_table
|
120
|
+
@db.drop_table?(:items, :cascade=>true)
|
121
|
+
@db.create_table(:items){Integer :number}
|
122
122
|
@db[:items].insert(10)
|
123
123
|
@db[:items].insert(20)
|
124
124
|
end
|
@@ -152,6 +152,15 @@ describe "PostgreSQL views" do
|
|
152
152
|
@db[:items_view].select_order_map(:number).should == [10, 15, 20]
|
153
153
|
end if DB.server_version >= 90300
|
154
154
|
|
155
|
+
specify "should support refreshing materialized views concurrently" do
|
156
|
+
@opts = {:materialized=>true}
|
157
|
+
@db.create_view(:items_view, @db[:items].where{number >= 10}, @opts)
|
158
|
+
@db.refresh_view(:items_view)
|
159
|
+
proc{@db.refresh_view(:items_view, :concurrently=>true)}.should raise_error(Sequel::DatabaseError)
|
160
|
+
@db.add_index :items_view, :number, :unique=>true
|
161
|
+
proc{@db.refresh_view(:items_view, :concurrently=>true)}.should_not raise_error
|
162
|
+
end if DB.server_version >= 90400
|
163
|
+
|
155
164
|
specify "should support :if_exists=>true for not raising an error if the view does not exist" do
|
156
165
|
proc{@db.drop_view(:items_view, :if_exists=>true)}.should_not raise_error
|
157
166
|
end
|
@@ -170,6 +179,14 @@ describe "A PostgreSQL database" do
|
|
170
179
|
@db.server_version.should > 70000
|
171
180
|
end
|
172
181
|
|
182
|
+
specify "should respect the :read_only option per-savepoint" do
|
183
|
+
proc{@db.transaction{@db.transaction(:savepoint=>true, :read_only=>true){@db[:public__testfk].insert}}}.should raise_error(Sequel::DatabaseError)
|
184
|
+
proc{@db.transaction(:auto_savepoint=>true, :read_only=>true){@db.transaction(:read_only=>false){@db[:public__testfk].insert}}}.should raise_error(Sequel::DatabaseError)
|
185
|
+
proc{@db.transaction{@db[:public__testfk].insert; @db.transaction(:savepoint=>true, :read_only=>true){@db[:public__testfk].all;}}}.should_not raise_error
|
186
|
+
proc{@db.transaction{@db.transaction(:savepoint=>true, :read_only=>true){}; @db[:public__testfk].insert}}.should_not raise_error
|
187
|
+
proc{@db.transaction{@db[:public__testfk].all; @db.transaction(:savepoint=>true, :read_only=>true){@db[:public__testfk].all;}}}.should_not raise_error
|
188
|
+
end
|
189
|
+
|
173
190
|
specify "should support disable_insert_returning" do
|
174
191
|
ds = @db[:public__testfk].disable_insert_returning
|
175
192
|
ds.delete
|
@@ -326,6 +343,22 @@ describe "A PostgreSQL dataset" do
|
|
326
343
|
@d.order(Sequel.asc(:value, :nulls=>:first), :name).reverse.select_map(:name).should == %w[bcd bcd abc]
|
327
344
|
end
|
328
345
|
|
346
|
+
specify "should support selecting from LATERAL functions" do
|
347
|
+
@d.from{[generate_series(1,3,1).as(:a), pow(:a, 2).lateral.as(:b)]}.select_map([:a, :b])== [[1, 1], [2, 4], [3, 9]]
|
348
|
+
end if DB.server_version >= 90300
|
349
|
+
|
350
|
+
specify "should support ordered-set and hypothetical-set aggregate functions" do
|
351
|
+
@d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{mode{}.within_group(:a)}.should == 1
|
352
|
+
end if DB.server_version >= 90400
|
353
|
+
|
354
|
+
specify "should support filtered aggregate functions" do
|
355
|
+
@d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{count(:a).filter(:a=>1)}.should == 2
|
356
|
+
end if DB.server_version >= 90400
|
357
|
+
|
358
|
+
specify "should support functions with ordinality" do
|
359
|
+
@d.from{generate_series(1,10,3).with_ordinality}.select_map([:generate_series, :ordinality]).should == [[1, 1], [4, 2], [7, 3], [10, 4]]
|
360
|
+
end if DB.server_version >= 90400
|
361
|
+
|
329
362
|
specify "#lock should lock tables and yield if a block is given" do
|
330
363
|
@d.lock('EXCLUSIVE'){@d.insert(:name=>'a')}
|
331
364
|
end
|
@@ -848,28 +881,14 @@ describe "A PostgreSQL database" do
|
|
848
881
|
|
849
882
|
specify "should support fulltext indexes and searching" do
|
850
883
|
@db.create_table(:posts){text :title; text :body; full_text_index [:title, :body]; full_text_index :title, :language => 'french', :index_type=>:gist}
|
851
|
-
check_sqls do
|
852
|
-
@db.sqls.should == [
|
853
|
-
%{CREATE TABLE "posts" ("title" text, "body" text)},
|
854
|
-
%{CREATE INDEX "posts_title_body_index" ON "posts" USING gin (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))))},
|
855
|
-
%{CREATE INDEX "posts_title_index" ON "posts" USING gist (to_tsvector('french'::regconfig, (COALESCE("title", ''))))}
|
856
|
-
]
|
857
|
-
end
|
858
884
|
|
859
885
|
@db[:posts].insert(:title=>'ruby rails', :body=>'yowsa')
|
860
886
|
@db[:posts].insert(:title=>'sequel', :body=>'ruby')
|
861
887
|
@db[:posts].insert(:title=>'ruby scooby', :body=>'x')
|
862
|
-
@db.sqls.clear
|
863
888
|
|
864
889
|
@db[:posts].full_text_search(:title, 'rails').all.should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
865
890
|
@db[:posts].full_text_search([:title, :body], ['yowsa', 'rails']).all.should == [:title=>'ruby rails', :body=>'yowsa']
|
866
891
|
@db[:posts].full_text_search(:title, 'scooby', :language => 'french').all.should == [{:title=>'ruby scooby', :body=>'x'}]
|
867
|
-
check_sqls do
|
868
|
-
@db.sqls.should == [
|
869
|
-
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('simple'::regconfig, 'rails'))},
|
870
|
-
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))) @@ to_tsquery('simple'::regconfig, 'yowsa | rails'))},
|
871
|
-
%{SELECT * FROM "posts" WHERE (to_tsvector('french'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('french'::regconfig, 'scooby'))}]
|
872
|
-
end
|
873
892
|
|
874
893
|
@db[:posts].full_text_search(:title, :$n).call(:select, :n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
875
894
|
@db[:posts].full_text_search(:title, :$n).prepare(:select, :fts_select).call(:n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
@@ -880,6 +899,13 @@ describe "A PostgreSQL database" do
|
|
880
899
|
@db[:posts].full_text_search(:title, 'jruby maglev', :phrase=>true).select_order_map(:title).should == ['ruby jruby maglev mri rubinius iron']
|
881
900
|
@db[:posts].full_text_search(:title, 'rubinius ruby', :plain=>true).select_order_map(:title).should == ['jruby rubinius ruby maglev mri iron', 'ruby jruby maglev mri rubinius iron']
|
882
901
|
@db[:posts].full_text_search(:title, 'jruby maglev', :plain=>true).select_order_map(:title).should == ['jruby rubinius ruby maglev mri iron', 'ruby jruby maglev mri rubinius iron']
|
902
|
+
|
903
|
+
@db[:posts].delete
|
904
|
+
t1 = "bork " * 1000 + "ruby sequel"
|
905
|
+
t2 = "ruby sequel " * 1000
|
906
|
+
@db[:posts].insert(:title=>t1)
|
907
|
+
@db[:posts].insert(:title=>t2)
|
908
|
+
@db[:posts].full_text_search(:title, 'ruby & sequel', :rank=>true).select_map(:title).should == [t1, t2]
|
883
909
|
end
|
884
910
|
|
885
911
|
specify "should support spatial indexes" do
|
@@ -2237,6 +2263,13 @@ describe 'PostgreSQL array handling' do
|
|
2237
2263
|
@ds.get(Sequel.pg_array(:i5).replace(1, 4).contains([1])).should == false
|
2238
2264
|
@ds.get(Sequel.pg_array(:i5).replace(1, 4).contains([4])).should == true
|
2239
2265
|
end
|
2266
|
+
if @db.server_version >= 90400
|
2267
|
+
@ds.get(Sequel.pg_array(:i).cardinality).should == 3
|
2268
|
+
@ds.get(Sequel.pg_array(:i4).cardinality).should == 4
|
2269
|
+
@ds.get(Sequel.pg_array(:i5).cardinality).should == 3
|
2270
|
+
|
2271
|
+
@ds.from{Sequel.pg_array([1,2,3]).op.unnest([4,5,6], [7,8]).as(:t1, [:a, :b, :c])}.select_order_map([:a, :b, :c]).should == [[1, 4, 7], [2, 5, 8], [3, 6, nil]]
|
2272
|
+
end
|
2240
2273
|
|
2241
2274
|
if @native
|
2242
2275
|
@ds.get(Sequel.pg_array(:i).push(4)).should == [1, 2, 3, 4]
|
@@ -2515,133 +2548,166 @@ describe 'PostgreSQL json type' do
|
|
2515
2548
|
@db.drop_table?(:items)
|
2516
2549
|
end
|
2517
2550
|
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
|
2526
|
-
|
2527
|
-
|
2528
|
-
|
2551
|
+
json_types = [:json]
|
2552
|
+
json_types << :jsonb if DB.server_version >= 90400
|
2553
|
+
json_types.each do |json_type|
|
2554
|
+
json_array_type = "#{json_type}[]"
|
2555
|
+
pg_json = lambda{|v| Sequel.send(:"pg_#{json_type}", v)}
|
2556
|
+
|
2557
|
+
specify 'insert and retrieve json values' do
|
2558
|
+
@db.create_table!(:items){column :j, json_type}
|
2559
|
+
@ds.insert(pg_json.call(@h))
|
2560
|
+
@ds.count.should == 1
|
2561
|
+
if @native
|
2562
|
+
rs = @ds.all
|
2563
|
+
v = rs.first[:j]
|
2564
|
+
v.should_not be_a_kind_of(Hash)
|
2565
|
+
v.to_hash.should be_a_kind_of(Hash)
|
2566
|
+
v.should == @h
|
2567
|
+
v.to_hash.should == @h
|
2568
|
+
@ds.delete
|
2569
|
+
@ds.insert(rs.first)
|
2570
|
+
@ds.all.should == rs
|
2571
|
+
end
|
2572
|
+
|
2529
2573
|
@ds.delete
|
2530
|
-
@ds.insert(
|
2531
|
-
@ds.
|
2574
|
+
@ds.insert(pg_json.call(@a))
|
2575
|
+
@ds.count.should == 1
|
2576
|
+
if @native
|
2577
|
+
rs = @ds.all
|
2578
|
+
v = rs.first[:j]
|
2579
|
+
v.should_not be_a_kind_of(Array)
|
2580
|
+
v.to_a.should be_a_kind_of(Array)
|
2581
|
+
v.should == @a
|
2582
|
+
v.to_a.should == @a
|
2583
|
+
@ds.delete
|
2584
|
+
@ds.insert(rs.first)
|
2585
|
+
@ds.all.should == rs
|
2586
|
+
end
|
2532
2587
|
end
|
2533
2588
|
|
2534
|
-
|
2535
|
-
|
2536
|
-
|
2537
|
-
|
2538
|
-
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
|
2543
|
-
|
2544
|
-
|
2545
|
-
|
2546
|
-
|
2589
|
+
specify 'insert and retrieve json[] values' do
|
2590
|
+
@db.create_table!(:items){column :j, json_array_type}
|
2591
|
+
j = Sequel.pg_array([pg_json.call('a'=>1), pg_json.call(['b', 2])])
|
2592
|
+
@ds.insert(j)
|
2593
|
+
@ds.count.should == 1
|
2594
|
+
if @native
|
2595
|
+
rs = @ds.all
|
2596
|
+
v = rs.first[:j]
|
2597
|
+
v.should_not be_a_kind_of(Array)
|
2598
|
+
v.to_a.should be_a_kind_of(Array)
|
2599
|
+
v.should == j
|
2600
|
+
v.to_a.should == j
|
2601
|
+
@ds.delete
|
2602
|
+
@ds.insert(rs.first)
|
2603
|
+
@ds.all.should == rs
|
2604
|
+
end
|
2547
2605
|
end
|
2548
|
-
end
|
2549
2606
|
|
2550
|
-
|
2551
|
-
|
2552
|
-
|
2553
|
-
|
2554
|
-
|
2555
|
-
|
2556
|
-
|
2557
|
-
|
2558
|
-
|
2559
|
-
v.to_a.should be_a_kind_of(Array)
|
2560
|
-
v.should == j
|
2561
|
-
v.to_a.should == j
|
2562
|
-
@ds.delete
|
2563
|
-
@ds.insert(rs.first)
|
2564
|
-
@ds.all.should == rs
|
2607
|
+
specify 'with models' do
|
2608
|
+
@db.create_table!(:items) do
|
2609
|
+
primary_key :id
|
2610
|
+
column :h, json_type
|
2611
|
+
end
|
2612
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
2613
|
+
c.plugin :pg_typecast_on_load, :h unless @native
|
2614
|
+
c.create(:h=>pg_json.call(@h)).h.should == @h
|
2615
|
+
c.create(:h=>pg_json.call(@a)).h.should == @a
|
2565
2616
|
end
|
2566
|
-
end
|
2567
2617
|
|
2568
|
-
|
2569
|
-
|
2570
|
-
|
2571
|
-
|
2572
|
-
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:first, :i=>Sequel.pg_json(@h)).should == {:i=>@h}
|
2573
|
-
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:first, :i=>Sequel.pg_json({})).should == nil
|
2574
|
-
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:delete, :i=>Sequel.pg_json(@h)).should == 1
|
2618
|
+
specify 'use json in bound variables' do
|
2619
|
+
@db.create_table!(:items){column :i, json_type}
|
2620
|
+
@ds.call(:insert, {:i=>pg_json.call(@h)}, {:i=>:$i})
|
2621
|
+
@ds.get(:i).should == @h
|
2575
2622
|
|
2576
|
-
|
2577
|
-
|
2578
|
-
|
2579
|
-
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:first, :i=>Sequel.pg_json([])).should == nil
|
2623
|
+
@ds.delete
|
2624
|
+
@ds.call(:insert, {:i=>pg_json.call('a'=>nil)}, {:i=>:$i})
|
2625
|
+
@ds.get(:i).should == pg_json.call('a'=>nil)
|
2580
2626
|
|
2581
|
-
|
2582
|
-
|
2583
|
-
|
2584
|
-
|
2585
|
-
|
2586
|
-
j = Sequel.pg_array([Sequel.pg_json('a'=>1), Sequel.pg_json(['b', 2])], :text)
|
2587
|
-
@ds.call(:insert, {:i=>j}, {:i=>:$i})
|
2588
|
-
@ds.get(:i).should == j
|
2589
|
-
@ds.filter(Sequel.cast(:i, 'text[]')=>:$i).call(:first, :i=>j).should == {:i=>j}
|
2590
|
-
@ds.filter(Sequel.cast(:i, 'text[]')=>:$i).call(:first, :i=>Sequel.pg_array([])).should == nil
|
2591
|
-
end if DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
2627
|
+
@db.create_table!(:items){column :i, json_array_type}
|
2628
|
+
j = Sequel.pg_array([pg_json.call('a'=>1), pg_json.call(['b', 2])], json_type)
|
2629
|
+
@ds.call(:insert, {:i=>j}, {:i=>:$i})
|
2630
|
+
@ds.get(:i).should == j
|
2631
|
+
end if DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
2592
2632
|
|
2593
|
-
|
2594
|
-
|
2595
|
-
|
2596
|
-
|
2597
|
-
|
2598
|
-
|
2599
|
-
|
2600
|
-
|
2601
|
-
|
2602
|
-
|
2603
|
-
|
2604
|
-
|
2605
|
-
|
2606
|
-
|
2607
|
-
|
2608
|
-
|
2609
|
-
|
2610
|
-
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
|
2615
|
-
|
2616
|
-
|
2617
|
-
|
2618
|
-
|
2619
|
-
|
2620
|
-
|
2621
|
-
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2635
|
-
|
2636
|
-
|
2637
|
-
|
2638
|
-
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2633
|
+
specify 'operations/functions with pg_json_ops' do
|
2634
|
+
Sequel.extension :pg_json_ops
|
2635
|
+
jo = pg_json.call('a'=>1, 'b'=>{'c'=>2, 'd'=>{'e'=>3}}).op
|
2636
|
+
ja = pg_json.call([2, 3, %w'a b']).op
|
2637
|
+
|
2638
|
+
@db.get(jo['a']).should == 1
|
2639
|
+
@db.get(jo['b']['c']).should == 2
|
2640
|
+
@db.get(jo[%w'b c']).should == 2
|
2641
|
+
@db.get(jo['b'].get_text(%w'd e')).should == "3"
|
2642
|
+
@db.get(jo[%w'b d'].get_text('e')).should == "3"
|
2643
|
+
@db.get(ja[1]).should == 3
|
2644
|
+
@db.get(ja[%w'2 1']).should == 'b'
|
2645
|
+
|
2646
|
+
@db.get(jo.extract('a')).should == 1
|
2647
|
+
@db.get(jo.extract('b').extract('c')).should == 2
|
2648
|
+
@db.get(jo.extract('b', 'c')).should == 2
|
2649
|
+
@db.get(jo.extract('b', 'd', 'e')).should == 3
|
2650
|
+
@db.get(jo.extract_text('b', 'd')).gsub(' ', '').should == '{"e":3}'
|
2651
|
+
@db.get(jo.extract_text('b', 'd', 'e')).should == '3'
|
2652
|
+
|
2653
|
+
@db.get(ja.array_length).should == 3
|
2654
|
+
@db.from(ja.array_elements.as(:v)).select_map(:v).should == [2, 3, %w'a b']
|
2655
|
+
|
2656
|
+
if DB.server_version >= 90400
|
2657
|
+
@db.get(jo.typeof).should == 'object'
|
2658
|
+
@db.get(ja.typeof).should == 'array'
|
2659
|
+
@db.from(ja.array_elements_text.as(:v)).select_map(:v).map{|s| s.gsub(' ', '')}.should == ['2', '3', '["a","b"]']
|
2660
|
+
@db.from(jo.to_record(true).as(:v, [Sequel.lit('a integer'), Sequel.lit('b text')])).select_map(:a).should == [1]
|
2661
|
+
@db.from(pg_json.call([{'a'=>1, 'b'=>1}]).op.to_recordset.as(:v, [Sequel.lit('a integer'), Sequel.lit('b integer')])).select_map(:a).should == [1]
|
2662
|
+
|
2663
|
+
if json_type == :jsonb
|
2664
|
+
@db.get(jo.has_key?('a')).should == true
|
2665
|
+
@db.get(jo.has_key?('c')).should == false
|
2666
|
+
@db.get(pg_json.call(['2', '3', %w'a b']).op.include?('2')).should == true
|
2667
|
+
@db.get(pg_json.call(['2', '3', %w'a b']).op.include?('4')).should == false
|
2668
|
+
|
2669
|
+
@db.get(jo.contain_all(['a', 'b'])).should == true
|
2670
|
+
@db.get(jo.contain_all(['a', 'c'])).should == false
|
2671
|
+
@db.get(jo.contain_all(['d', 'c'])).should == false
|
2672
|
+
@db.get(jo.contain_any(['a', 'b'])).should == true
|
2673
|
+
@db.get(jo.contain_any(['a', 'c'])).should == true
|
2674
|
+
@db.get(jo.contain_any(['d', 'c'])).should == false
|
2675
|
+
|
2676
|
+
@db.get(jo.contains(jo)).should == true
|
2677
|
+
@db.get(jo.contained_by(jo)).should == true
|
2678
|
+
@db.get(jo.contains('a'=>1)).should == true
|
2679
|
+
@db.get(jo.contained_by('a'=>1)).should == false
|
2680
|
+
@db.get(pg_json.call('a'=>1).op.contains(jo)).should == false
|
2681
|
+
@db.get(pg_json.call('a'=>1).op.contained_by(jo)).should == true
|
2682
|
+
|
2683
|
+
@db.get(ja.contains(ja)).should == true
|
2684
|
+
@db.get(ja.contained_by(ja)).should == true
|
2685
|
+
@db.get(ja.contains([2,3])).should == true
|
2686
|
+
@db.get(ja.contained_by([2,3])).should == false
|
2687
|
+
@db.get(pg_json.call([2,3]).op.contains(ja)).should == false
|
2688
|
+
@db.get(pg_json.call([2,3]).op.contained_by(ja)).should == true
|
2689
|
+
end
|
2690
|
+
end
|
2691
|
+
|
2692
|
+
@db.from(jo.keys.as(:k)).select_order_map(:k).should == %w'a b'
|
2693
|
+
@db.from(jo.each).select_order_map(:key).should == %w'a b'
|
2694
|
+
@db.from(jo.each).order(:key).select_map(:value).should == [1, {'c'=>2, 'd'=>{'e'=>3}}]
|
2695
|
+
@db.from(jo.each_text).select_order_map(:key).should == %w'a b'
|
2696
|
+
@db.from(jo.each_text).order(:key).where(:key=>'b').get(:value).gsub(' ', '').should =~ /\{"d":\{"e":3\},"c":2\}|\{"c":2,"d":\{"e":3\}\}/
|
2697
|
+
|
2698
|
+
Sequel.extension :pg_row_ops
|
2699
|
+
@db.create_table!(:items) do
|
2700
|
+
Integer :a
|
2701
|
+
String :b
|
2702
|
+
end
|
2703
|
+
j = Sequel.pg_json('a'=>1, 'b'=>'c').op
|
2704
|
+
@db.get(j.populate(Sequel.cast(nil, :items)).pg_row[:a]).should == 1
|
2705
|
+
@db.get(j.populate(Sequel.cast(nil, :items)).pg_row[:b]).should == 'c'
|
2706
|
+
j = Sequel.pg_json([{'a'=>1, 'b'=>'c'}, {'a'=>2, 'b'=>'d'}]).op
|
2707
|
+
@db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:a).should == [1, 2]
|
2708
|
+
@db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:b).should == %w'c d'
|
2709
|
+
end if DB.server_version >= 90300 && (DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc)
|
2710
|
+
end
|
2645
2711
|
end if DB.server_version >= 90200
|
2646
2712
|
|
2647
2713
|
describe 'PostgreSQL inet/cidr types' do
|
@@ -911,6 +911,12 @@ shared_examples_for "All connection pools classes" do
|
|
911
911
|
x = nil
|
912
912
|
@class.new(mock_db.call{123}, :after_connect=>proc{|c| x = [c, c]}).hold{}
|
913
913
|
x.should == [123, 123]
|
914
|
+
@class.new(mock_db.call{123}, :after_connect=>lambda{|c| x = [c, c]}).hold{}
|
915
|
+
x.should == [123, 123]
|
916
|
+
@class.new(mock_db.call{123}, :after_connect=>proc{|c, s| x = [c, s]}).hold{}
|
917
|
+
x.should == [123, :default]
|
918
|
+
@class.new(mock_db.call{123}, :after_connect=>lambda{|c, s| x = [c, s]}).hold{}
|
919
|
+
x.should == [123, :default]
|
914
920
|
end
|
915
921
|
|
916
922
|
specify "should raise a DatabaseConnectionError if the connection raises an exception" do
|
data/spec/core/database_spec.rb
CHANGED
@@ -2184,6 +2184,18 @@ describe "Database#supports_savepoints?" do
|
|
2184
2184
|
end
|
2185
2185
|
end
|
2186
2186
|
|
2187
|
+
describe "Database#supports_views_with_check_option?" do
|
2188
|
+
specify "should be false by default" do
|
2189
|
+
Sequel::Database.new.supports_views_with_check_option?.should == false
|
2190
|
+
end
|
2191
|
+
end
|
2192
|
+
|
2193
|
+
describe "Database#supports_views_with_local_check_option?" do
|
2194
|
+
specify "should be false by default" do
|
2195
|
+
Sequel::Database.new.supports_views_with_local_check_option?.should == false
|
2196
|
+
end
|
2197
|
+
end
|
2198
|
+
|
2187
2199
|
describe "Database#supports_savepoints_in_prepared_transactions?" do
|
2188
2200
|
specify "should be false by default" do
|
2189
2201
|
Sequel::Database.new.supports_savepoints_in_prepared_transactions?.should == false
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -870,6 +870,7 @@ describe "Dataset#as" do
|
|
870
870
|
specify "should set up an alias" do
|
871
871
|
dataset = Sequel.mock.dataset.from(:test)
|
872
872
|
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
873
|
+
dataset.select(dataset.limit(1).select(:name).as(:n, [:nm])).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n(nm) FROM test'
|
873
874
|
end
|
874
875
|
end
|
875
876
|
|
@@ -2046,6 +2047,10 @@ describe "Dataset#from_self" do
|
|
2046
2047
|
@ds.from_self(:alias=>:some_name).sql.should == 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name'
|
2047
2048
|
end
|
2048
2049
|
|
2050
|
+
specify "should use the user-specified column aliases" do
|
2051
|
+
@ds.from_self(:alias=>:some_name, :column_aliases=>[:c1, :c2]).sql.should == 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name(c1, c2)'
|
2052
|
+
end
|
2053
|
+
|
2049
2054
|
specify "should use the user-specified alias for joins" do
|
2050
2055
|
@ds.from_self(:alias=>:some_name).inner_join(:posts, :alias=>:name).sql.should == \
|
2051
2056
|
'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
|
@@ -2154,6 +2159,10 @@ describe "Dataset#join_table" do
|
|
2154
2159
|
@d.from('stats').join(Sequel.expr(:players).as(:p), {:id => :player_id}).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
2155
2160
|
end
|
2156
2161
|
|
2162
|
+
specify "should support aliased tables with an implicit column aliases" do
|
2163
|
+
@d.from('stats').join(Sequel.expr(:players).as(:p, [:c1, :c2]), {:id => :player_id}).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p"("c1", "c2") ON ("p"."id" = "stats"."player_id")'
|
2164
|
+
end
|
2165
|
+
|
2157
2166
|
specify "should support using an alias for the FROM when doing the first join with unqualified condition columns" do
|
2158
2167
|
@d.from(Sequel.as(:foo, :f)).join_table(:inner, :bar, :id => :bar_id).sql.should == 'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
2159
2168
|
end
|
@@ -2894,11 +2903,32 @@ describe "Dataset#import" do
|
|
2894
2903
|
'COMMIT']
|
2895
2904
|
end
|
2896
2905
|
|
2906
|
+
specify "should slice based on the default_import_slice option" do
|
2907
|
+
def @ds.default_import_slice; 2 end
|
2908
|
+
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]])
|
2909
|
+
@db.sqls.should == ['BEGIN',
|
2910
|
+
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2911
|
+
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2912
|
+
'COMMIT',
|
2913
|
+
'BEGIN',
|
2914
|
+
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2915
|
+
'COMMIT']
|
2916
|
+
|
2917
|
+
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice=>nil)
|
2918
|
+
@db.sqls.should == ['BEGIN',
|
2919
|
+
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2920
|
+
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2921
|
+
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2922
|
+
'COMMIT']
|
2923
|
+
end
|
2924
|
+
|
2897
2925
|
specify "should accept a columns array and a values array with :commit_every option" do
|
2898
|
-
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every =>
|
2926
|
+
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 2)
|
2899
2927
|
@db.sqls.should == ['BEGIN',
|
2900
2928
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2901
2929
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2930
|
+
'COMMIT',
|
2931
|
+
'BEGIN',
|
2902
2932
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2903
2933
|
'COMMIT']
|
2904
2934
|
end
|
@@ -2920,6 +2950,14 @@ describe "Dataset#import" do
|
|
2920
2950
|
@db.sqls.should == ['BEGIN',
|
2921
2951
|
"INSERT INTO items (x, y) VALUES (1, 2), (3, 4), (5, 6)",
|
2922
2952
|
'COMMIT']
|
2953
|
+
|
2954
|
+
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice=>2)
|
2955
|
+
@db.sqls.should == ['BEGIN',
|
2956
|
+
"INSERT INTO items (x, y) VALUES (1, 2), (3, 4)",
|
2957
|
+
'COMMIT',
|
2958
|
+
'BEGIN',
|
2959
|
+
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2960
|
+
'COMMIT']
|
2923
2961
|
end
|
2924
2962
|
|
2925
2963
|
specify "should use correct sql for :union strategy" do
|
@@ -2928,6 +2966,14 @@ describe "Dataset#import" do
|
|
2928
2966
|
@db.sqls.should == ['BEGIN',
|
2929
2967
|
"INSERT INTO items (x, y) SELECT 1, 2 UNION ALL SELECT 3, 4 UNION ALL SELECT 5, 6",
|
2930
2968
|
'COMMIT']
|
2969
|
+
|
2970
|
+
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice=>2)
|
2971
|
+
@db.sqls.should == ['BEGIN',
|
2972
|
+
"INSERT INTO items (x, y) SELECT 1, 2 UNION ALL SELECT 3, 4",
|
2973
|
+
'COMMIT',
|
2974
|
+
'BEGIN',
|
2975
|
+
"INSERT INTO items (x, y) SELECT 5, 6",
|
2976
|
+
'COMMIT']
|
2931
2977
|
end
|
2932
2978
|
|
2933
2979
|
specify "should use correct sql for :union strategy when FROM is required" do
|
@@ -2937,6 +2983,14 @@ describe "Dataset#import" do
|
|
2937
2983
|
@db.sqls.should == ['BEGIN',
|
2938
2984
|
"INSERT INTO items (x, y) SELECT 1, 2 FROM foo UNION ALL SELECT 3, 4 FROM foo UNION ALL SELECT 5, 6 FROM foo",
|
2939
2985
|
'COMMIT']
|
2986
|
+
|
2987
|
+
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice=>2)
|
2988
|
+
@db.sqls.should == ['BEGIN',
|
2989
|
+
"INSERT INTO items (x, y) SELECT 1, 2 FROM foo UNION ALL SELECT 3, 4 FROM foo",
|
2990
|
+
'COMMIT',
|
2991
|
+
'BEGIN',
|
2992
|
+
"INSERT INTO items (x, y) SELECT 5, 6 FROM foo",
|
2993
|
+
'COMMIT']
|
2940
2994
|
end
|
2941
2995
|
end
|
2942
2996
|
|
@@ -3622,6 +3676,7 @@ describe "Sequel::Dataset#qualify" do
|
|
3622
3676
|
|
3623
3677
|
specify "should handle SQL::AliasedExpressions" do
|
3624
3678
|
@ds.select(Sequel.expr(:a).as(:b)).qualify.sql.should == 'SELECT t.a AS b FROM t'
|
3679
|
+
@ds.select(Sequel.expr(:a).as(:b, [:c, :d])).qualify.sql.should == 'SELECT t.a AS b(c, d) FROM t'
|
3625
3680
|
end
|
3626
3681
|
|
3627
3682
|
specify "should handle SQL::CaseExpressions" do
|
@@ -3660,7 +3715,7 @@ describe "Sequel::Dataset#qualify" do
|
|
3660
3715
|
@ds.filter(Sequel::SQL::Wrapper.new(:a)).qualify.sql.should == 'SELECT t.* FROM t WHERE t.a'
|
3661
3716
|
end
|
3662
3717
|
|
3663
|
-
specify "should handle SQL::
|
3718
|
+
specify "should handle SQL::Functions with windows" do
|
3664
3719
|
meta_def(@ds, :supports_window_functions?){true}
|
3665
3720
|
@ds.select{sum(:a).over(:partition=>:b, :order=>:c)}.qualify.sql.should == 'SELECT sum(t.a) OVER (PARTITION BY t.b ORDER BY t.c) FROM t'
|
3666
3721
|
end
|
@@ -4345,7 +4400,7 @@ describe "Custom ASTTransformer" do
|
|
4345
4400
|
end.new
|
4346
4401
|
ds = Sequel.mock.dataset.from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
4347
4402
|
ds.sql.should == 'SELECT * FROM t CROSS JOIN a AS g INNER JOIN b AS h USING (c) INNER JOIN d AS i ON (i.e = h.f)'
|
4348
|
-
ds.clone(:from=>c.transform(ds.opts[:from]), :join=>c.transform(ds.opts[:join])).sql.should == 'SELECT * FROM tt CROSS JOIN aa AS
|
4403
|
+
ds.clone(:from=>c.transform(ds.opts[:from]), :join=>c.transform(ds.opts[:join])).sql.should == 'SELECT * FROM tt CROSS JOIN aa AS g INNER JOIN bb AS h USING (cc) INNER JOIN dd AS i ON (ii.ee = hh.ff)'
|
4349
4404
|
end
|
4350
4405
|
end
|
4351
4406
|
|