sequel 3.33.0 → 3.34.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.
- data/CHANGELOG +140 -0
- data/Rakefile +7 -0
- data/bin/sequel +22 -2
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/mass_assignment.rdoc +3 -1
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +23 -3
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/schema_modification.rdoc +18 -2
- data/doc/virtual_rows.rdoc +49 -0
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/ibmdb.rb +9 -4
- data/lib/sequel/adapters/jdbc.rb +9 -4
- data/lib/sequel/adapters/jdbc/h2.rb +8 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
- data/lib/sequel/adapters/mock.rb +24 -3
- data/lib/sequel/adapters/mysql.rb +29 -50
- data/lib/sequel/adapters/mysql2.rb +13 -28
- data/lib/sequel/adapters/oracle.rb +8 -2
- data/lib/sequel/adapters/postgres.rb +115 -20
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +14 -3
- data/lib/sequel/adapters/shared/mysql.rb +59 -11
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +127 -30
- data/lib/sequel/adapters/shared/sqlite.rb +55 -38
- data/lib/sequel/adapters/sqlite.rb +9 -3
- data/lib/sequel/adapters/swift.rb +2 -2
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +10 -0
- data/lib/sequel/ast_transformer.rb +4 -0
- data/lib/sequel/connection_pool.rb +8 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -0
- data/lib/sequel/core.rb +24 -3
- data/lib/sequel/database/connecting.rb +24 -14
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +16 -25
- data/lib/sequel/database/query.rb +20 -2
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +120 -23
- data/lib/sequel/dataset/actions.rb +91 -18
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -2
- data/lib/sequel/dataset/sql.rb +68 -51
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +227 -31
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +11 -2
- data/lib/sequel/model/associations.rb +35 -7
- data/lib/sequel/model/base.rb +159 -36
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +11 -3
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +4 -3
- data/lib/sequel/plugins/prepared_statements.rb +3 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +417 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +12 -15
- data/spec/adapters/mysql_spec.rb +81 -23
- data/spec/adapters/postgres_spec.rb +444 -77
- data/spec/adapters/spec_helper.rb +2 -0
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +85 -0
- data/spec/core/database_spec.rb +29 -5
- data/spec/core/dataset_spec.rb +171 -3
- data/spec/core/expression_filters_spec.rb +364 -0
- data/spec/core/mock_adapter_spec.rb +17 -3
- data/spec/core/schema_spec.rb +133 -0
- data/spec/extensions/association_dependencies_spec.rb +13 -13
- data/spec/extensions/caching_spec.rb +26 -3
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +5 -2
- data/spec/extensions/identity_map_spec.rb +17 -0
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +2 -2
- data/spec/extensions/list_spec.rb +4 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +6 -2
- data/spec/extensions/nested_attributes_spec.rb +20 -0
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_spec.rb +4 -0
- data/spec/extensions/pretty_table_spec.rb +6 -0
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +231 -11
- data/spec/extensions/schema_spec.rb +14 -2
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/sharding_spec.rb +6 -6
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +2 -1
- data/spec/extensions/sql_expr_spec.rb +28 -19
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +9 -1
- data/spec/integration/associations_test.rb +6 -6
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +89 -26
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +85 -22
- data/spec/integration/prepared_statement_test.rb +28 -8
- data/spec/integration/schema_test.rb +78 -7
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +4 -6
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +94 -8
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/hooks_spec.rb +2 -2
- data/spec/model/model_spec.rb +19 -7
- data/spec/model/record_spec.rb +135 -58
- data/spec/model/spec_helper.rb +1 -0
- metadata +35 -7
data/lib/sequel/version.rb
CHANGED
|
@@ -3,7 +3,7 @@ module Sequel
|
|
|
3
3
|
MAJOR = 3
|
|
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 = 34
|
|
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
|
data/spec/adapters/mssql_spec.rb
CHANGED
|
@@ -67,10 +67,10 @@ end
|
|
|
67
67
|
describe "MSSQL full_text_search" do
|
|
68
68
|
before do
|
|
69
69
|
@db = MSSQL_DB
|
|
70
|
-
@db.drop_table(:posts)
|
|
70
|
+
@db.drop_table?(:posts)
|
|
71
71
|
end
|
|
72
72
|
after do
|
|
73
|
-
@db.drop_table(:posts)
|
|
73
|
+
@db.drop_table?(:posts)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
specify "should support fulltext indexes and full_text_search" do
|
|
@@ -109,8 +109,7 @@ describe "MSSQL Dataset#output" do
|
|
|
109
109
|
@ds = @db[:items]
|
|
110
110
|
end
|
|
111
111
|
after do
|
|
112
|
-
@db.drop_table(:items)
|
|
113
|
-
@db.drop_table(:out)
|
|
112
|
+
@db.drop_table?(:items, :out)
|
|
114
113
|
end
|
|
115
114
|
|
|
116
115
|
specify "should format OUTPUT clauses without INTO for DELETE statements" do
|
|
@@ -256,7 +255,7 @@ describe "MSSQL::Dataset#import" do
|
|
|
256
255
|
@ds = @db[:test]
|
|
257
256
|
end
|
|
258
257
|
after do
|
|
259
|
-
@db.drop_table(:test)
|
|
258
|
+
@db.drop_table?(:test)
|
|
260
259
|
end
|
|
261
260
|
|
|
262
261
|
specify "#import should work correctly with an arbitrary output value" do
|
|
@@ -291,7 +290,7 @@ describe "Offset support" do
|
|
|
291
290
|
@ds.import [:id, :parent_id], [[1,nil],[2,nil],[3,1],[4,1],[5,3],[6,5]]
|
|
292
291
|
end
|
|
293
292
|
after do
|
|
294
|
-
@db.drop_table(:i)
|
|
293
|
+
@db.drop_table?(:i)
|
|
295
294
|
end
|
|
296
295
|
|
|
297
296
|
specify "should return correct rows" do
|
|
@@ -314,8 +313,7 @@ describe "Common Table Expressions" do
|
|
|
314
313
|
@ds.import [:id, :parent_id], [[1,nil],[2,nil],[3,1],[4,1],[5,3],[6,5]]
|
|
315
314
|
end
|
|
316
315
|
after do
|
|
317
|
-
@db.drop_table(:i1)
|
|
318
|
-
@db.drop_table(:i2)
|
|
316
|
+
@db.drop_table?(:i1, :i2)
|
|
319
317
|
end
|
|
320
318
|
|
|
321
319
|
specify "using #with should be able to update" do
|
|
@@ -385,7 +383,7 @@ describe "MSSSQL::Dataset#insert" do
|
|
|
385
383
|
@ds = @db[:test5]
|
|
386
384
|
end
|
|
387
385
|
after do
|
|
388
|
-
@db.drop_table(:test5)
|
|
386
|
+
@db.drop_table?(:test5)
|
|
389
387
|
end
|
|
390
388
|
|
|
391
389
|
specify "should have insert_select return nil if disable_insert_output is used" do
|
|
@@ -424,8 +422,7 @@ describe "MSSSQL::Dataset#into" do
|
|
|
424
422
|
@db[:t].insert(:id => 1, :value => "test")
|
|
425
423
|
@db << @db[:t].into(:new).select_sql
|
|
426
424
|
@db[:new].all.should == [{:id => 1, :value => "test"}]
|
|
427
|
-
@db.drop_table(:t)
|
|
428
|
-
@db.drop_table(:new)
|
|
425
|
+
@db.drop_table?(:t, :new)
|
|
429
426
|
end
|
|
430
427
|
end
|
|
431
428
|
|
|
@@ -434,7 +431,7 @@ describe "A MSSQL database" do
|
|
|
434
431
|
@db = MSSQL_DB
|
|
435
432
|
end
|
|
436
433
|
after do
|
|
437
|
-
@db.drop_table(:a)
|
|
434
|
+
@db.drop_table?(:a)
|
|
438
435
|
end
|
|
439
436
|
|
|
440
437
|
specify "should handle many existing types for set_column_allow_null" do
|
|
@@ -461,7 +458,7 @@ describe "MSSQL::Database#rename_table" do
|
|
|
461
458
|
MSSQL_DB.create_table! :'foo bar' do
|
|
462
459
|
text :name
|
|
463
460
|
end
|
|
464
|
-
MSSQL_DB.drop_table :baz
|
|
461
|
+
MSSQL_DB.drop_table? :baz
|
|
465
462
|
proc { MSSQL_DB.rename_table 'foo bar', 'baz' }.should_not raise_error
|
|
466
463
|
end
|
|
467
464
|
|
|
@@ -501,7 +498,7 @@ describe "MSSQL::Database#mssql_unicode_strings = false" do
|
|
|
501
498
|
MSSQL_DB.mssql_unicode_strings = false
|
|
502
499
|
end
|
|
503
500
|
after do
|
|
504
|
-
MSSQL_DB.drop_table(:items)
|
|
501
|
+
MSSQL_DB.drop_table?(:items)
|
|
505
502
|
MSSQL_DB.mssql_unicode_strings = true
|
|
506
503
|
end
|
|
507
504
|
|
|
@@ -535,7 +532,7 @@ describe "A MSSQL database adds index with include" do
|
|
|
535
532
|
end
|
|
536
533
|
|
|
537
534
|
after :all do
|
|
538
|
-
@db.drop_table @table_name
|
|
535
|
+
@db.drop_table? @table_name
|
|
539
536
|
end
|
|
540
537
|
|
|
541
538
|
cspecify "should be able add index with include" do
|
data/spec/adapters/mysql_spec.rb
CHANGED
|
@@ -26,9 +26,7 @@ def logger.method_missing(m, msg)
|
|
|
26
26
|
MYSQL_DB.sqls << msg
|
|
27
27
|
end
|
|
28
28
|
MYSQL_DB.loggers = [logger]
|
|
29
|
-
MYSQL_DB.drop_table(:items
|
|
30
|
-
MYSQL_DB.drop_table(:dolls) rescue nil
|
|
31
|
-
MYSQL_DB.drop_table(:booltest) rescue nil
|
|
29
|
+
MYSQL_DB.drop_table?(:items, :dolls, :booltest)
|
|
32
30
|
|
|
33
31
|
SQL_BEGIN = 'BEGIN'
|
|
34
32
|
SQL_ROLLBACK = 'ROLLBACK'
|
|
@@ -40,7 +38,7 @@ describe "MySQL", '#create_table' do
|
|
|
40
38
|
MYSQL_DB.sqls.clear
|
|
41
39
|
end
|
|
42
40
|
after do
|
|
43
|
-
@db.drop_table(:dolls)
|
|
41
|
+
@db.drop_table?(:dolls)
|
|
44
42
|
end
|
|
45
43
|
|
|
46
44
|
specify "should allow to specify options for MySQL" do
|
|
@@ -83,7 +81,7 @@ describe "MySQL", '#create_table' do
|
|
|
83
81
|
@db.schema(:dolls).map{|k, v| v[:auto_increment]}.should == [nil, nil, true]
|
|
84
82
|
end
|
|
85
83
|
|
|
86
|
-
|
|
84
|
+
cspecify "should support collate with various other column options", :swift do
|
|
87
85
|
@db.create_table!(:dolls){ String :name, :size=>128, :collate=>:utf8_bin, :default=>'foo', :null=>false, :unique=>true}
|
|
88
86
|
@db[:dolls].insert
|
|
89
87
|
@db[:dolls].select_map(:name).should == ["foo"]
|
|
@@ -113,7 +111,7 @@ if MYSQL_DB.adapter_scheme == :mysql
|
|
|
113
111
|
end
|
|
114
112
|
after do
|
|
115
113
|
@db.convert_tinyint_to_bool = true
|
|
116
|
-
@db.drop_table(:booltest)
|
|
114
|
+
@db.drop_table?(:booltest)
|
|
117
115
|
end
|
|
118
116
|
|
|
119
117
|
specify "should consider tinyint(1) datatypes as boolean if set, but not larger tinyints" do
|
|
@@ -161,7 +159,7 @@ describe "A MySQL dataset" do
|
|
|
161
159
|
MYSQL_DB.sqls.clear
|
|
162
160
|
end
|
|
163
161
|
after do
|
|
164
|
-
MYSQL_DB.drop_table(:items)
|
|
162
|
+
MYSQL_DB.drop_table?(:items)
|
|
165
163
|
end
|
|
166
164
|
|
|
167
165
|
specify "should quote columns and tables using back-ticks if quoting identifiers" do
|
|
@@ -241,6 +239,12 @@ describe "A MySQL dataset" do
|
|
|
241
239
|
@d.filter(:name => /^bc/).count.should == 1
|
|
242
240
|
end
|
|
243
241
|
|
|
242
|
+
specify "should have explain output" do
|
|
243
|
+
@d.explain.should be_a_kind_of(String)
|
|
244
|
+
@d.explain(:extended=>true).should be_a_kind_of(String)
|
|
245
|
+
@d.explain.should_not == @d.explain(:extended=>true)
|
|
246
|
+
end
|
|
247
|
+
|
|
244
248
|
specify "should correctly literalize strings with comment backslashes in them" do
|
|
245
249
|
@d.delete
|
|
246
250
|
proc {@d << {:name => ':\\'}}.should_not raise_error
|
|
@@ -285,7 +289,7 @@ describe "Dataset#distinct" do
|
|
|
285
289
|
@ds = @db[:a]
|
|
286
290
|
end
|
|
287
291
|
after do
|
|
288
|
-
@db.drop_table(:a)
|
|
292
|
+
@db.drop_table?(:a)
|
|
289
293
|
end
|
|
290
294
|
|
|
291
295
|
it "#distinct with arguments should return results distinct on those arguments" do
|
|
@@ -450,12 +454,12 @@ describe "A MySQL database with table options" do
|
|
|
450
454
|
Sequel::MySQL.default_collate = 'utf8_general_ci'
|
|
451
455
|
|
|
452
456
|
@db = MYSQL_DB
|
|
453
|
-
@db.drop_table(:items)
|
|
457
|
+
@db.drop_table?(:items)
|
|
454
458
|
|
|
455
459
|
MYSQL_DB.sqls.clear
|
|
456
460
|
end
|
|
457
461
|
after do
|
|
458
|
-
@db.drop_table(:items)
|
|
462
|
+
@db.drop_table?(:items)
|
|
459
463
|
|
|
460
464
|
Sequel::MySQL.default_engine = nil
|
|
461
465
|
Sequel::MySQL.default_charset = nil
|
|
@@ -481,12 +485,11 @@ end
|
|
|
481
485
|
describe "A MySQL database" do
|
|
482
486
|
before do
|
|
483
487
|
@db = MYSQL_DB
|
|
484
|
-
@db.drop_table(:items)
|
|
488
|
+
@db.drop_table?(:items)
|
|
485
489
|
MYSQL_DB.sqls.clear
|
|
486
490
|
end
|
|
487
491
|
after do
|
|
488
|
-
@db.drop_table(:items)
|
|
489
|
-
@db.drop_table(:users) rescue nil
|
|
492
|
+
@db.drop_table?(:items, :users)
|
|
490
493
|
end
|
|
491
494
|
|
|
492
495
|
specify "should support defaults for boolean columns" do
|
|
@@ -601,8 +604,7 @@ end
|
|
|
601
604
|
|
|
602
605
|
describe "MySQL foreign key support" do
|
|
603
606
|
after do
|
|
604
|
-
MYSQL_DB.drop_table(:testfk)
|
|
605
|
-
MYSQL_DB.drop_table(:testpk) rescue nil
|
|
607
|
+
MYSQL_DB.drop_table?(:testfk, :testpk)
|
|
606
608
|
end
|
|
607
609
|
|
|
608
610
|
specify "should create table without :key" do
|
|
@@ -674,11 +676,11 @@ end
|
|
|
674
676
|
describe "A MySQL database" do
|
|
675
677
|
before do
|
|
676
678
|
@db = MYSQL_DB
|
|
677
|
-
@db.drop_table(:posts)
|
|
679
|
+
@db.drop_table?(:posts)
|
|
678
680
|
@db.sqls.clear
|
|
679
681
|
end
|
|
680
682
|
after do
|
|
681
|
-
@db.drop_table(:posts)
|
|
683
|
+
@db.drop_table?(:posts)
|
|
682
684
|
end
|
|
683
685
|
|
|
684
686
|
specify "should support fulltext indexes and full_text_search" do
|
|
@@ -750,7 +752,7 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
|
750
752
|
MYSQL_DB.sqls.clear
|
|
751
753
|
end
|
|
752
754
|
after do
|
|
753
|
-
MYSQL_DB.drop_table(:items)
|
|
755
|
+
MYSQL_DB.drop_table?(:items)
|
|
754
756
|
end
|
|
755
757
|
|
|
756
758
|
specify "#insert should insert record with default values when no arguments given" do
|
|
@@ -786,6 +788,62 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
|
786
788
|
@d.all.should == [{:name => 'abc', :value => 6}, {:name => 'def', :value => 2}]
|
|
787
789
|
end
|
|
788
790
|
|
|
791
|
+
specify "#multi_replace should insert multiple records in a single statement" do
|
|
792
|
+
@d.multi_replace([{:name => 'abc'}, {:name => 'def'}])
|
|
793
|
+
|
|
794
|
+
MYSQL_DB.sqls.should == [
|
|
795
|
+
SQL_BEGIN,
|
|
796
|
+
"REPLACE INTO `items` (`name`) VALUES ('abc'), ('def')",
|
|
797
|
+
SQL_COMMIT
|
|
798
|
+
]
|
|
799
|
+
|
|
800
|
+
@d.all.should == [
|
|
801
|
+
{:name => 'abc', :value => nil}, {:name => 'def', :value => nil}
|
|
802
|
+
]
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
specify "#multi_replace should split the list of records into batches if :commit_every option is given" do
|
|
806
|
+
@d.multi_replace([{:value => 1}, {:value => 2}, {:value => 3}, {:value => 4}],
|
|
807
|
+
:commit_every => 2)
|
|
808
|
+
|
|
809
|
+
MYSQL_DB.sqls.should == [
|
|
810
|
+
SQL_BEGIN,
|
|
811
|
+
"REPLACE INTO `items` (`value`) VALUES (1), (2)",
|
|
812
|
+
SQL_COMMIT,
|
|
813
|
+
SQL_BEGIN,
|
|
814
|
+
"REPLACE INTO `items` (`value`) VALUES (3), (4)",
|
|
815
|
+
SQL_COMMIT
|
|
816
|
+
]
|
|
817
|
+
|
|
818
|
+
@d.all.should == [
|
|
819
|
+
{:name => nil, :value => 1},
|
|
820
|
+
{:name => nil, :value => 2},
|
|
821
|
+
{:name => nil, :value => 3},
|
|
822
|
+
{:name => nil, :value => 4}
|
|
823
|
+
]
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
specify "#multi_replace should split the list of records into batches if :slice option is given" do
|
|
827
|
+
@d.multi_replace([{:value => 1}, {:value => 2}, {:value => 3}, {:value => 4}],
|
|
828
|
+
:slice => 2)
|
|
829
|
+
|
|
830
|
+
MYSQL_DB.sqls.should == [
|
|
831
|
+
SQL_BEGIN,
|
|
832
|
+
"REPLACE INTO `items` (`value`) VALUES (1), (2)",
|
|
833
|
+
SQL_COMMIT,
|
|
834
|
+
SQL_BEGIN,
|
|
835
|
+
"REPLACE INTO `items` (`value`) VALUES (3), (4)",
|
|
836
|
+
SQL_COMMIT
|
|
837
|
+
]
|
|
838
|
+
|
|
839
|
+
@d.all.should == [
|
|
840
|
+
{:name => nil, :value => 1},
|
|
841
|
+
{:name => nil, :value => 2},
|
|
842
|
+
{:name => nil, :value => 3},
|
|
843
|
+
{:name => nil, :value => 4}
|
|
844
|
+
]
|
|
845
|
+
end
|
|
846
|
+
|
|
789
847
|
specify "#multi_insert should insert multiple records in a single statement" do
|
|
790
848
|
@d.multi_insert([{:name => 'abc'}, {:name => 'def'}])
|
|
791
849
|
|
|
@@ -916,7 +974,7 @@ describe "MySQL::Dataset#update and related methods" do
|
|
|
916
974
|
@d = MYSQL_DB[:items]
|
|
917
975
|
end
|
|
918
976
|
after do
|
|
919
|
-
MYSQL_DB.drop_table(:items)
|
|
977
|
+
MYSQL_DB.drop_table?(:items)
|
|
920
978
|
end
|
|
921
979
|
|
|
922
980
|
specify "#update_ignore should not raise error where normal update would fail" do
|
|
@@ -937,7 +995,7 @@ describe "MySQL::Dataset#replace" do
|
|
|
937
995
|
MYSQL_DB.sqls.clear
|
|
938
996
|
end
|
|
939
997
|
after do
|
|
940
|
-
MYSQL_DB.drop_table(:items)
|
|
998
|
+
MYSQL_DB.drop_table?(:items)
|
|
941
999
|
end
|
|
942
1000
|
|
|
943
1001
|
specify "should use default values if they exist" do
|
|
@@ -1005,7 +1063,7 @@ describe "MySQL::Dataset#calc_found_rows" do
|
|
|
1005
1063
|
MYSQL_DB.create_table!(:items){Integer :a}
|
|
1006
1064
|
end
|
|
1007
1065
|
after do
|
|
1008
|
-
MYSQL_DB.drop_table(:items)
|
|
1066
|
+
MYSQL_DB.drop_table?(:items)
|
|
1009
1067
|
end
|
|
1010
1068
|
|
|
1011
1069
|
specify "should add the SQL_CALC_FOUND_ROWS keyword when selecting" do
|
|
@@ -1035,7 +1093,7 @@ if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc or MYSQ
|
|
|
1035
1093
|
MYSQL_DB.sqls.clear
|
|
1036
1094
|
end
|
|
1037
1095
|
after do
|
|
1038
|
-
MYSQL_DB.drop_table(:items)
|
|
1096
|
+
MYSQL_DB.drop_table?(:items)
|
|
1039
1097
|
MYSQL_DB.execute('DROP PROCEDURE test_sproc')
|
|
1040
1098
|
end
|
|
1041
1099
|
|
|
@@ -1126,7 +1184,7 @@ if MYSQL_DB.adapter_scheme == :mysql
|
|
|
1126
1184
|
MYSQL_DB[:b].insert(25)
|
|
1127
1185
|
end
|
|
1128
1186
|
after do
|
|
1129
|
-
MYSQL_DB.drop_table(:a, :b)
|
|
1187
|
+
MYSQL_DB.drop_table?(:a, :b)
|
|
1130
1188
|
end
|
|
1131
1189
|
|
|
1132
1190
|
specify "should combine all results by default" do
|
|
@@ -6,6 +6,14 @@ unless defined?(POSTGRES_DB)
|
|
|
6
6
|
end
|
|
7
7
|
INTEGRATION_DB = POSTGRES_DB unless defined?(INTEGRATION_DB)
|
|
8
8
|
|
|
9
|
+
# Automatic parameterization changes the SQL used, so don't check
|
|
10
|
+
# for expected SQL if it is being used.
|
|
11
|
+
if defined?(Sequel::Postgres::AutoParameterize)
|
|
12
|
+
check_sqls = false
|
|
13
|
+
else
|
|
14
|
+
check_sqls = true
|
|
15
|
+
end
|
|
16
|
+
|
|
9
17
|
def POSTGRES_DB.sqls
|
|
10
18
|
(@sqls ||= [])
|
|
11
19
|
end
|
|
@@ -13,7 +21,7 @@ logger = Object.new
|
|
|
13
21
|
def logger.method_missing(m, msg)
|
|
14
22
|
POSTGRES_DB.sqls << msg
|
|
15
23
|
end
|
|
16
|
-
POSTGRES_DB.loggers
|
|
24
|
+
POSTGRES_DB.loggers << logger
|
|
17
25
|
|
|
18
26
|
#POSTGRES_DB.instance_variable_set(:@server_version, 80100)
|
|
19
27
|
POSTGRES_DB.create_table! :test do
|
|
@@ -61,7 +69,6 @@ describe "A PostgreSQL dataset" do
|
|
|
61
69
|
end
|
|
62
70
|
|
|
63
71
|
specify "should quote columns and tables using double quotes if quoting identifiers" do
|
|
64
|
-
@d.quote_identifiers = true
|
|
65
72
|
@d.select(:name).sql.should == \
|
|
66
73
|
'SELECT "name" FROM "test"'
|
|
67
74
|
|
|
@@ -89,27 +96,28 @@ describe "A PostgreSQL dataset" do
|
|
|
89
96
|
@d.select('max(test."name") AS "max_name"'.lit).sql.should == \
|
|
90
97
|
'SELECT max(test."name") AS "max_name" FROM "test"'
|
|
91
98
|
|
|
92
|
-
@d.
|
|
93
|
-
"
|
|
99
|
+
@d.insert_sql(:x => :y).should =~ \
|
|
100
|
+
/\AINSERT INTO "test" \("x"\) VALUES \("y"\)( RETURNING NULL)?\z/
|
|
94
101
|
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
if check_sqls
|
|
103
|
+
@d.select(:test.sql_function(:abc, 'hello')).sql.should == \
|
|
104
|
+
"SELECT test(\"abc\", 'hello') FROM \"test\""
|
|
97
105
|
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
@d.select(:test.sql_function(:abc__def, 'hello')).sql.should == \
|
|
107
|
+
"SELECT test(\"abc\".\"def\", 'hello') FROM \"test\""
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
@d.select(:test.sql_function(:abc__def, 'hello').as(:x2)).sql.should == \
|
|
110
|
+
"SELECT test(\"abc\".\"def\", 'hello') AS \"x2\" FROM \"test\""
|
|
103
111
|
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
@d.insert_sql(:value => 333).should =~ \
|
|
113
|
+
/\AINSERT INTO "test" \("value"\) VALUES \(333\)( RETURNING NULL)?\z/
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
@d.disable_insert_returning.insert_sql(:value => 333).should =~ \
|
|
116
|
+
/\AINSERT INTO "test" \("value"\) VALUES \(333\)\z/
|
|
117
|
+
end
|
|
109
118
|
end
|
|
110
119
|
|
|
111
120
|
specify "should quote fields correctly when reversing the order if quoting identifiers" do
|
|
112
|
-
@d.quote_identifiers = true
|
|
113
121
|
@d.reverse_order(:name).sql.should == \
|
|
114
122
|
'SELECT * FROM "test" ORDER BY "name" DESC'
|
|
115
123
|
|
|
@@ -167,7 +175,7 @@ describe "Dataset#distinct" do
|
|
|
167
175
|
@ds = @db[:a]
|
|
168
176
|
end
|
|
169
177
|
after do
|
|
170
|
-
@db.drop_table(:a)
|
|
178
|
+
@db.drop_table?(:a)
|
|
171
179
|
end
|
|
172
180
|
|
|
173
181
|
it "#distinct with arguments should return results distinct on those arguments" do
|
|
@@ -191,7 +199,7 @@ if POSTGRES_DB.pool.respond_to?(:max_size) and POSTGRES_DB.pool.max_size > 1
|
|
|
191
199
|
@ds = POSTGRES_DB[:items]
|
|
192
200
|
end
|
|
193
201
|
after do
|
|
194
|
-
POSTGRES_DB.drop_table(:items)
|
|
202
|
+
POSTGRES_DB.drop_table?(:items)
|
|
195
203
|
POSTGRES_DB.disconnect
|
|
196
204
|
end
|
|
197
205
|
|
|
@@ -240,27 +248,60 @@ end
|
|
|
240
248
|
|
|
241
249
|
describe "A PostgreSQL dataset with a timestamp field" do
|
|
242
250
|
before do
|
|
243
|
-
@
|
|
251
|
+
@db = POSTGRES_DB
|
|
252
|
+
@d = @db[:test3]
|
|
244
253
|
@d.delete
|
|
245
254
|
end
|
|
255
|
+
after do
|
|
256
|
+
@db.convert_infinite_timestamps = false if @db.adapter_scheme == :postgres
|
|
257
|
+
end
|
|
246
258
|
|
|
247
|
-
cspecify "should store milliseconds in time fields for Time objects", :do do
|
|
259
|
+
cspecify "should store milliseconds in time fields for Time objects", :do, :swift do
|
|
248
260
|
t = Time.now
|
|
249
261
|
@d << {:value=>1, :time=>t}
|
|
250
|
-
t2 = @d[:value =>
|
|
262
|
+
t2 = @d[:value =>1][:time]
|
|
251
263
|
@d.literal(t2).should == @d.literal(t)
|
|
252
264
|
t2.strftime('%Y-%m-%d %H:%M:%S').should == t.strftime('%Y-%m-%d %H:%M:%S')
|
|
253
265
|
t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000 == t.usec
|
|
254
266
|
end
|
|
255
267
|
|
|
256
|
-
cspecify "should store milliseconds in time fields for DateTime objects", :do do
|
|
268
|
+
cspecify "should store milliseconds in time fields for DateTime objects", :do, :swift do
|
|
257
269
|
t = DateTime.now
|
|
258
270
|
@d << {:value=>1, :time=>t}
|
|
259
|
-
t2 = @d[:value =>
|
|
271
|
+
t2 = @d[:value =>1][:time]
|
|
260
272
|
@d.literal(t2).should == @d.literal(t)
|
|
261
273
|
t2.strftime('%Y-%m-%d %H:%M:%S').should == t.strftime('%Y-%m-%d %H:%M:%S')
|
|
262
274
|
t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000 == t.strftime('%N').to_i/1000
|
|
263
275
|
end
|
|
276
|
+
|
|
277
|
+
if POSTGRES_DB.adapter_scheme == :postgres
|
|
278
|
+
specify "should handle infinite timestamps if convert_infinite_timestamps is set" do
|
|
279
|
+
@d << {:time=>'infinity'.cast(:timestamp)}
|
|
280
|
+
@db.convert_infinite_timestamps = :nil
|
|
281
|
+
@db[:test3].get(:time).should == nil
|
|
282
|
+
@db.convert_infinite_timestamps = :string
|
|
283
|
+
@db[:test3].get(:time).should == 'infinity'
|
|
284
|
+
@db.convert_infinite_timestamps = :float
|
|
285
|
+
@db[:test3].get(:time).should == 1.0/0.0
|
|
286
|
+
|
|
287
|
+
@d.update(:time=>'-infinity'.cast(:timestamp))
|
|
288
|
+
@db.convert_infinite_timestamps = :nil
|
|
289
|
+
@db[:test3].get(:time).should == nil
|
|
290
|
+
@db.convert_infinite_timestamps = :string
|
|
291
|
+
@db[:test3].get(:time).should == '-infinity'
|
|
292
|
+
@db.convert_infinite_timestamps = :float
|
|
293
|
+
@db[:test3].get(:time).should == -1.0/0.0
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
specify "should handle conversions from infinite strings/floats in models" do
|
|
297
|
+
c = Class.new(Sequel::Model(:test3))
|
|
298
|
+
@db.convert_infinite_timestamps = :float
|
|
299
|
+
c.new(:time=>'infinity').time.should == 'infinity'
|
|
300
|
+
c.new(:time=>'-infinity').time.should == '-infinity'
|
|
301
|
+
c.new(:time=>1.0/0.0).time.should == 1.0/0.0
|
|
302
|
+
c.new(:time=>-1.0/0.0).time.should == -1.0/0.0
|
|
303
|
+
end
|
|
304
|
+
end
|
|
264
305
|
end
|
|
265
306
|
|
|
266
307
|
describe "PostgreSQL's EXPLAIN and ANALYZE" do
|
|
@@ -317,11 +358,11 @@ end
|
|
|
317
358
|
describe "A PostgreSQL database" do
|
|
318
359
|
before do
|
|
319
360
|
@db = POSTGRES_DB
|
|
320
|
-
@db.drop_table(:posts)
|
|
361
|
+
@db.drop_table?(:posts)
|
|
321
362
|
@db.sqls.clear
|
|
322
363
|
end
|
|
323
364
|
after do
|
|
324
|
-
@db.drop_table(:posts)
|
|
365
|
+
@db.drop_table?(:posts)
|
|
325
366
|
end
|
|
326
367
|
|
|
327
368
|
specify "should support resetting the primary key sequence" do
|
|
@@ -364,9 +405,9 @@ describe "A PostgreSQL database" do
|
|
|
364
405
|
@db.create_table(:posts){text :title; text :body; full_text_index [:title, :body]; full_text_index :title, :language => 'french'}
|
|
365
406
|
@db.sqls.should == [
|
|
366
407
|
%{CREATE TABLE "posts" ("title" text, "body" text)},
|
|
367
|
-
%{CREATE INDEX "posts_title_body_index" ON "posts" USING gin (to_tsvector('simple', (COALESCE("title", '') || ' ' || COALESCE("body", ''))))},
|
|
368
|
-
%{CREATE INDEX "posts_title_index" ON "posts" USING gin (to_tsvector('french', (COALESCE("title", ''))))}
|
|
369
|
-
]
|
|
408
|
+
%{CREATE INDEX "posts_title_body_index" ON "posts" USING gin (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))))},
|
|
409
|
+
%{CREATE INDEX "posts_title_index" ON "posts" USING gin (to_tsvector('french'::regconfig, (COALESCE("title", ''))))}
|
|
410
|
+
] if check_sqls
|
|
370
411
|
|
|
371
412
|
@db[:posts].insert(:title=>'ruby rails', :body=>'yowsa')
|
|
372
413
|
@db[:posts].insert(:title=>'sequel', :body=>'ruby')
|
|
@@ -377,9 +418,9 @@ describe "A PostgreSQL database" do
|
|
|
377
418
|
@db[:posts].full_text_search([:title, :body], ['yowsa', 'rails']).all.should == [:title=>'ruby rails', :body=>'yowsa']
|
|
378
419
|
@db[:posts].full_text_search(:title, 'scooby', :language => 'french').all.should == [{:title=>'ruby scooby', :body=>'x'}]
|
|
379
420
|
@db.sqls.should == [
|
|
380
|
-
%{SELECT * FROM "posts" WHERE (to_tsvector('simple', (COALESCE("title", ''))) @@ to_tsquery('simple', 'rails'))},
|
|
381
|
-
%{SELECT * FROM "posts" WHERE (to_tsvector('simple', (COALESCE("title", '') || ' ' || COALESCE("body", ''))) @@ to_tsquery('simple', 'yowsa | rails'))},
|
|
382
|
-
%{SELECT * FROM "posts" WHERE (to_tsvector('french', (COALESCE("title", ''))) @@ to_tsquery('french', 'scooby'))}]
|
|
421
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('simple'::regconfig, 'rails'))},
|
|
422
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))) @@ to_tsquery('simple'::regconfig, 'yowsa | rails'))},
|
|
423
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('french'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('french'::regconfig, 'scooby'))}] if check_sqls
|
|
383
424
|
|
|
384
425
|
@db[:posts].full_text_search(:title, :$n).call(:select, :n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
385
426
|
@db[:posts].full_text_search(:title, :$n).prepare(:select, :fts_select).call(:n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
@@ -439,13 +480,13 @@ describe "Postgres::Dataset#import" do
|
|
|
439
480
|
@ds = @db[:test]
|
|
440
481
|
end
|
|
441
482
|
after do
|
|
442
|
-
@db.drop_table(:test)
|
|
483
|
+
@db.drop_table?(:test)
|
|
443
484
|
end
|
|
444
485
|
|
|
445
486
|
specify "#import should return separate insert statements if server_version < 80200" do
|
|
446
487
|
@ds.meta_def(:server_version){80199}
|
|
447
488
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
448
|
-
@db.sqls.should == ['BEGIN', 'INSERT INTO "test" ("x", "y") VALUES (1, 2)', 'INSERT INTO "test" ("x", "y") VALUES (3, 4)', 'COMMIT']
|
|
489
|
+
@db.sqls.should == ['BEGIN', 'INSERT INTO "test" ("x", "y") VALUES (1, 2)', 'INSERT INTO "test" ("x", "y") VALUES (3, 4)', 'COMMIT'] if check_sqls
|
|
449
490
|
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
450
491
|
end
|
|
451
492
|
|
|
@@ -495,7 +536,7 @@ describe "Postgres::Dataset#insert" do
|
|
|
495
536
|
@ds = @db[:test5]
|
|
496
537
|
end
|
|
497
538
|
after do
|
|
498
|
-
@db.drop_table(:test5)
|
|
539
|
+
@db.drop_table?(:test5)
|
|
499
540
|
end
|
|
500
541
|
|
|
501
542
|
specify "should work with static SQL" do
|
|
@@ -516,7 +557,7 @@ describe "Postgres::Dataset#insert" do
|
|
|
516
557
|
"SELECT currval('\"public\".test5_xid_seq')",
|
|
517
558
|
'INSERT INTO "test5" ("value") VALUES (13)',
|
|
518
559
|
"SELECT currval('\"public\".test5_xid_seq')"
|
|
519
|
-
]
|
|
560
|
+
] if check_sqls
|
|
520
561
|
@ds.all.should == [{:xid=>1, :value=>10}, {:xid=>2, :value=>20}, {:xid=>3, :value=>13}]
|
|
521
562
|
end
|
|
522
563
|
|
|
@@ -540,7 +581,7 @@ describe "Postgres::Dataset#insert" do
|
|
|
540
581
|
specify "should use INSERT RETURNING if server_version >= 80200" do
|
|
541
582
|
@ds.meta_def(:server_version){80201}
|
|
542
583
|
@ds.insert(:value=>10).should == 1
|
|
543
|
-
@db.sqls.last.should == 'INSERT INTO "test5" ("value") VALUES (10) RETURNING "xid"'
|
|
584
|
+
@db.sqls.last.should == 'INSERT INTO "test5" ("value") VALUES (10) RETURNING "xid"' if check_sqls
|
|
544
585
|
end
|
|
545
586
|
|
|
546
587
|
specify "should have insert_select return nil if server_version < 80200" do
|
|
@@ -582,7 +623,6 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
582
623
|
POSTGRES_DB.instance_variable_set(:@primary_key_sequences, {})
|
|
583
624
|
end
|
|
584
625
|
after do
|
|
585
|
-
POSTGRES_DB.quote_identifiers = false
|
|
586
626
|
POSTGRES_DB << "DROP SCHEMA schema_test CASCADE"
|
|
587
627
|
POSTGRES_DB.default_schema = nil
|
|
588
628
|
end
|
|
@@ -638,7 +678,7 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
638
678
|
POSTGRES_DB.schema(:public__domains).map{|x| x.first}.should == [:d]
|
|
639
679
|
POSTGRES_DB.schema(:schema_test__domains).map{|x| x.first}.should == [:i]
|
|
640
680
|
ensure
|
|
641
|
-
POSTGRES_DB.drop_table(:public__domains)
|
|
681
|
+
POSTGRES_DB.drop_table?(:public__domains)
|
|
642
682
|
end
|
|
643
683
|
end
|
|
644
684
|
|
|
@@ -658,7 +698,6 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
658
698
|
end
|
|
659
699
|
|
|
660
700
|
specify "should be able to get serial sequences for tables that have spaces in the name in a given schema" do
|
|
661
|
-
POSTGRES_DB.quote_identifiers = true
|
|
662
701
|
POSTGRES_DB.create_table(:"schema_test__schema test"){primary_key :i}
|
|
663
702
|
POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."schema test_i_seq"'
|
|
664
703
|
end
|
|
@@ -670,7 +709,6 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
670
709
|
end
|
|
671
710
|
|
|
672
711
|
specify "should be able to get custom sequences for tables that have spaces in the name in a given schema" do
|
|
673
|
-
POSTGRES_DB.quote_identifiers = true
|
|
674
712
|
POSTGRES_DB << "CREATE SEQUENCE schema_test.\"ks eq\""
|
|
675
713
|
POSTGRES_DB.create_table(:"schema_test__schema test"){integer :j; primary_key :k, :type=>:integer, :default=>"nextval('schema_test.\"ks eq\"'::regclass)".lit}
|
|
676
714
|
POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."ks eq"'
|
|
@@ -691,7 +729,6 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
691
729
|
@db = POSTGRES_DB
|
|
692
730
|
@db.run "DROP SCHEMA s CASCADE" rescue nil
|
|
693
731
|
@db.run "CREATE SCHEMA s"
|
|
694
|
-
@db.quote_identifiers = true
|
|
695
732
|
|
|
696
733
|
@db.create_table(:s__bands){primary_key :id; String :name}
|
|
697
734
|
@db.create_table(:s__albums){primary_key :id; String :name; foreign_key :band_id, :s__bands}
|
|
@@ -733,7 +770,6 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
733
770
|
@m4 = @Member.create(:name=>"JC", :band=>@b2)
|
|
734
771
|
end
|
|
735
772
|
after(:all) do
|
|
736
|
-
@db.quote_identifiers = false
|
|
737
773
|
@db.run "DROP SCHEMA s CASCADE"
|
|
738
774
|
end
|
|
739
775
|
|
|
@@ -916,7 +952,7 @@ if POSTGRES_DB.dataset.supports_window_functions?
|
|
|
916
952
|
@ds.insert(:id=>6, :group_id=>2, :amount=>100000)
|
|
917
953
|
end
|
|
918
954
|
after do
|
|
919
|
-
@db.drop_table(:i1)
|
|
955
|
+
@db.drop_table?(:i1)
|
|
920
956
|
end
|
|
921
957
|
|
|
922
958
|
specify "should give correct results for window functions" do
|
|
@@ -941,7 +977,7 @@ describe "Postgres::Database functions, languages, schemas, and triggers" do
|
|
|
941
977
|
@d.drop_function('tf', :if_exists=>true, :cascade=>true, :args=>%w'integer integer')
|
|
942
978
|
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
|
|
943
979
|
@d.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
|
|
944
|
-
@d.drop_table(:test)
|
|
980
|
+
@d.drop_table?(:test)
|
|
945
981
|
end
|
|
946
982
|
|
|
947
983
|
specify "#create_function and #drop_function should create and drop functions" do
|
|
@@ -983,9 +1019,9 @@ describe "Postgres::Database functions, languages, schemas, and triggers" do
|
|
|
983
1019
|
end
|
|
984
1020
|
|
|
985
1021
|
specify "#create_schema and #drop_schema should create and drop schemas" do
|
|
986
|
-
@d.send(:create_schema_sql, :sequel).should == 'CREATE SCHEMA sequel'
|
|
987
|
-
@d.send(:drop_schema_sql, :sequel).should == 'DROP SCHEMA sequel'
|
|
988
|
-
@d.send(:drop_schema_sql, :sequel, :if_exists=>true, :cascade=>true).should == 'DROP SCHEMA IF EXISTS sequel CASCADE'
|
|
1022
|
+
@d.send(:create_schema_sql, :sequel).should == 'CREATE SCHEMA "sequel"'
|
|
1023
|
+
@d.send(:drop_schema_sql, :sequel).should == 'DROP SCHEMA "sequel"'
|
|
1024
|
+
@d.send(:drop_schema_sql, :sequel, :if_exists=>true, :cascade=>true).should == 'DROP SCHEMA IF EXISTS "sequel" CASCADE'
|
|
989
1025
|
@d.create_schema(:sequel)
|
|
990
1026
|
@d.create_table(:sequel__test){Integer :a}
|
|
991
1027
|
if @d.server_version >= 80200
|
|
@@ -998,7 +1034,7 @@ describe "Postgres::Database functions, languages, schemas, and triggers" do
|
|
|
998
1034
|
specify "#create_trigger and #drop_trigger should create and drop triggers" do
|
|
999
1035
|
@d.create_language(:plpgsql) if @d.server_version < 90000
|
|
1000
1036
|
@d.create_function(:tf, 'BEGIN IF NEW.value IS NULL THEN RAISE EXCEPTION \'Blah\'; END IF; RETURN NEW; END;', :language=>:plpgsql, :returns=>:trigger)
|
|
1001
|
-
@d.send(:create_trigger_sql, :test, :identity, :tf, :each_row=>true).should == 'CREATE TRIGGER identity BEFORE INSERT OR UPDATE OR DELETE ON test FOR EACH ROW EXECUTE PROCEDURE tf()'
|
|
1037
|
+
@d.send(:create_trigger_sql, :test, :identity, :tf, :each_row=>true).should == 'CREATE TRIGGER identity BEFORE INSERT OR UPDATE OR DELETE ON "test" FOR EACH ROW EXECUTE PROCEDURE tf()'
|
|
1002
1038
|
@d.create_table(:test){String :name; Integer :value}
|
|
1003
1039
|
@d.create_trigger(:test, :identity, :tf, :each_row=>true)
|
|
1004
1040
|
@d[:test].insert(:name=>'a', :value=>1)
|
|
@@ -1007,10 +1043,10 @@ describe "Postgres::Database functions, languages, schemas, and triggers" do
|
|
|
1007
1043
|
@d[:test].filter(:name=>'a').all.should == [{:name=>'a', :value=>1}]
|
|
1008
1044
|
@d[:test].filter(:name=>'a').update(:value=>3)
|
|
1009
1045
|
@d[:test].filter(:name=>'a').all.should == [{:name=>'a', :value=>3}]
|
|
1010
|
-
@d.send(:drop_trigger_sql, :test, :identity).should == 'DROP TRIGGER identity ON test'
|
|
1046
|
+
@d.send(:drop_trigger_sql, :test, :identity).should == 'DROP TRIGGER identity ON "test"'
|
|
1011
1047
|
@d.drop_trigger(:test, :identity)
|
|
1012
|
-
@d.send(:create_trigger_sql, :test, :identity, :tf, :after=>true, :events=>:insert, :args=>[1, 'a']).should == 'CREATE TRIGGER identity AFTER INSERT ON test EXECUTE PROCEDURE tf(1, \'a\')'
|
|
1013
|
-
@d.send(:drop_trigger_sql, :test, :identity, :if_exists=>true, :cascade=>true).should == 'DROP TRIGGER IF EXISTS identity ON test CASCADE'
|
|
1048
|
+
@d.send(:create_trigger_sql, :test, :identity, :tf, :after=>true, :events=>:insert, :args=>[1, 'a']).should == 'CREATE TRIGGER identity AFTER INSERT ON "test" EXECUTE PROCEDURE tf(1, \'a\')'
|
|
1049
|
+
@d.send(:drop_trigger_sql, :test, :identity, :if_exists=>true, :cascade=>true).should == 'DROP TRIGGER IF EXISTS identity ON "test" CASCADE'
|
|
1014
1050
|
# Make sure if exists works
|
|
1015
1051
|
@d.drop_trigger(:test, :identity, :if_exists=>true, :cascade=>true)
|
|
1016
1052
|
end
|
|
@@ -1026,7 +1062,7 @@ if POSTGRES_DB.adapter_scheme == :postgres
|
|
|
1026
1062
|
@db.transaction{1001.times{|i| @ds.insert(i)}}
|
|
1027
1063
|
end
|
|
1028
1064
|
after(:all) do
|
|
1029
|
-
@db.drop_table(:test_cursor)
|
|
1065
|
+
@db.drop_table?(:test_cursor)
|
|
1030
1066
|
end
|
|
1031
1067
|
|
|
1032
1068
|
specify "should return the same results as the non-cursor use" do
|
|
@@ -1055,23 +1091,17 @@ if POSTGRES_DB.adapter_scheme == :postgres
|
|
|
1055
1091
|
before do
|
|
1056
1092
|
@db = POSTGRES_DB
|
|
1057
1093
|
Sequel::Postgres::PG_NAMED_TYPES[:interval] = lambda{|v| v.reverse}
|
|
1058
|
-
@db.
|
|
1059
|
-
disconnect
|
|
1060
|
-
@conversion_procs = nil
|
|
1061
|
-
end
|
|
1094
|
+
@db.reset_conversion_procs
|
|
1062
1095
|
end
|
|
1063
1096
|
after do
|
|
1064
1097
|
Sequel::Postgres::PG_NAMED_TYPES.delete(:interval)
|
|
1065
|
-
@db.
|
|
1066
|
-
|
|
1067
|
-
@conversion_procs = nil
|
|
1068
|
-
end
|
|
1069
|
-
@db.drop_table(:foo)
|
|
1098
|
+
@db.reset_conversion_procs
|
|
1099
|
+
@db.drop_table?(:foo)
|
|
1070
1100
|
end
|
|
1071
1101
|
|
|
1072
1102
|
specify "should look up conversion procs by name" do
|
|
1073
1103
|
@db.create_table!(:foo){interval :bar}
|
|
1074
|
-
@db[:foo].insert('21 days')
|
|
1104
|
+
@db[:foo].insert('21 days'.cast(:interval))
|
|
1075
1105
|
@db[:foo].get(:bar).should == 'syad 12'
|
|
1076
1106
|
end
|
|
1077
1107
|
end
|
|
@@ -1087,7 +1117,7 @@ if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && POSTGRE
|
|
|
1087
1117
|
ds.insert(3, 4)
|
|
1088
1118
|
end
|
|
1089
1119
|
after(:all) do
|
|
1090
|
-
@db.drop_table(:test_copy)
|
|
1120
|
+
@db.drop_table?(:test_copy)
|
|
1091
1121
|
end
|
|
1092
1122
|
|
|
1093
1123
|
specify "without a block or options should return a text version of the table as a single string" do
|
|
@@ -1111,7 +1141,7 @@ if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && POSTGRE
|
|
|
1111
1141
|
end
|
|
1112
1142
|
|
|
1113
1143
|
specify "should accept dataset as first argument" do
|
|
1114
|
-
@db.copy_table(@db[:test_copy].cross_join(:test_copy___tc).order(
|
|
1144
|
+
@db.copy_table(@db[:test_copy].cross_join(:test_copy___tc).order(:test_copy__x, :test_copy__y, :tc__x, :tc__y)).should == "1\t2\t1\t2\n1\t2\t3\t4\n3\t4\t1\t2\n3\t4\t3\t4\n"
|
|
1115
1145
|
end
|
|
1116
1146
|
|
|
1117
1147
|
specify "with a block and no options should yield each row as a string in text format" do
|
|
@@ -1207,11 +1237,11 @@ if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && POSTGRE
|
|
|
1207
1237
|
i = 0
|
|
1208
1238
|
@db.listen('foo2', :timeout=>0.001, :loop=>proc{i+=1; throw :stop if i > 3}){|ev, pid, payload| called = true}.should == nil
|
|
1209
1239
|
i.should == 4
|
|
1210
|
-
end
|
|
1240
|
+
end unless RUBY_VERSION == '1.9.2' && RUBY_PLATFORM =~ /mingw/ # Ruby freezes on this spec on this platform/version
|
|
1211
1241
|
end
|
|
1212
1242
|
end
|
|
1213
1243
|
|
|
1214
|
-
describe '
|
|
1244
|
+
describe 'PostgreSQL special float handling' do
|
|
1215
1245
|
before do
|
|
1216
1246
|
@db = POSTGRES_DB
|
|
1217
1247
|
@db.create_table!(:test5){Float :value}
|
|
@@ -1219,22 +1249,24 @@ describe 'POSTGRES special float handling' do
|
|
|
1219
1249
|
@ds = @db[:test5]
|
|
1220
1250
|
end
|
|
1221
1251
|
after do
|
|
1222
|
-
@db.drop_table(:test5)
|
|
1252
|
+
@db.drop_table?(:test5)
|
|
1223
1253
|
end
|
|
1224
1254
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1255
|
+
if check_sqls
|
|
1256
|
+
specify 'should quote NaN' do
|
|
1257
|
+
nan = 0.0/0.0
|
|
1258
|
+
@ds.insert_sql(:value => nan).should == %q{INSERT INTO "test5" ("value") VALUES ('NaN')}
|
|
1259
|
+
end
|
|
1229
1260
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1261
|
+
specify 'should quote +Infinity' do
|
|
1262
|
+
inf = 1.0/0.0
|
|
1263
|
+
@ds.insert_sql(:value => inf).should == %q{INSERT INTO "test5" ("value") VALUES ('Infinity')}
|
|
1264
|
+
end
|
|
1234
1265
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1266
|
+
specify 'should quote -Infinity' do
|
|
1267
|
+
inf = -1.0/0.0
|
|
1268
|
+
@ds.insert_sql(:value => inf).should == %q{INSERT INTO "test5" ("value") VALUES ('-Infinity')}
|
|
1269
|
+
end
|
|
1238
1270
|
end
|
|
1239
1271
|
|
|
1240
1272
|
if POSTGRES_DB.adapter_scheme == :postgres
|
|
@@ -1257,3 +1289,338 @@ describe 'POSTGRES special float handling' do
|
|
|
1257
1289
|
end
|
|
1258
1290
|
end
|
|
1259
1291
|
end
|
|
1292
|
+
|
|
1293
|
+
describe 'PostgreSQL array handling' do
|
|
1294
|
+
before(:all) do
|
|
1295
|
+
Sequel.extension :pg_array
|
|
1296
|
+
@db = POSTGRES_DB
|
|
1297
|
+
@db.extend Sequel::Postgres::PGArray::DatabaseMethods
|
|
1298
|
+
@ds = @db[:items]
|
|
1299
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1300
|
+
end
|
|
1301
|
+
after do
|
|
1302
|
+
@db.drop_table?(:items)
|
|
1303
|
+
end
|
|
1304
|
+
|
|
1305
|
+
specify 'insert and retrieve integer and float arrays of various sizes' do
|
|
1306
|
+
@db.create_table!(:items) do
|
|
1307
|
+
column :i2, 'int2[]'
|
|
1308
|
+
column :i4, 'int4[]'
|
|
1309
|
+
column :i8, 'int8[]'
|
|
1310
|
+
column :r, 'real[]'
|
|
1311
|
+
column :dp, 'double precision[]'
|
|
1312
|
+
end
|
|
1313
|
+
@ds.insert([1].pg_array(:int2), [nil, 2].pg_array(:int4), [3, nil].pg_array(:int8), [4, nil, 4.5].pg_array(:real), [5, nil, 5.5].pg_array("double precision"))
|
|
1314
|
+
@ds.count.should == 1
|
|
1315
|
+
if @native
|
|
1316
|
+
rs = @ds.all
|
|
1317
|
+
rs.should == [{:i2=>[1], :i4=>[nil, 2], :i8=>[3, nil], :r=>[4.0, nil, 4.5], :dp=>[5.0, nil, 5.5]}]
|
|
1318
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1319
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1320
|
+
@ds.delete
|
|
1321
|
+
@ds.insert(rs.first)
|
|
1322
|
+
@ds.all.should == rs
|
|
1323
|
+
|
|
1324
|
+
@ds.delete
|
|
1325
|
+
@ds.insert([[1], [2]].pg_array(:int2), [[nil, 2], [3, 4]].pg_array(:int4), [[3, nil], [nil, nil]].pg_array(:int8), [[4, nil], [nil, 4.5]].pg_array(:real), [[5, nil], [nil, 5.5]].pg_array("double precision"))
|
|
1326
|
+
rs = @ds.all
|
|
1327
|
+
rs.should == [{:i2=>[[1], [2]], :i4=>[[nil, 2], [3, 4]], :i8=>[[3, nil], [nil, nil]], :r=>[[4, nil], [nil, 4.5]], :dp=>[[5, nil], [nil, 5.5]]}]
|
|
1328
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1329
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1330
|
+
@ds.delete
|
|
1331
|
+
@ds.insert(rs.first)
|
|
1332
|
+
@ds.all.should == rs
|
|
1333
|
+
end
|
|
1334
|
+
end
|
|
1335
|
+
|
|
1336
|
+
specify 'insert and retrieve decimal arrays' do
|
|
1337
|
+
@db.create_table!(:items) do
|
|
1338
|
+
column :n, 'numeric[]'
|
|
1339
|
+
end
|
|
1340
|
+
@ds.insert([BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')].pg_array(:numeric))
|
|
1341
|
+
@ds.count.should == 1
|
|
1342
|
+
if @native
|
|
1343
|
+
rs = @ds.all
|
|
1344
|
+
rs.should == [{:n=>[BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')]}]
|
|
1345
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1346
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1347
|
+
@ds.delete
|
|
1348
|
+
@ds.insert(rs.first)
|
|
1349
|
+
@ds.all.should == rs
|
|
1350
|
+
|
|
1351
|
+
@ds.delete
|
|
1352
|
+
@ds.insert([[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]].pg_array(:numeric))
|
|
1353
|
+
rs = @ds.all
|
|
1354
|
+
rs.should == [{:n=>[[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]]}]
|
|
1355
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1356
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1357
|
+
@ds.delete
|
|
1358
|
+
@ds.insert(rs.first)
|
|
1359
|
+
@ds.all.should == rs
|
|
1360
|
+
end
|
|
1361
|
+
end
|
|
1362
|
+
|
|
1363
|
+
specify 'insert and retrieve string arrays' do
|
|
1364
|
+
@db.create_table!(:items) do
|
|
1365
|
+
column :c, 'char(4)[]'
|
|
1366
|
+
column :vc, 'varchar[]'
|
|
1367
|
+
column :t, 'text[]'
|
|
1368
|
+
end
|
|
1369
|
+
@ds.insert(['a', nil, 'NULL', 'b"\'c'].pg_array('char(4)'), ['a', nil, 'NULL', 'b"\'c'].pg_array(:varchar), ['a', nil, 'NULL', 'b"\'c'].pg_array(:text))
|
|
1370
|
+
@ds.count.should == 1
|
|
1371
|
+
if @native
|
|
1372
|
+
rs = @ds.all
|
|
1373
|
+
rs.should == [{:c=>['a ', nil, 'NULL', 'b"\'c'], :vc=>['a', nil, 'NULL', 'b"\'c'], :t=>['a', nil, 'NULL', 'b"\'c']}]
|
|
1374
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1375
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1376
|
+
@ds.delete
|
|
1377
|
+
@ds.insert(rs.first)
|
|
1378
|
+
@ds.all.should == rs
|
|
1379
|
+
|
|
1380
|
+
@ds.delete
|
|
1381
|
+
@ds.insert([[['a'], [nil]], [['NULL'], ['b"\'c']]].pg_array('char(4)'), [[['a'], ['']], [['NULL'], ['b"\'c']]].pg_array(:varchar), [[['a'], [nil]], [['NULL'], ['b"\'c']]].pg_array(:text))
|
|
1382
|
+
rs = @ds.all
|
|
1383
|
+
rs.should == [{:c=>[[['a '], [nil]], [['NULL'], ['b"\'c']]], :vc=>[[['a'], ['']], [['NULL'], ['b"\'c']]], :t=>[[['a'], [nil]], [['NULL'], ['b"\'c']]]}]
|
|
1384
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1385
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1386
|
+
@ds.delete
|
|
1387
|
+
@ds.insert(rs.first)
|
|
1388
|
+
@ds.all.should == rs
|
|
1389
|
+
end
|
|
1390
|
+
end
|
|
1391
|
+
|
|
1392
|
+
specify 'use arrays in bound variables' do
|
|
1393
|
+
@db.create_table!(:items) do
|
|
1394
|
+
column :i, 'int4[]'
|
|
1395
|
+
end
|
|
1396
|
+
@ds.call(:insert, {:i=>[1,2]}, {:i=>:$i})
|
|
1397
|
+
@ds.get(:i).should == [1, 2]
|
|
1398
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[1,2]).should == {:i=>[1,2]}
|
|
1399
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[1,3]).should == nil
|
|
1400
|
+
|
|
1401
|
+
@db.create_table!(:items) do
|
|
1402
|
+
column :i, 'text[]'
|
|
1403
|
+
end
|
|
1404
|
+
a = ["\"\\\\\"{}\n\t\r \v\b123afP", 'NULL', nil, '']
|
|
1405
|
+
@ds.call(:insert, {:i=>:$i}, :i=>a.pg_array)
|
|
1406
|
+
@ds.get(:i).should == a
|
|
1407
|
+
@ds.filter(:i=>:$i).call(:first, :i=>a).should == {:i=>a}
|
|
1408
|
+
@ds.filter(:i=>:$i).call(:first, :i=>['', nil, nil, 'a']).should == nil
|
|
1409
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1410
|
+
|
|
1411
|
+
specify 'with models' do
|
|
1412
|
+
@db.create_table!(:items) do
|
|
1413
|
+
primary_key :id
|
|
1414
|
+
column :i, 'integer[]'
|
|
1415
|
+
column :f, 'double precision[]'
|
|
1416
|
+
column :d, 'numeric[]'
|
|
1417
|
+
column :t, 'text[]'
|
|
1418
|
+
end
|
|
1419
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
1420
|
+
c.plugin :typecast_on_load, :i, :f, :d, :t unless @native
|
|
1421
|
+
o = c.create(:i=>[1,2, nil], :f=>[[1, 2.5], [3, 4.5]], :d=>[1, BigDecimal.new('1.000000000000000000001')], :t=>[%w'a b c', ['NULL', nil, '1']])
|
|
1422
|
+
o.i.should == [1, 2, nil]
|
|
1423
|
+
o.f.should == [[1, 2.5], [3, 4.5]]
|
|
1424
|
+
o.d.should == [BigDecimal.new('1'), BigDecimal.new('1.000000000000000000001')]
|
|
1425
|
+
o.t.should == [%w'a b c', ['NULL', nil, '1']]
|
|
1426
|
+
end
|
|
1427
|
+
|
|
1428
|
+
specify 'operations/functions with pg_array_ops' do
|
|
1429
|
+
Sequel.extension :pg_array_ops
|
|
1430
|
+
@db.create_table!(:items){column :i, 'integer[]'; column :i2, 'integer[]'; column :i3, 'integer[]'; column :i4, 'integer[]'; column :i5, 'integer[]'}
|
|
1431
|
+
@ds.insert([1, 2, 3].pg_array, [2, 1].pg_array, [4, 4].pg_array, [[5, 5], [4, 3]].pg_array, [1, nil, 5].pg_array)
|
|
1432
|
+
|
|
1433
|
+
@ds.get(:i.pg_array > :i3).should be_false
|
|
1434
|
+
@ds.get(:i3.pg_array > :i).should be_true
|
|
1435
|
+
|
|
1436
|
+
@ds.get(:i.pg_array >= :i3).should be_false
|
|
1437
|
+
@ds.get(:i.pg_array >= :i).should be_true
|
|
1438
|
+
|
|
1439
|
+
@ds.get(:i3.pg_array < :i).should be_false
|
|
1440
|
+
@ds.get(:i.pg_array < :i3).should be_true
|
|
1441
|
+
|
|
1442
|
+
@ds.get(:i3.pg_array <= :i).should be_false
|
|
1443
|
+
@ds.get(:i.pg_array <= :i).should be_true
|
|
1444
|
+
|
|
1445
|
+
@ds.get({5=>:i.pg_array.any}.sql_expr).should be_false
|
|
1446
|
+
@ds.get({1=>:i.pg_array.any}.sql_expr).should be_true
|
|
1447
|
+
|
|
1448
|
+
@ds.get({1=>:i3.pg_array.all}.sql_expr).should be_false
|
|
1449
|
+
@ds.get({4=>:i3.pg_array.all}.sql_expr).should be_true
|
|
1450
|
+
|
|
1451
|
+
@ds.get(:i2.pg_array[1]).should == 2
|
|
1452
|
+
@ds.get(:i2.pg_array[2]).should == 1
|
|
1453
|
+
|
|
1454
|
+
@ds.get(:i4.pg_array[2][1]).should == 4
|
|
1455
|
+
@ds.get(:i4.pg_array[2][2]).should == 3
|
|
1456
|
+
|
|
1457
|
+
@ds.get(:i.pg_array.contains(:i2)).should be_true
|
|
1458
|
+
@ds.get(:i.pg_array.contains(:i3)).should be_false
|
|
1459
|
+
|
|
1460
|
+
@ds.get(:i2.pg_array.contained_by(:i)).should be_true
|
|
1461
|
+
@ds.get(:i.pg_array.contained_by(:i2)).should be_false
|
|
1462
|
+
|
|
1463
|
+
@ds.get(:i.pg_array.overlaps(:i2)).should be_true
|
|
1464
|
+
@ds.get(:i2.pg_array.overlaps(:i3)).should be_false
|
|
1465
|
+
|
|
1466
|
+
@ds.get(:i.pg_array.dims).should == '[1:3]'
|
|
1467
|
+
@ds.get(:i.pg_array.length).should == 3
|
|
1468
|
+
@ds.get(:i.pg_array.lower).should == 1
|
|
1469
|
+
|
|
1470
|
+
if @db.server_version >= 90000
|
|
1471
|
+
@ds.get(:i5.pg_array.join).should == '15'
|
|
1472
|
+
@ds.get(:i5.pg_array.join(':')).should == '1:5'
|
|
1473
|
+
@ds.get(:i5.pg_array.join(':', '*')).should == '1:*:5'
|
|
1474
|
+
end
|
|
1475
|
+
@ds.select(:i.pg_array.unnest).from_self.count.should == 3 if @db.server_version >= 80400
|
|
1476
|
+
|
|
1477
|
+
if @native
|
|
1478
|
+
@ds.get(:i.pg_array.push(4)).should == [1, 2, 3, 4]
|
|
1479
|
+
@ds.get(:i.pg_array.unshift(4)).should == [4, 1, 2, 3]
|
|
1480
|
+
@ds.get(:i.pg_array.concat(:i2)).should == [1, 2, 3, 2, 1]
|
|
1481
|
+
end
|
|
1482
|
+
end
|
|
1483
|
+
end
|
|
1484
|
+
|
|
1485
|
+
describe 'PostgreSQL hstore handling' do
|
|
1486
|
+
before(:all) do
|
|
1487
|
+
Sequel.extension :pg_hstore
|
|
1488
|
+
@db = POSTGRES_DB
|
|
1489
|
+
@db.extend Sequel::Postgres::HStore::DatabaseMethods
|
|
1490
|
+
@ds = @db[:items]
|
|
1491
|
+
@h = {'a'=>'b', 'c'=>nil, 'd'=>'NULL', 'e'=>'\\\\" \\\' ,=>'}
|
|
1492
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1493
|
+
end
|
|
1494
|
+
after do
|
|
1495
|
+
@db.drop_table?(:items)
|
|
1496
|
+
end
|
|
1497
|
+
|
|
1498
|
+
specify 'insert and retrieve hstore values' do
|
|
1499
|
+
@db.create_table!(:items) do
|
|
1500
|
+
column :h, :hstore
|
|
1501
|
+
end
|
|
1502
|
+
@ds.insert(@h.hstore)
|
|
1503
|
+
@ds.count.should == 1
|
|
1504
|
+
if @native
|
|
1505
|
+
rs = @ds.all
|
|
1506
|
+
v = rs.first[:h]
|
|
1507
|
+
v.should_not be_a_kind_of(Hash)
|
|
1508
|
+
v.to_hash.should be_a_kind_of(Hash)
|
|
1509
|
+
v.to_hash.should == @h
|
|
1510
|
+
@ds.delete
|
|
1511
|
+
@ds.insert(rs.first)
|
|
1512
|
+
@ds.all.should == rs
|
|
1513
|
+
end
|
|
1514
|
+
end
|
|
1515
|
+
|
|
1516
|
+
specify 'use hstore in bound variables' do
|
|
1517
|
+
@db.create_table!(:items) do
|
|
1518
|
+
column :i, :hstore
|
|
1519
|
+
end
|
|
1520
|
+
@ds.call(:insert, {:i=>@h.hstore}, {:i=>:$i})
|
|
1521
|
+
@ds.get(:i).should == @h
|
|
1522
|
+
@ds.filter(:i=>:$i).call(:first, :i=>@h.hstore).should == {:i=>@h}
|
|
1523
|
+
@ds.filter(:i=>:$i).call(:first, :i=>{}.hstore).should == nil
|
|
1524
|
+
|
|
1525
|
+
@ds.delete
|
|
1526
|
+
@ds.call(:insert, {:i=>@h}, {:i=>:$i})
|
|
1527
|
+
@ds.get(:i).should == @h
|
|
1528
|
+
@ds.filter(:i=>:$i).call(:first, :i=>@h).should == {:i=>@h}
|
|
1529
|
+
@ds.filter(:i=>:$i).call(:first, :i=>{}).should == nil
|
|
1530
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1531
|
+
|
|
1532
|
+
specify 'with models' do
|
|
1533
|
+
@db.create_table!(:items) do
|
|
1534
|
+
primary_key :id
|
|
1535
|
+
column :h, :hstore
|
|
1536
|
+
end
|
|
1537
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
1538
|
+
c.plugin :typecast_on_load, :h unless @native
|
|
1539
|
+
c.create(:h=>@h.hstore).h.should == @h
|
|
1540
|
+
end
|
|
1541
|
+
|
|
1542
|
+
specify 'operations/functions with pg_hstore_ops' do
|
|
1543
|
+
Sequel.extension :pg_hstore_ops
|
|
1544
|
+
Sequel.extension :pg_array
|
|
1545
|
+
Sequel.extension :pg_array_ops
|
|
1546
|
+
@db.create_table!(:items){hstore :h1; hstore :h2; hstore :h3; String :t}
|
|
1547
|
+
@ds.insert({'a'=>'b', 'c'=>nil}.hstore, {'a'=>'b'}.hstore, {'d'=>'e'}.hstore)
|
|
1548
|
+
h1 = :h1.hstore
|
|
1549
|
+
h2 = :h2.hstore
|
|
1550
|
+
h3 = :h3.hstore
|
|
1551
|
+
|
|
1552
|
+
@ds.get(h1['a']).should == 'b'
|
|
1553
|
+
@ds.get(h1['d']).should == nil
|
|
1554
|
+
|
|
1555
|
+
@ds.get(h2.concat(h3).keys.pg_array.length).should == 2
|
|
1556
|
+
@ds.get(h1.concat(h3).keys.pg_array.length).should == 3
|
|
1557
|
+
@ds.get(h2.merge(h3).keys.pg_array.length).should == 2
|
|
1558
|
+
@ds.get(h1.merge(h3).keys.pg_array.length).should == 3
|
|
1559
|
+
|
|
1560
|
+
unless @db.adapter_scheme == :do
|
|
1561
|
+
# Broken DataObjects thinks operators with ? represent placeholders
|
|
1562
|
+
@ds.get(h1.contain_all(%w'a c'.pg_array)).should == true
|
|
1563
|
+
@ds.get(h1.contain_all(%w'a d'.pg_array)).should == false
|
|
1564
|
+
|
|
1565
|
+
@ds.get(h1.contain_any(%w'a d'.pg_array)).should == true
|
|
1566
|
+
@ds.get(h1.contain_any(%w'e d'.pg_array)).should == false
|
|
1567
|
+
end
|
|
1568
|
+
|
|
1569
|
+
@ds.get(h1.contains(h2)).should == true
|
|
1570
|
+
@ds.get(h1.contains(h3)).should == false
|
|
1571
|
+
|
|
1572
|
+
@ds.get(h2.contained_by(h1)).should == true
|
|
1573
|
+
@ds.get(h2.contained_by(h3)).should == false
|
|
1574
|
+
|
|
1575
|
+
@ds.get(h1.defined('a')).should == true
|
|
1576
|
+
@ds.get(h1.defined('c')).should == false
|
|
1577
|
+
@ds.get(h1.defined('d')).should == false
|
|
1578
|
+
|
|
1579
|
+
@ds.get(h1.delete('a')['c']).should == nil
|
|
1580
|
+
@ds.get(h1.delete(%w'a d'.pg_array)['c']).should == nil
|
|
1581
|
+
@ds.get(h1.delete(h2)['c']).should == nil
|
|
1582
|
+
|
|
1583
|
+
@ds.from({'a'=>'b', 'c'=>nil}.hstore.op.each).order(:key).all.should == [{:key=>'a', :value=>'b'}, {:key=>'c', :value=>nil}]
|
|
1584
|
+
|
|
1585
|
+
unless @db.adapter_scheme == :do
|
|
1586
|
+
@ds.get(h1.has_key?('c')).should == true
|
|
1587
|
+
@ds.get(h1.include?('c')).should == true
|
|
1588
|
+
@ds.get(h1.key?('c')).should == true
|
|
1589
|
+
@ds.get(h1.member?('c')).should == true
|
|
1590
|
+
@ds.get(h1.exist?('c')).should == true
|
|
1591
|
+
@ds.get(h1.has_key?('d')).should == false
|
|
1592
|
+
@ds.get(h1.include?('d')).should == false
|
|
1593
|
+
@ds.get(h1.key?('d')).should == false
|
|
1594
|
+
@ds.get(h1.member?('d')).should == false
|
|
1595
|
+
@ds.get(h1.exist?('d')).should == false
|
|
1596
|
+
end
|
|
1597
|
+
|
|
1598
|
+
@ds.get(h1.hstore.hstore.hstore.keys.pg_array.length).should == 2
|
|
1599
|
+
@ds.get(h1.keys.pg_array.length).should == 2
|
|
1600
|
+
@ds.get(h2.keys.pg_array.length).should == 1
|
|
1601
|
+
@ds.get(h1.akeys.pg_array.length).should == 2
|
|
1602
|
+
@ds.get(h2.akeys.pg_array.length).should == 1
|
|
1603
|
+
|
|
1604
|
+
@ds.from({'t'=>'s'}.hstore.op.populate(Sequel::SQL::Cast.new(nil, :items))).select_map(:t).should == ['s']
|
|
1605
|
+
@ds.from(:items___i).select({'t'=>'s'}.hstore.op.record_set(:i).as(:r)).from_self(:alias=>:s).select('(r).*'.lit).from_self.select_map(:t).should == ['s']
|
|
1606
|
+
|
|
1607
|
+
@ds.from({'t'=>'s', 'a'=>'b'}.hstore.op.skeys.as(:s)).select_order_map(:s).should == %w'a t'
|
|
1608
|
+
|
|
1609
|
+
@ds.get(h1.slice(%w'a c'.pg_array).keys.pg_array.length).should == 2
|
|
1610
|
+
@ds.get(h1.slice(%w'd c'.pg_array).keys.pg_array.length).should == 1
|
|
1611
|
+
@ds.get(h1.slice(%w'd e'.pg_array).keys.pg_array.length).should == nil
|
|
1612
|
+
|
|
1613
|
+
@ds.from({'t'=>'s', 'a'=>'b'}.hstore.op.svals.as(:s)).select_order_map(:s).should == %w'b s'
|
|
1614
|
+
|
|
1615
|
+
@ds.get(h1.to_array.pg_array.length).should == 4
|
|
1616
|
+
@ds.get(h2.to_array.pg_array.length).should == 2
|
|
1617
|
+
|
|
1618
|
+
@ds.get(h1.to_matrix.pg_array.length).should == 2
|
|
1619
|
+
@ds.get(h2.to_matrix.pg_array.length).should == 1
|
|
1620
|
+
|
|
1621
|
+
@ds.get(h1.values.pg_array.length).should == 2
|
|
1622
|
+
@ds.get(h2.values.pg_array.length).should == 1
|
|
1623
|
+
@ds.get(h1.avals.pg_array.length).should == 2
|
|
1624
|
+
@ds.get(h2.avals.pg_array.length).should == 1
|
|
1625
|
+
end
|
|
1626
|
+
end if POSTGRES_DB.type_supported?(:hstore)
|