sequel 3.21.0 → 3.36.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 +855 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -7
- data/Rakefile +42 -24
- data/bin/sequel +26 -8
- data/doc/active_record.rdoc +1 -0
- data/doc/advanced_associations.rdoc +171 -11
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +85 -552
- data/doc/model_hooks.rdoc +78 -27
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +97 -50
- data/doc/prepared_statements.rdoc +40 -14
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +30 -4
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +572 -0
- data/doc/sharding.rdoc +95 -3
- data/doc/testing.rdoc +129 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +51 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +1 -57
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +47 -0
- data/lib/sequel/adapters/jdbc/derby.rb +287 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +265 -94
- data/lib/sequel/adapters/mock.rb +361 -0
- data/lib/sequel/adapters/mysql.rb +118 -222
- data/lib/sequel/adapters/mysql2.rb +58 -57
- data/lib/sequel/adapters/odbc/mssql.rb +15 -7
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +356 -107
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +342 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +335 -118
- data/lib/sequel/adapters/shared/mysql.rb +340 -76
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +243 -45
- data/lib/sequel/adapters/shared/postgres.rb +524 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +265 -89
- data/lib/sequel/adapters/sqlite.rb +101 -39
- data/lib/sequel/adapters/swift/mysql.rb +9 -12
- data/lib/sequel/adapters/swift/postgres.rb +9 -74
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +8 -7
- data/lib/sequel/adapters/tinytds.rb +161 -21
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +38 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +118 -11
- data/lib/sequel/database/connecting.rb +38 -28
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +150 -46
- data/lib/sequel/database/query.rb +215 -65
- data/lib/sequel/database/schema_generator.rb +64 -20
- data/lib/sequel/database/schema_methods.rb +212 -54
- data/lib/sequel/dataset/actions.rb +322 -85
- data/lib/sequel/dataset/features.rb +96 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +237 -44
- data/lib/sequel/dataset/sql.rb +698 -278
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
- data/lib/sequel/extensions/migration.rb +97 -11
- data/lib/sequel/extensions/named_timezones.rb +5 -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 +169 -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_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -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.rb +1 -1
- 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 +251 -37
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/server_block.rb +139 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1187 -393
- data/lib/sequel/model/base.rb +578 -170
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +123 -8
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +58 -6
- data/lib/sequel/plugins/list.rb +12 -2
- data/lib/sequel/plugins/many_through_many.rb +79 -28
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +139 -63
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/prepared_statements.rb +167 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +10 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +526 -59
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +142 -40
- data/spec/adapters/mysql_spec.rb +380 -234
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +1050 -212
- data/spec/adapters/spec_helper.rb +8 -5
- data/spec/adapters/sqlite_spec.rb +139 -27
- data/spec/core/connection_pool_spec.rb +196 -93
- data/spec/core/database_spec.rb +879 -510
- data/spec/core/dataset_spec.rb +1415 -1086
- data/spec/core/expression_filters_spec.rb +554 -109
- data/spec/core/mock_adapter_spec.rb +449 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +482 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/caching_spec.rb +47 -51
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +69 -92
- data/spec/extensions/identity_map_spec.rb +131 -22
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -6
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +48 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +251 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- 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 +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/query_spec.rb +6 -0
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +429 -22
- data/spec/extensions/schema_spec.rb +25 -21
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +85 -43
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +23 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +22 -61
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +9 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/extensions/xml_serializer_spec.rb +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +9 -3
- data/spec/integration/dataset_test.rb +605 -91
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +454 -143
- data/spec/integration/prepared_statement_test.rb +263 -128
- data/spec/integration/schema_test.rb +309 -43
- data/spec/integration/spec_helper.rb +40 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +18 -4
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +1067 -661
- data/spec/model/base_spec.rb +329 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +349 -67
- data/spec/model/model_spec.rb +240 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +490 -232
- data/spec/model/spec_helper.rb +14 -71
- data/spec/model/validations_spec.rb +11 -0
- data/spec/rcov.opts +2 -0
- metadata +178 -80
|
@@ -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,9 +21,9 @@ 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
|
-
#POSTGRES_DB.instance_variable_set(:@server_version,
|
|
26
|
+
#POSTGRES_DB.instance_variable_set(:@server_version, 80200)
|
|
19
27
|
POSTGRES_DB.create_table! :test do
|
|
20
28
|
text :name
|
|
21
29
|
integer :value, :index => true
|
|
@@ -37,7 +45,7 @@ describe "A PostgreSQL database" do
|
|
|
37
45
|
before do
|
|
38
46
|
@db = POSTGRES_DB
|
|
39
47
|
end
|
|
40
|
-
|
|
48
|
+
|
|
41
49
|
specify "should provide the server version" do
|
|
42
50
|
@db.server_version.should > 70000
|
|
43
51
|
end
|
|
@@ -52,25 +60,34 @@ describe "A PostgreSQL database" do
|
|
|
52
60
|
[:value, {:type=>:blob, :allow_null=>true, :default=>nil, :ruby_default=>nil, :db_type=>"bytea", :primary_key=>false}]
|
|
53
61
|
]
|
|
54
62
|
end
|
|
63
|
+
|
|
64
|
+
specify "should parse foreign keys for tables in a schema" do
|
|
65
|
+
begin
|
|
66
|
+
@db.create_table!(:public__testfk){primary_key :id; foreign_key :i, :public__testfk}
|
|
67
|
+
@db.foreign_key_list(:public__testfk).should == [{:on_delete=>:no_action, :on_update=>:no_action, :columns=>[:i], :key=>[:id], :deferrable=>false, :table=>Sequel.qualify(:public, :testfk), :name=>:testfk_i_fkey}]
|
|
68
|
+
ensure
|
|
69
|
+
@db.drop_table(:public__testfk)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
55
72
|
end
|
|
56
73
|
|
|
57
74
|
describe "A PostgreSQL dataset" do
|
|
58
75
|
before do
|
|
59
76
|
@d = POSTGRES_DB[:test]
|
|
60
77
|
@d.delete # remove all records
|
|
78
|
+
POSTGRES_DB.sqls.clear
|
|
61
79
|
end
|
|
62
|
-
|
|
80
|
+
|
|
63
81
|
specify "should quote columns and tables using double quotes if quoting identifiers" do
|
|
64
|
-
@d.quote_identifiers = true
|
|
65
82
|
@d.select(:name).sql.should == \
|
|
66
83
|
'SELECT "name" FROM "test"'
|
|
67
|
-
|
|
84
|
+
|
|
68
85
|
@d.select('COUNT(*)'.lit).sql.should == \
|
|
69
86
|
'SELECT COUNT(*) FROM "test"'
|
|
70
87
|
|
|
71
88
|
@d.select(:max.sql_function(:value)).sql.should == \
|
|
72
89
|
'SELECT max("value") FROM "test"'
|
|
73
|
-
|
|
90
|
+
|
|
74
91
|
@d.select(:NOW.sql_function).sql.should == \
|
|
75
92
|
'SELECT NOW() FROM "test"'
|
|
76
93
|
|
|
@@ -82,34 +99,32 @@ describe "A PostgreSQL dataset" do
|
|
|
82
99
|
|
|
83
100
|
@d.select('test.name AS item_name'.lit).sql.should == \
|
|
84
101
|
'SELECT test.name AS item_name FROM "test"'
|
|
85
|
-
|
|
102
|
+
|
|
86
103
|
@d.select('"name"'.lit).sql.should == \
|
|
87
104
|
'SELECT "name" FROM "test"'
|
|
88
105
|
|
|
89
106
|
@d.select('max(test."name") AS "max_name"'.lit).sql.should == \
|
|
90
107
|
'SELECT max(test."name") AS "max_name" FROM "test"'
|
|
91
|
-
|
|
92
|
-
@d.select(:test.sql_function(:abc, 'hello')).sql.should == \
|
|
93
|
-
"SELECT test(\"abc\", 'hello') FROM \"test\""
|
|
94
108
|
|
|
95
|
-
@d.
|
|
96
|
-
"
|
|
109
|
+
@d.insert_sql(:x => :y).should =~ \
|
|
110
|
+
/\AINSERT INTO "test" \("x"\) VALUES \("y"\)( RETURNING NULL)?\z/
|
|
97
111
|
|
|
98
|
-
|
|
99
|
-
|
|
112
|
+
if check_sqls
|
|
113
|
+
@d.select(:test.sql_function(:abc, 'hello')).sql.should == \
|
|
114
|
+
"SELECT test(\"abc\", 'hello') FROM \"test\""
|
|
100
115
|
|
|
101
|
-
|
|
102
|
-
|
|
116
|
+
@d.select(:test.sql_function(:abc__def, 'hello')).sql.should == \
|
|
117
|
+
"SELECT test(\"abc\".\"def\", 'hello') FROM \"test\""
|
|
103
118
|
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
@d.select(:test.sql_function(:abc__def, 'hello').as(:x2)).sql.should == \
|
|
120
|
+
"SELECT test(\"abc\".\"def\", 'hello') AS \"x2\" FROM \"test\""
|
|
106
121
|
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
@d.insert_sql(:value => 333).should =~ \
|
|
123
|
+
/\AINSERT INTO "test" \("value"\) VALUES \(333\)( RETURNING NULL)?\z/
|
|
124
|
+
end
|
|
109
125
|
end
|
|
110
|
-
|
|
126
|
+
|
|
111
127
|
specify "should quote fields correctly when reversing the order if quoting identifiers" do
|
|
112
|
-
@d.quote_identifiers = true
|
|
113
128
|
@d.reverse_order(:name).sql.should == \
|
|
114
129
|
'SELECT * FROM "test" ORDER BY "name" DESC'
|
|
115
130
|
|
|
@@ -129,7 +144,7 @@ describe "A PostgreSQL dataset" do
|
|
|
129
144
|
@d.filter(:name => /bc/).count.should == 2
|
|
130
145
|
@d.filter(:name => /^bc/).count.should == 1
|
|
131
146
|
end
|
|
132
|
-
|
|
147
|
+
|
|
133
148
|
specify "should support NULLS FIRST and NULLS LAST" do
|
|
134
149
|
@d << {:name => 'abc'}
|
|
135
150
|
@d << {:name => 'bcd'}
|
|
@@ -138,23 +153,138 @@ describe "A PostgreSQL dataset" do
|
|
|
138
153
|
@d.order(:value.asc(:nulls=>:last), :name).select_map(:name).should == %w[bcd abc bcd]
|
|
139
154
|
@d.order(:value.asc(:nulls=>:first), :name).reverse.select_map(:name).should == %w[bcd bcd abc]
|
|
140
155
|
end
|
|
141
|
-
|
|
156
|
+
|
|
142
157
|
specify "#lock should lock tables and yield if a block is given" do
|
|
143
158
|
@d.lock('EXCLUSIVE'){@d.insert(:name=>'a')}
|
|
144
159
|
end
|
|
145
|
-
|
|
160
|
+
|
|
161
|
+
specify "should support :using when altering a column's type" do
|
|
162
|
+
begin
|
|
163
|
+
@db = POSTGRES_DB
|
|
164
|
+
@db.create_table!(:atest){Integer :t}
|
|
165
|
+
@db[:atest].insert(1262304000)
|
|
166
|
+
@db.alter_table(:atest){set_column_type :t, Time, :using=>'epoch'.cast(Time) + '1 second'.cast(:interval) * :t}
|
|
167
|
+
@db[:atest].get(:t.extract(:year)).should == 2010
|
|
168
|
+
ensure
|
|
169
|
+
@db.drop_table?(:atest)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
specify "should support :using with a string when altering a column's type" do
|
|
174
|
+
begin
|
|
175
|
+
@db = POSTGRES_DB
|
|
176
|
+
@db.create_table!(:atest){Integer :t}
|
|
177
|
+
@db[:atest].insert(1262304000)
|
|
178
|
+
@db.alter_table(:atest){set_column_type :t, Time, :using=>"'epoch'::timestamp + '1 second'::interval * t"}
|
|
179
|
+
@db[:atest].get(:t.extract(:year)).should == 2010
|
|
180
|
+
ensure
|
|
181
|
+
@db.drop_table?(:atest)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
specify "should have #transaction support various types of synchronous options" do
|
|
186
|
+
@db = POSTGRES_DB
|
|
187
|
+
@db.transaction(:synchronous=>:on){}
|
|
188
|
+
@db.transaction(:synchronous=>true){}
|
|
189
|
+
@db.transaction(:synchronous=>:off){}
|
|
190
|
+
@db.transaction(:synchronous=>false){}
|
|
191
|
+
@db.sqls.grep(/synchronous/).should == ["SET LOCAL synchronous_commit = on", "SET LOCAL synchronous_commit = on", "SET LOCAL synchronous_commit = off", "SET LOCAL synchronous_commit = off"]
|
|
192
|
+
|
|
193
|
+
@db.sqls.clear
|
|
194
|
+
@db.transaction(:synchronous=>nil){}
|
|
195
|
+
@db.sqls.should == ['BEGIN', 'COMMIT']
|
|
196
|
+
|
|
197
|
+
if @db.server_version >= 90100
|
|
198
|
+
@db.sqls.clear
|
|
199
|
+
@db.transaction(:synchronous=>:local){}
|
|
200
|
+
@db.sqls.grep(/synchronous/).should == ["SET LOCAL synchronous_commit = local"]
|
|
201
|
+
|
|
202
|
+
if @db.server_version >= 90200
|
|
203
|
+
@db.sqls.clear
|
|
204
|
+
@db.transaction(:synchronous=>:remote_write){}
|
|
205
|
+
@db.sqls.grep(/synchronous/).should == ["SET LOCAL synchronous_commit = remote_write"]
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
specify "should have #transaction support read only transactions" do
|
|
211
|
+
@db = POSTGRES_DB
|
|
212
|
+
@db.transaction(:read_only=>true){}
|
|
213
|
+
@db.transaction(:read_only=>false){}
|
|
214
|
+
@db.transaction(:isolation=>:serializable, :read_only=>true){}
|
|
215
|
+
@db.transaction(:isolation=>:serializable, :read_only=>false){}
|
|
216
|
+
@db.sqls.grep(/READ/).should == ["SET TRANSACTION READ ONLY", "SET TRANSACTION READ WRITE", "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY", "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE READ WRITE"]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
specify "should have #transaction support deferrable transactions" do
|
|
220
|
+
@db = POSTGRES_DB
|
|
221
|
+
@db.transaction(:deferrable=>true){}
|
|
222
|
+
@db.transaction(:deferrable=>false){}
|
|
223
|
+
@db.transaction(:deferrable=>true, :read_only=>true){}
|
|
224
|
+
@db.transaction(:deferrable=>false, :read_only=>false){}
|
|
225
|
+
@db.transaction(:isolation=>:serializable, :deferrable=>true, :read_only=>true){}
|
|
226
|
+
@db.transaction(:isolation=>:serializable, :deferrable=>false, :read_only=>false){}
|
|
227
|
+
@db.sqls.grep(/DEF/).should == ["SET TRANSACTION DEFERRABLE", "SET TRANSACTION NOT DEFERRABLE", "SET TRANSACTION READ ONLY DEFERRABLE", "SET TRANSACTION READ WRITE NOT DEFERRABLE", "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE", "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE READ WRITE NOT DEFERRABLE"]
|
|
228
|
+
end if POSTGRES_DB.server_version >= 90100
|
|
229
|
+
|
|
230
|
+
specify "should support creating indexes concurrently" do
|
|
231
|
+
POSTGRES_DB.sqls.clear
|
|
232
|
+
POSTGRES_DB.add_index :test, [:name, :value], :concurrently=>true
|
|
233
|
+
POSTGRES_DB.sqls.should == ['CREATE INDEX CONCURRENTLY "test_name_value_index" ON "test" ("name", "value")'] if check_sqls
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
specify "should support dropping indexes only if they already exist" do
|
|
237
|
+
POSTGRES_DB.add_index :test, [:name, :value], :name=>'tnv1'
|
|
238
|
+
POSTGRES_DB.sqls.clear
|
|
239
|
+
POSTGRES_DB.drop_index :test, [:name, :value], :if_exists=>true, :name=>'tnv1'
|
|
240
|
+
POSTGRES_DB.sqls.should == ['DROP INDEX IF EXISTS "tnv1"']
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
specify "should support CASCADE when dropping indexes" do
|
|
244
|
+
POSTGRES_DB.add_index :test, [:name, :value], :name=>'tnv2'
|
|
245
|
+
POSTGRES_DB.sqls.clear
|
|
246
|
+
POSTGRES_DB.drop_index :test, [:name, :value], :cascade=>true, :name=>'tnv2'
|
|
247
|
+
POSTGRES_DB.sqls.should == ['DROP INDEX "tnv2" CASCADE']
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
specify "should support dropping indexes concurrently" do
|
|
251
|
+
POSTGRES_DB.add_index :test, [:name, :value], :name=>'tnv2'
|
|
252
|
+
POSTGRES_DB.sqls.clear
|
|
253
|
+
POSTGRES_DB.drop_index :test, [:name, :value], :concurrently=>true, :name=>'tnv2'
|
|
254
|
+
POSTGRES_DB.sqls.should == ['DROP INDEX CONCURRENTLY "tnv2"']
|
|
255
|
+
end if POSTGRES_DB.server_version >= 90200
|
|
256
|
+
|
|
146
257
|
specify "#lock should lock table if inside a transaction" do
|
|
147
258
|
POSTGRES_DB.transaction{@d.lock('EXCLUSIVE'); @d.insert(:name=>'a')}
|
|
148
259
|
end
|
|
149
|
-
|
|
260
|
+
|
|
150
261
|
specify "#lock should return nil" do
|
|
151
262
|
@d.lock('EXCLUSIVE'){@d.insert(:name=>'a')}.should == nil
|
|
152
263
|
POSTGRES_DB.transaction{@d.lock('EXCLUSIVE').should == nil; @d.insert(:name=>'a')}
|
|
153
264
|
end
|
|
154
|
-
|
|
265
|
+
|
|
155
266
|
specify "should raise an error if attempting to update a joined dataset with a single FROM table" do
|
|
156
267
|
proc{POSTGRES_DB[:test].join(:test2, [:name]).update(:name=>'a')}.should raise_error(Sequel::Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs')
|
|
157
268
|
end
|
|
269
|
+
|
|
270
|
+
specify "should truncate with options" do
|
|
271
|
+
@d << { :name => 'abc', :value => 1}
|
|
272
|
+
@d.count.should == 1
|
|
273
|
+
@d.truncate(:cascade => true)
|
|
274
|
+
@d.count.should == 0
|
|
275
|
+
if @d.db.server_version > 80400
|
|
276
|
+
@d << { :name => 'abc', :value => 1}
|
|
277
|
+
@d.truncate(:cascade => true, :only=>true, :restart=>true)
|
|
278
|
+
@d.count.should == 0
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
specify "should truncate multiple tables at once" do
|
|
283
|
+
tables = [:test, :test2, :test3, :test4]
|
|
284
|
+
tables.each{|t| @d.from(t).insert}
|
|
285
|
+
@d.from(:test, :test2, :test3, :test4).truncate
|
|
286
|
+
tables.each{|t| @d.from(t).count.should == 0}
|
|
287
|
+
end
|
|
158
288
|
end
|
|
159
289
|
|
|
160
290
|
describe "Dataset#distinct" do
|
|
@@ -167,9 +297,9 @@ describe "Dataset#distinct" do
|
|
|
167
297
|
@ds = @db[:a]
|
|
168
298
|
end
|
|
169
299
|
after do
|
|
170
|
-
@db.drop_table(:a)
|
|
300
|
+
@db.drop_table?(:a)
|
|
171
301
|
end
|
|
172
|
-
|
|
302
|
+
|
|
173
303
|
it "#distinct with arguments should return results distinct on those arguments" do
|
|
174
304
|
@ds.insert(20, 10)
|
|
175
305
|
@ds.insert(30, 10)
|
|
@@ -191,41 +321,45 @@ if POSTGRES_DB.pool.respond_to?(:max_size) and POSTGRES_DB.pool.max_size > 1
|
|
|
191
321
|
@ds = POSTGRES_DB[:items]
|
|
192
322
|
end
|
|
193
323
|
after do
|
|
194
|
-
POSTGRES_DB.drop_table(:items)
|
|
324
|
+
POSTGRES_DB.drop_table?(:items)
|
|
195
325
|
POSTGRES_DB.disconnect
|
|
196
326
|
end
|
|
197
|
-
|
|
327
|
+
|
|
198
328
|
specify "should handle FOR UPDATE" do
|
|
199
329
|
@ds.insert(:number=>20)
|
|
200
|
-
c = nil
|
|
201
|
-
|
|
330
|
+
c, t = nil, nil
|
|
331
|
+
q = Queue.new
|
|
202
332
|
POSTGRES_DB.transaction do
|
|
203
333
|
@ds.for_update.first(:id=>1)
|
|
204
334
|
t = Thread.new do
|
|
205
335
|
POSTGRES_DB.transaction do
|
|
336
|
+
q.push nil
|
|
206
337
|
@ds.filter(:id=>1).update(:name=>'Jim')
|
|
207
338
|
c = @ds.first(:id=>1)
|
|
339
|
+
q.push nil
|
|
208
340
|
end
|
|
209
341
|
end
|
|
210
|
-
|
|
342
|
+
q.pop
|
|
211
343
|
@ds.filter(:id=>1).update(:number=>30)
|
|
212
344
|
end
|
|
345
|
+
q.pop
|
|
213
346
|
t.join
|
|
214
347
|
c.should == {:id=>1, :number=>30, :name=>'Jim'}
|
|
215
348
|
end
|
|
216
|
-
|
|
349
|
+
|
|
217
350
|
specify "should handle FOR SHARE" do
|
|
218
351
|
@ds.insert(:number=>20)
|
|
219
|
-
c = nil
|
|
220
|
-
|
|
352
|
+
c, t = nil
|
|
353
|
+
q = Queue.new
|
|
221
354
|
POSTGRES_DB.transaction do
|
|
222
355
|
@ds.for_share.first(:id=>1)
|
|
223
356
|
t = Thread.new do
|
|
224
357
|
POSTGRES_DB.transaction do
|
|
225
358
|
c = @ds.for_share.filter(:id=>1).first
|
|
359
|
+
q.push nil
|
|
226
360
|
end
|
|
227
361
|
end
|
|
228
|
-
|
|
362
|
+
q.pop
|
|
229
363
|
@ds.filter(:id=>1).update(:name=>'Jim')
|
|
230
364
|
c.should == {:id=>1, :number=>20, :name=>nil}
|
|
231
365
|
end
|
|
@@ -236,26 +370,59 @@ end
|
|
|
236
370
|
|
|
237
371
|
describe "A PostgreSQL dataset with a timestamp field" do
|
|
238
372
|
before do
|
|
239
|
-
@
|
|
373
|
+
@db = POSTGRES_DB
|
|
374
|
+
@d = @db[:test3]
|
|
240
375
|
@d.delete
|
|
241
376
|
end
|
|
377
|
+
after do
|
|
378
|
+
@db.convert_infinite_timestamps = false if @db.adapter_scheme == :postgres
|
|
379
|
+
end
|
|
242
380
|
|
|
243
|
-
cspecify "should store milliseconds in time fields for Time objects", :do do
|
|
381
|
+
cspecify "should store milliseconds in time fields for Time objects", :do, :swift do
|
|
244
382
|
t = Time.now
|
|
245
383
|
@d << {:value=>1, :time=>t}
|
|
246
|
-
t2 = @d[:value =>
|
|
384
|
+
t2 = @d[:value =>1][:time]
|
|
247
385
|
@d.literal(t2).should == @d.literal(t)
|
|
248
386
|
t2.strftime('%Y-%m-%d %H:%M:%S').should == t.strftime('%Y-%m-%d %H:%M:%S')
|
|
249
|
-
t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000 == t.usec
|
|
387
|
+
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).should == t.usec
|
|
250
388
|
end
|
|
251
389
|
|
|
252
|
-
cspecify "should store milliseconds in time fields for DateTime objects", :do do
|
|
390
|
+
cspecify "should store milliseconds in time fields for DateTime objects", :do, :swift do
|
|
253
391
|
t = DateTime.now
|
|
254
392
|
@d << {:value=>1, :time=>t}
|
|
255
|
-
t2 = @d[:value =>
|
|
393
|
+
t2 = @d[:value =>1][:time]
|
|
256
394
|
@d.literal(t2).should == @d.literal(t)
|
|
257
395
|
t2.strftime('%Y-%m-%d %H:%M:%S').should == t.strftime('%Y-%m-%d %H:%M:%S')
|
|
258
|
-
t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000 == t.strftime('%N').to_i/1000
|
|
396
|
+
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).should == t.strftime('%N').to_i/1000
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
if POSTGRES_DB.adapter_scheme == :postgres
|
|
400
|
+
specify "should handle infinite timestamps if convert_infinite_timestamps is set" do
|
|
401
|
+
@d << {:time=>'infinity'.cast(:timestamp)}
|
|
402
|
+
@db.convert_infinite_timestamps = :nil
|
|
403
|
+
@db[:test3].get(:time).should == nil
|
|
404
|
+
@db.convert_infinite_timestamps = :string
|
|
405
|
+
@db[:test3].get(:time).should == 'infinity'
|
|
406
|
+
@db.convert_infinite_timestamps = :float
|
|
407
|
+
@db[:test3].get(:time).should == 1.0/0.0
|
|
408
|
+
|
|
409
|
+
@d.update(:time=>'-infinity'.cast(:timestamp))
|
|
410
|
+
@db.convert_infinite_timestamps = :nil
|
|
411
|
+
@db[:test3].get(:time).should == nil
|
|
412
|
+
@db.convert_infinite_timestamps = :string
|
|
413
|
+
@db[:test3].get(:time).should == '-infinity'
|
|
414
|
+
@db.convert_infinite_timestamps = :float
|
|
415
|
+
@db[:test3].get(:time).should == -1.0/0.0
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
specify "should handle conversions from infinite strings/floats in models" do
|
|
419
|
+
c = Class.new(Sequel::Model(:test3))
|
|
420
|
+
@db.convert_infinite_timestamps = :float
|
|
421
|
+
c.new(:time=>'infinity').time.should == 'infinity'
|
|
422
|
+
c.new(:time=>'-infinity').time.should == '-infinity'
|
|
423
|
+
c.new(:time=>1.0/0.0).time.should == 1.0/0.0
|
|
424
|
+
c.new(:time=>-1.0/0.0).time.should == -1.0/0.0
|
|
425
|
+
end
|
|
259
426
|
end
|
|
260
427
|
end
|
|
261
428
|
|
|
@@ -281,12 +448,12 @@ describe "A PostgreSQL database" do
|
|
|
281
448
|
@db[:test2].columns.should == [:name, :value, :xyz]
|
|
282
449
|
@db[:test2] << {:name => 'mmm', :value => 111}
|
|
283
450
|
@db[:test2].first[:xyz].should == '000'
|
|
284
|
-
|
|
451
|
+
|
|
285
452
|
@db[:test2].columns.should == [:name, :value, :xyz]
|
|
286
453
|
@db.drop_column :test2, :xyz
|
|
287
|
-
|
|
454
|
+
|
|
288
455
|
@db[:test2].columns.should == [:name, :value]
|
|
289
|
-
|
|
456
|
+
|
|
290
457
|
@db[:test2].delete
|
|
291
458
|
@db.add_column :test2, :xyz, :text, :default => '000'
|
|
292
459
|
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 'qqqq'}
|
|
@@ -295,31 +462,31 @@ describe "A PostgreSQL database" do
|
|
|
295
462
|
@db.rename_column :test2, :xyz, :zyx
|
|
296
463
|
@db[:test2].columns.should == [:name, :value, :zyx]
|
|
297
464
|
@db[:test2].first[:zyx].should == 'qqqq'
|
|
298
|
-
|
|
465
|
+
|
|
299
466
|
@db.add_column :test2, :xyz, :float
|
|
300
467
|
@db[:test2].delete
|
|
301
468
|
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
|
|
302
469
|
@db.set_column_type :test2, :xyz, :integer
|
|
303
|
-
|
|
470
|
+
|
|
304
471
|
@db[:test2].first[:xyz].should == 57
|
|
305
472
|
end
|
|
306
|
-
|
|
473
|
+
|
|
307
474
|
specify "#locks should be a dataset returning database locks " do
|
|
308
475
|
@db.locks.should be_a_kind_of(Sequel::Dataset)
|
|
309
476
|
@db.locks.all.should be_a_kind_of(Array)
|
|
310
477
|
end
|
|
311
|
-
end
|
|
478
|
+
end
|
|
312
479
|
|
|
313
480
|
describe "A PostgreSQL database" do
|
|
314
481
|
before do
|
|
315
482
|
@db = POSTGRES_DB
|
|
316
|
-
@db.drop_table(:posts)
|
|
483
|
+
@db.drop_table?(:posts)
|
|
317
484
|
@db.sqls.clear
|
|
318
485
|
end
|
|
319
486
|
after do
|
|
320
|
-
@db.drop_table(:posts)
|
|
487
|
+
@db.drop_table?(:posts)
|
|
321
488
|
end
|
|
322
|
-
|
|
489
|
+
|
|
323
490
|
specify "should support resetting the primary key sequence" do
|
|
324
491
|
@db.create_table(:posts){primary_key :a}
|
|
325
492
|
@db[:posts].insert(:a=>20).should == 20
|
|
@@ -330,7 +497,7 @@ describe "A PostgreSQL database" do
|
|
|
330
497
|
@db[:posts].insert.should == 21
|
|
331
498
|
@db[:posts].order(:a).map(:a).should == [1, 2, 10, 20, 21]
|
|
332
499
|
end
|
|
333
|
-
|
|
500
|
+
|
|
334
501
|
specify "should support specifying Integer/Bignum/Fixnum types in primary keys and have them be auto incrementing" do
|
|
335
502
|
@db.create_table(:posts){primary_key :a, :type=>Integer}
|
|
336
503
|
@db[:posts].insert.should == 1
|
|
@@ -347,22 +514,22 @@ describe "A PostgreSQL database" do
|
|
|
347
514
|
@db.create_table(:posts){Integer :a}
|
|
348
515
|
@db.reset_primary_key_sequence(:posts).should == nil
|
|
349
516
|
end
|
|
350
|
-
|
|
517
|
+
|
|
351
518
|
specify "should support opclass specification" do
|
|
352
519
|
@db.create_table(:posts){text :title; text :body; integer :user_id; index(:user_id, :opclass => :int4_ops, :type => :btree)}
|
|
353
520
|
@db.sqls.should == [
|
|
354
|
-
|
|
355
|
-
|
|
521
|
+
'CREATE TABLE "posts" ("title" text, "body" text, "user_id" integer)',
|
|
522
|
+
'CREATE INDEX "posts_user_id_index" ON "posts" USING btree ("user_id" int4_ops)'
|
|
356
523
|
]
|
|
357
524
|
end
|
|
358
525
|
|
|
359
526
|
specify "should support fulltext indexes and searching" do
|
|
360
527
|
@db.create_table(:posts){text :title; text :body; full_text_index [:title, :body]; full_text_index :title, :language => 'french'}
|
|
361
528
|
@db.sqls.should == [
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
]
|
|
529
|
+
%{CREATE TABLE "posts" ("title" text, "body" text)},
|
|
530
|
+
%{CREATE INDEX "posts_title_body_index" ON "posts" USING gin (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))))},
|
|
531
|
+
%{CREATE INDEX "posts_title_index" ON "posts" USING gin (to_tsvector('french'::regconfig, (COALESCE("title", ''))))}
|
|
532
|
+
] if check_sqls
|
|
366
533
|
|
|
367
534
|
@db[:posts].insert(:title=>'ruby rails', :body=>'yowsa')
|
|
368
535
|
@db[:posts].insert(:title=>'sequel', :body=>'ruby')
|
|
@@ -373,51 +540,54 @@ describe "A PostgreSQL database" do
|
|
|
373
540
|
@db[:posts].full_text_search([:title, :body], ['yowsa', 'rails']).all.should == [:title=>'ruby rails', :body=>'yowsa']
|
|
374
541
|
@db[:posts].full_text_search(:title, 'scooby', :language => 'french').all.should == [{:title=>'ruby scooby', :body=>'x'}]
|
|
375
542
|
@db.sqls.should == [
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
543
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('simple'::regconfig, 'rails'))},
|
|
544
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))) @@ to_tsquery('simple'::regconfig, 'yowsa | rails'))},
|
|
545
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('french'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('french'::regconfig, 'scooby'))}] if check_sqls
|
|
546
|
+
|
|
547
|
+
@db[:posts].full_text_search(:title, :$n).call(:select, :n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
548
|
+
@db[:posts].full_text_search(:title, :$n).prepare(:select, :fts_select).call(:n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
379
549
|
end
|
|
380
550
|
|
|
381
551
|
specify "should support spatial indexes" do
|
|
382
552
|
@db.create_table(:posts){box :geom; spatial_index [:geom]}
|
|
383
553
|
@db.sqls.should == [
|
|
384
|
-
|
|
385
|
-
|
|
554
|
+
'CREATE TABLE "posts" ("geom" box)',
|
|
555
|
+
'CREATE INDEX "posts_geom_index" ON "posts" USING gist ("geom")'
|
|
386
556
|
]
|
|
387
557
|
end
|
|
388
|
-
|
|
558
|
+
|
|
389
559
|
specify "should support indexes with index type" do
|
|
390
560
|
@db.create_table(:posts){varchar :title, :size => 5; index :title, :type => 'hash'}
|
|
391
561
|
@db.sqls.should == [
|
|
392
|
-
|
|
393
|
-
|
|
562
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
563
|
+
'CREATE INDEX "posts_title_index" ON "posts" USING hash ("title")'
|
|
394
564
|
]
|
|
395
565
|
end
|
|
396
|
-
|
|
566
|
+
|
|
397
567
|
specify "should support unique indexes with index type" do
|
|
398
568
|
@db.create_table(:posts){varchar :title, :size => 5; index :title, :type => 'btree', :unique => true}
|
|
399
569
|
@db.sqls.should == [
|
|
400
|
-
|
|
401
|
-
|
|
570
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
571
|
+
'CREATE UNIQUE INDEX "posts_title_index" ON "posts" USING btree ("title")'
|
|
402
572
|
]
|
|
403
573
|
end
|
|
404
|
-
|
|
574
|
+
|
|
405
575
|
specify "should support partial indexes" do
|
|
406
576
|
@db.create_table(:posts){varchar :title, :size => 5; index :title, :where => {:title => '5'}}
|
|
407
577
|
@db.sqls.should == [
|
|
408
|
-
|
|
409
|
-
|
|
578
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
579
|
+
'CREATE INDEX "posts_title_index" ON "posts" ("title") WHERE ("title" = \'5\')'
|
|
410
580
|
]
|
|
411
581
|
end
|
|
412
|
-
|
|
582
|
+
|
|
413
583
|
specify "should support identifiers for table names in indicies" do
|
|
414
584
|
@db.create_table(Sequel::SQL::Identifier.new(:posts)){varchar :title, :size => 5; index :title, :where => {:title => '5'}}
|
|
415
585
|
@db.sqls.should == [
|
|
416
|
-
|
|
417
|
-
|
|
586
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
587
|
+
'CREATE INDEX "posts_title_index" ON "posts" ("title") WHERE ("title" = \'5\')'
|
|
418
588
|
]
|
|
419
589
|
end
|
|
420
|
-
|
|
590
|
+
|
|
421
591
|
specify "should support renaming tables" do
|
|
422
592
|
@db.create_table!(:posts1){primary_key :a}
|
|
423
593
|
@db.rename_table(:posts1, :posts)
|
|
@@ -427,38 +597,33 @@ end
|
|
|
427
597
|
describe "Postgres::Dataset#import" do
|
|
428
598
|
before do
|
|
429
599
|
@db = POSTGRES_DB
|
|
430
|
-
@db.create_table!(:test){
|
|
600
|
+
@db.create_table!(:test){primary_key :x; Integer :y}
|
|
431
601
|
@db.sqls.clear
|
|
432
602
|
@ds = @db[:test]
|
|
433
603
|
end
|
|
434
604
|
after do
|
|
435
|
-
@db.drop_table(:test)
|
|
605
|
+
@db.drop_table?(:test)
|
|
436
606
|
end
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
specify "#import should a single insert statement" do
|
|
441
610
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
442
|
-
|
|
443
|
-
@db.sqls.should == [
|
|
444
|
-
'BEGIN',
|
|
445
|
-
'INSERT INTO test (x, y) VALUES (1, 2)',
|
|
446
|
-
'INSERT INTO test (x, y) VALUES (3, 4)',
|
|
447
|
-
'COMMIT'
|
|
448
|
-
]
|
|
611
|
+
@db.sqls.should == ['BEGIN', 'INSERT INTO "test" ("x", "y") VALUES (1, 2), (3, 4)', 'COMMIT']
|
|
449
612
|
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
450
613
|
end
|
|
451
|
-
|
|
452
|
-
specify "#import should
|
|
453
|
-
@ds.
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
614
|
+
|
|
615
|
+
specify "#import should work correctly when returning primary keys" do
|
|
616
|
+
@ds.import([:x, :y], [[1, 2], [3, 4]], :return=>:primary_key).should == [1, 3]
|
|
617
|
+
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
specify "#import should work correctly when returning primary keys with :slice option" do
|
|
621
|
+
@ds.import([:x, :y], [[1, 2], [3, 4]], :return=>:primary_key, :slice=>1).should == [1, 3]
|
|
622
|
+
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
specify "#import should work correctly with an arbitrary returning value" do
|
|
626
|
+
@ds.returning(:y, :x).import([:x, :y], [[1, 2], [3, 4]]).should == [{:y=>2, :x=>1}, {:y=>4, :x=>3}]
|
|
462
627
|
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
463
628
|
end
|
|
464
629
|
end
|
|
@@ -471,7 +636,7 @@ describe "Postgres::Dataset#insert" do
|
|
|
471
636
|
@ds = @db[:test5]
|
|
472
637
|
end
|
|
473
638
|
after do
|
|
474
|
-
@db.drop_table(:test5)
|
|
639
|
+
@db.drop_table?(:test5)
|
|
475
640
|
end
|
|
476
641
|
|
|
477
642
|
specify "should work with static SQL" do
|
|
@@ -480,56 +645,17 @@ describe "Postgres::Dataset#insert" do
|
|
|
480
645
|
@ds.all.should == [{:xid=>1, :value=>10}, {:xid=>2, :value=>20}]
|
|
481
646
|
end
|
|
482
647
|
|
|
483
|
-
specify "should
|
|
484
|
-
@ds.insert(:value
|
|
485
|
-
@ds.
|
|
486
|
-
@ds.meta_def(:server_version){80100}
|
|
487
|
-
@ds.insert(:value=>13).should == 3
|
|
488
|
-
|
|
489
|
-
@db.sqls.reject{|x| x =~ /pg_class/}.should == [
|
|
490
|
-
'INSERT INTO test5 (value) VALUES (10) RETURNING xid',
|
|
491
|
-
'INSERT INTO test5 (value) VALUES (20)',
|
|
492
|
-
"SELECT currval('\"public\".test5_xid_seq')",
|
|
493
|
-
'INSERT INTO test5 (value) VALUES (13)',
|
|
494
|
-
"SELECT currval('\"public\".test5_xid_seq')"
|
|
495
|
-
]
|
|
496
|
-
@ds.all.should == [{:xid=>1, :value=>10}, {:xid=>2, :value=>20}, {:xid=>3, :value=>13}]
|
|
497
|
-
end
|
|
498
|
-
|
|
499
|
-
specify "should call execute_insert if server_version < 80200" do
|
|
500
|
-
@ds.meta_def(:server_version){80100}
|
|
501
|
-
@ds.should_receive(:execute_insert).once.with('INSERT INTO test5 (value) VALUES (10)', :table=>:test5, :values=>{:value=>10})
|
|
502
|
-
@ds.insert(:value=>10)
|
|
503
|
-
end
|
|
504
|
-
|
|
505
|
-
specify "should call execute_insert if disabling insert returning" do
|
|
506
|
-
@ds.disable_insert_returning!
|
|
507
|
-
@ds.should_receive(:execute_insert).once.with('INSERT INTO test5 (value) VALUES (10)', :table=>:test5, :values=>{:value=>10})
|
|
508
|
-
@ds.insert(:value=>10)
|
|
648
|
+
specify "should insert correctly if using a column array and a value array" do
|
|
649
|
+
@ds.insert([:value], [10]).should == 1
|
|
650
|
+
@ds.all.should == [{:xid=>1, :value=>10}]
|
|
509
651
|
end
|
|
510
652
|
|
|
511
|
-
specify "should use INSERT RETURNING
|
|
512
|
-
@ds.
|
|
513
|
-
@
|
|
514
|
-
@db.sqls.last.should == 'INSERT INTO test5 (value) VALUES (10) RETURNING xid'
|
|
515
|
-
end
|
|
516
|
-
|
|
517
|
-
specify "should have insert_returning_sql use the RETURNING keyword" do
|
|
518
|
-
@ds.insert_returning_sql(:xid, :value=>10).should == "INSERT INTO test5 (value) VALUES (10) RETURNING xid"
|
|
519
|
-
@ds.insert_returning_sql('*'.lit, :value=>10).should == "INSERT INTO test5 (value) VALUES (10) RETURNING *"
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
specify "should have insert_select return nil if server_version < 80200" do
|
|
523
|
-
@ds.meta_def(:server_version){80100}
|
|
524
|
-
@ds.insert_select(:value=>10).should == nil
|
|
525
|
-
end
|
|
526
|
-
|
|
527
|
-
specify "should have insert_select return nil if disable_insert_returning is used" do
|
|
528
|
-
@ds.disable_insert_returning.insert_select(:value=>10).should == nil
|
|
653
|
+
specify "should use INSERT RETURNING" do
|
|
654
|
+
@ds.insert(:value=>10).should == 1
|
|
655
|
+
@db.sqls.last.should == 'INSERT INTO "test5" ("value") VALUES (10) RETURNING "xid"' if check_sqls
|
|
529
656
|
end
|
|
530
657
|
|
|
531
|
-
specify "should have insert_select insert the record and return the inserted record
|
|
532
|
-
@ds.meta_def(:server_version){80201}
|
|
658
|
+
specify "should have insert_select insert the record and return the inserted record" do
|
|
533
659
|
h = @ds.insert_select(:value=>10)
|
|
534
660
|
h[:value].should == 10
|
|
535
661
|
@ds.first(:xid=>h[:xid])[:value].should == 10
|
|
@@ -558,11 +684,10 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
558
684
|
POSTGRES_DB.instance_variable_set(:@primary_key_sequences, {})
|
|
559
685
|
end
|
|
560
686
|
after do
|
|
561
|
-
POSTGRES_DB.quote_identifiers = false
|
|
562
687
|
POSTGRES_DB << "DROP SCHEMA schema_test CASCADE"
|
|
563
688
|
POSTGRES_DB.default_schema = nil
|
|
564
689
|
end
|
|
565
|
-
|
|
690
|
+
|
|
566
691
|
specify "should be able to create, drop, select and insert into tables in a given schema" do
|
|
567
692
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
568
693
|
POSTGRES_DB[:schema_test__schema_test].first.should == nil
|
|
@@ -575,19 +700,19 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
575
700
|
POSTGRES_DB.from('schema_test.schema_test'.lit).first.should == nil
|
|
576
701
|
POSTGRES_DB.drop_table(:schema_test.qualify(:schema_test))
|
|
577
702
|
end
|
|
578
|
-
|
|
703
|
+
|
|
579
704
|
specify "#tables should not include tables in a default non-public schema" do
|
|
580
705
|
POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
|
|
581
706
|
POSTGRES_DB.tables.should include(:schema_test)
|
|
582
707
|
POSTGRES_DB.tables.should_not include(:pg_am)
|
|
583
708
|
POSTGRES_DB.tables.should_not include(:domain_udt_usage)
|
|
584
709
|
end
|
|
585
|
-
|
|
710
|
+
|
|
586
711
|
specify "#tables should return tables in the schema provided by the :schema argument" do
|
|
587
712
|
POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
|
|
588
713
|
POSTGRES_DB.tables(:schema=>:schema_test).should == [:schema_test]
|
|
589
714
|
end
|
|
590
|
-
|
|
715
|
+
|
|
591
716
|
specify "#schema should not include columns from tables in a default non-public schema" do
|
|
592
717
|
POSTGRES_DB.create_table(:schema_test__domains){integer :i}
|
|
593
718
|
sch = POSTGRES_DB.schema(:domains)
|
|
@@ -595,7 +720,7 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
595
720
|
cs.should include(:i)
|
|
596
721
|
cs.should_not include(:data_type)
|
|
597
722
|
end
|
|
598
|
-
|
|
723
|
+
|
|
599
724
|
specify "#schema should only include columns from the table in the given :schema argument" do
|
|
600
725
|
POSTGRES_DB.create_table!(:domains){integer :d}
|
|
601
726
|
POSTGRES_DB.create_table(:schema_test__domains){integer :i}
|
|
@@ -605,47 +730,51 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
605
730
|
cs.should_not include(:d)
|
|
606
731
|
POSTGRES_DB.drop_table(:domains)
|
|
607
732
|
end
|
|
608
|
-
|
|
609
|
-
specify "#
|
|
610
|
-
POSTGRES_DB.create_table(:
|
|
611
|
-
POSTGRES_DB.
|
|
612
|
-
|
|
733
|
+
|
|
734
|
+
specify "#schema should raise an exception if columns from tables in two separate schema are returned" do
|
|
735
|
+
POSTGRES_DB.create_table!(:public__domains){integer :d}
|
|
736
|
+
POSTGRES_DB.create_table(:schema_test__domains){integer :i}
|
|
737
|
+
begin
|
|
738
|
+
proc{POSTGRES_DB.schema(:domains)}.should raise_error(Sequel::Error)
|
|
739
|
+
POSTGRES_DB.schema(:public__domains).map{|x| x.first}.should == [:d]
|
|
740
|
+
POSTGRES_DB.schema(:schema_test__domains).map{|x| x.first}.should == [:i]
|
|
741
|
+
ensure
|
|
742
|
+
POSTGRES_DB.drop_table?(:public__domains)
|
|
743
|
+
end
|
|
613
744
|
end
|
|
614
|
-
|
|
745
|
+
|
|
615
746
|
specify "#table_exists? should see if the table is in a given schema" do
|
|
616
747
|
POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
|
|
617
748
|
POSTGRES_DB.table_exists?(:schema_test__schema_test).should == true
|
|
618
749
|
end
|
|
619
|
-
|
|
750
|
+
|
|
620
751
|
specify "should be able to get primary keys for tables in a given schema" do
|
|
621
752
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
622
753
|
POSTGRES_DB.primary_key(:schema_test__schema_test).should == 'i'
|
|
623
754
|
end
|
|
624
|
-
|
|
755
|
+
|
|
625
756
|
specify "should be able to get serial sequences for tables in a given schema" do
|
|
626
757
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
627
758
|
POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test".schema_test_i_seq'
|
|
628
759
|
end
|
|
629
|
-
|
|
760
|
+
|
|
630
761
|
specify "should be able to get serial sequences for tables that have spaces in the name in a given schema" do
|
|
631
|
-
POSTGRES_DB.quote_identifiers = true
|
|
632
762
|
POSTGRES_DB.create_table(:"schema_test__schema test"){primary_key :i}
|
|
633
763
|
POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."schema test_i_seq"'
|
|
634
764
|
end
|
|
635
|
-
|
|
765
|
+
|
|
636
766
|
specify "should be able to get custom sequences for tables in a given schema" do
|
|
637
767
|
POSTGRES_DB << "CREATE SEQUENCE schema_test.kseq"
|
|
638
768
|
POSTGRES_DB.create_table(:schema_test__schema_test){integer :j; primary_key :k, :type=>:integer, :default=>"nextval('schema_test.kseq'::regclass)".lit}
|
|
639
769
|
POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test".kseq'
|
|
640
770
|
end
|
|
641
|
-
|
|
771
|
+
|
|
642
772
|
specify "should be able to get custom sequences for tables that have spaces in the name in a given schema" do
|
|
643
|
-
POSTGRES_DB.quote_identifiers = true
|
|
644
773
|
POSTGRES_DB << "CREATE SEQUENCE schema_test.\"ks eq\""
|
|
645
774
|
POSTGRES_DB.create_table(:"schema_test__schema test"){integer :j; primary_key :k, :type=>:integer, :default=>"nextval('schema_test.\"ks eq\"'::regclass)".lit}
|
|
646
775
|
POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."ks eq"'
|
|
647
776
|
end
|
|
648
|
-
|
|
777
|
+
|
|
649
778
|
specify "#default_schema= should change the default schema used from public" do
|
|
650
779
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
651
780
|
POSTGRES_DB.default_schema = :schema_test
|
|
@@ -661,13 +790,12 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
661
790
|
@db = POSTGRES_DB
|
|
662
791
|
@db.run "DROP SCHEMA s CASCADE" rescue nil
|
|
663
792
|
@db.run "CREATE SCHEMA s"
|
|
664
|
-
|
|
665
|
-
|
|
793
|
+
|
|
666
794
|
@db.create_table(:s__bands){primary_key :id; String :name}
|
|
667
795
|
@db.create_table(:s__albums){primary_key :id; String :name; foreign_key :band_id, :s__bands}
|
|
668
796
|
@db.create_table(:s__tracks){primary_key :id; String :name; foreign_key :album_id, :s__albums}
|
|
669
797
|
@db.create_table(:s__members){primary_key :id; String :name; foreign_key :band_id, :s__bands}
|
|
670
|
-
|
|
798
|
+
|
|
671
799
|
@Band = Class.new(Sequel::Model(:s__bands))
|
|
672
800
|
@Album = Class.new(Sequel::Model(:s__albums))
|
|
673
801
|
@Track = Class.new(Sequel::Model(:s__tracks))
|
|
@@ -676,17 +804,17 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
676
804
|
def @Album.name; :Album; end
|
|
677
805
|
def @Track.name; :Track; end
|
|
678
806
|
def @Member.name; :Member; end
|
|
679
|
-
|
|
807
|
+
|
|
680
808
|
@Band.one_to_many :albums, :class=>@Album, :order=>:name
|
|
681
809
|
@Band.one_to_many :members, :class=>@Member, :order=>:name
|
|
682
810
|
@Album.many_to_one :band, :class=>@Band, :order=>:name
|
|
683
811
|
@Album.one_to_many :tracks, :class=>@Track, :order=>:name
|
|
684
812
|
@Track.many_to_one :album, :class=>@Album, :order=>:name
|
|
685
813
|
@Member.many_to_one :band, :class=>@Band, :order=>:name
|
|
686
|
-
|
|
814
|
+
|
|
687
815
|
@Member.many_to_many :members, :class=>@Member, :join_table=>:s__bands, :right_key=>:id, :left_key=>:id, :left_primary_key=>:band_id, :right_primary_key=>:band_id, :order=>:name
|
|
688
816
|
@Band.many_to_many :tracks, :class=>@Track, :join_table=>:s__albums, :right_key=>:id, :right_primary_key=>:album_id, :order=>:name
|
|
689
|
-
|
|
817
|
+
|
|
690
818
|
@b1 = @Band.create(:name=>"BM")
|
|
691
819
|
@b2 = @Band.create(:name=>"J")
|
|
692
820
|
@a1 = @Album.create(:name=>"BM1", :band=>@b1)
|
|
@@ -703,10 +831,9 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
703
831
|
@m4 = @Member.create(:name=>"JC", :band=>@b2)
|
|
704
832
|
end
|
|
705
833
|
after(:all) do
|
|
706
|
-
@db.quote_identifiers = false
|
|
707
834
|
@db.run "DROP SCHEMA s CASCADE"
|
|
708
835
|
end
|
|
709
|
-
|
|
836
|
+
|
|
710
837
|
specify "should return all eager graphs correctly" do
|
|
711
838
|
bands = @Band.order(:bands__name).eager_graph(:albums).all
|
|
712
839
|
bands.should == [@b1, @b2]
|
|
@@ -886,9 +1013,9 @@ if POSTGRES_DB.dataset.supports_window_functions?
|
|
|
886
1013
|
@ds.insert(:id=>6, :group_id=>2, :amount=>100000)
|
|
887
1014
|
end
|
|
888
1015
|
after do
|
|
889
|
-
@db.drop_table(:i1)
|
|
1016
|
+
@db.drop_table?(:i1)
|
|
890
1017
|
end
|
|
891
|
-
|
|
1018
|
+
|
|
892
1019
|
specify "should give correct results for window functions" do
|
|
893
1020
|
@ds.window(:win, :partition=>:group_id, :order=>:id).select(:id){sum(:over, :args=>amount, :window=>win){}}.all.should ==
|
|
894
1021
|
[{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1000, :id=>4}, {:sum=>11000, :id=>5}, {:sum=>111000, :id=>6}]
|
|
@@ -902,15 +1029,16 @@ if POSTGRES_DB.dataset.supports_window_functions?
|
|
|
902
1029
|
end
|
|
903
1030
|
end
|
|
904
1031
|
|
|
905
|
-
describe "Postgres::Database functions, languages, and triggers" do
|
|
1032
|
+
describe "Postgres::Database functions, languages, schemas, and triggers" do
|
|
906
1033
|
before do
|
|
907
1034
|
@d = POSTGRES_DB
|
|
908
1035
|
end
|
|
909
1036
|
after do
|
|
910
1037
|
@d.drop_function('tf', :if_exists=>true, :cascade=>true)
|
|
911
1038
|
@d.drop_function('tf', :if_exists=>true, :cascade=>true, :args=>%w'integer integer')
|
|
912
|
-
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true)
|
|
913
|
-
@d.
|
|
1039
|
+
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
|
|
1040
|
+
@d.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
|
|
1041
|
+
@d.drop_table?(:test)
|
|
914
1042
|
end
|
|
915
1043
|
|
|
916
1044
|
specify "#create_function and #drop_function should create and drop functions" do
|
|
@@ -923,7 +1051,7 @@ describe "Postgres::Database functions, languages, and triggers" do
|
|
|
923
1051
|
@d.drop_function('tf')
|
|
924
1052
|
proc{@d['SELECT tf()'].all}.should raise_error(Sequel::DatabaseError)
|
|
925
1053
|
end
|
|
926
|
-
|
|
1054
|
+
|
|
927
1055
|
specify "#create_function and #drop_function should support options" do
|
|
928
1056
|
args = ['tf', 'SELECT $1 + $2', {:args=>[[:integer, :a], :integer], :replace=>true, :returns=>:integer, :language=>'SQL', :behavior=>:immutable, :strict=>true, :security_definer=>true, :cost=>2, :set=>{:search_path => 'public'}}]
|
|
929
1057
|
@d.send(:create_function_sql,*args).should =~ /\A\s*CREATE OR REPLACE FUNCTION tf\(a integer, integer\)\s+RETURNS integer\s+LANGUAGE SQL\s+IMMUTABLE\s+STRICT\s+SECURITY DEFINER\s+COST 2\s+SET search_path = public\s+AS 'SELECT \$1 \+ \$2'\s*\z/
|
|
@@ -937,24 +1065,33 @@ describe "Postgres::Database functions, languages, and triggers" do
|
|
|
937
1065
|
# Make sure if exists works
|
|
938
1066
|
@d.drop_function(*args)
|
|
939
1067
|
end
|
|
940
|
-
|
|
1068
|
+
|
|
941
1069
|
specify "#create_language and #drop_language should create and drop languages" do
|
|
942
1070
|
@d.send(:create_language_sql, :plpgsql).should == 'CREATE LANGUAGE plpgsql'
|
|
943
|
-
@d.create_language(:plpgsql, :replace=>true)
|
|
1071
|
+
@d.create_language(:plpgsql, :replace=>true) if @d.server_version < 90000
|
|
944
1072
|
proc{@d.create_language(:plpgsql)}.should raise_error(Sequel::DatabaseError)
|
|
945
1073
|
@d.send(:drop_language_sql, :plpgsql).should == 'DROP LANGUAGE plpgsql'
|
|
946
|
-
@d.drop_language(:plpgsql)
|
|
947
|
-
proc{@d.drop_language(:plpgsql)}.should raise_error(Sequel::DatabaseError)
|
|
1074
|
+
@d.drop_language(:plpgsql) if @d.server_version < 90000
|
|
1075
|
+
proc{@d.drop_language(:plpgsql)}.should raise_error(Sequel::DatabaseError) if @d.server_version < 90000
|
|
948
1076
|
@d.send(:create_language_sql, :plpgsql, :replace=>true, :trusted=>true, :handler=>:a, :validator=>:b).should == (@d.server_version >= 90000 ? 'CREATE OR REPLACE TRUSTED LANGUAGE plpgsql HANDLER a VALIDATOR b' : 'CREATE TRUSTED LANGUAGE plpgsql HANDLER a VALIDATOR b')
|
|
949
1077
|
@d.send(:drop_language_sql, :plpgsql, :if_exists=>true, :cascade=>true).should == 'DROP LANGUAGE IF EXISTS plpgsql CASCADE'
|
|
950
1078
|
# Make sure if exists works
|
|
951
|
-
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true)
|
|
1079
|
+
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
|
|
952
1080
|
end
|
|
953
|
-
|
|
1081
|
+
|
|
1082
|
+
specify "#create_schema and #drop_schema should create and drop schemas" do
|
|
1083
|
+
@d.send(:create_schema_sql, :sequel).should == 'CREATE SCHEMA "sequel"'
|
|
1084
|
+
@d.send(:drop_schema_sql, :sequel).should == 'DROP SCHEMA "sequel"'
|
|
1085
|
+
@d.send(:drop_schema_sql, :sequel, :if_exists=>true, :cascade=>true).should == 'DROP SCHEMA IF EXISTS "sequel" CASCADE'
|
|
1086
|
+
@d.create_schema(:sequel)
|
|
1087
|
+
@d.create_table(:sequel__test){Integer :a}
|
|
1088
|
+
@d.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
|
|
1089
|
+
end
|
|
1090
|
+
|
|
954
1091
|
specify "#create_trigger and #drop_trigger should create and drop triggers" do
|
|
955
|
-
@d.create_language(:plpgsql)
|
|
1092
|
+
@d.create_language(:plpgsql) if @d.server_version < 90000
|
|
956
1093
|
@d.create_function(:tf, 'BEGIN IF NEW.value IS NULL THEN RAISE EXCEPTION \'Blah\'; END IF; RETURN NEW; END;', :language=>:plpgsql, :returns=>:trigger)
|
|
957
|
-
@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()'
|
|
1094
|
+
@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()'
|
|
958
1095
|
@d.create_table(:test){String :name; Integer :value}
|
|
959
1096
|
@d.create_trigger(:test, :identity, :tf, :each_row=>true)
|
|
960
1097
|
@d[:test].insert(:name=>'a', :value=>1)
|
|
@@ -963,32 +1100,32 @@ describe "Postgres::Database functions, languages, and triggers" do
|
|
|
963
1100
|
@d[:test].filter(:name=>'a').all.should == [{:name=>'a', :value=>1}]
|
|
964
1101
|
@d[:test].filter(:name=>'a').update(:value=>3)
|
|
965
1102
|
@d[:test].filter(:name=>'a').all.should == [{:name=>'a', :value=>3}]
|
|
966
|
-
@d.send(:drop_trigger_sql, :test, :identity).should == 'DROP TRIGGER identity ON test'
|
|
1103
|
+
@d.send(:drop_trigger_sql, :test, :identity).should == 'DROP TRIGGER identity ON "test"'
|
|
967
1104
|
@d.drop_trigger(:test, :identity)
|
|
968
|
-
@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\')'
|
|
969
|
-
@d.send(:drop_trigger_sql, :test, :identity, :if_exists=>true, :cascade=>true).should == 'DROP TRIGGER IF EXISTS identity ON test CASCADE'
|
|
1105
|
+
@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\')'
|
|
1106
|
+
@d.send(:drop_trigger_sql, :test, :identity, :if_exists=>true, :cascade=>true).should == 'DROP TRIGGER IF EXISTS identity ON "test" CASCADE'
|
|
970
1107
|
# Make sure if exists works
|
|
971
1108
|
@d.drop_trigger(:test, :identity, :if_exists=>true, :cascade=>true)
|
|
972
1109
|
end
|
|
973
1110
|
end
|
|
974
1111
|
|
|
975
1112
|
if POSTGRES_DB.adapter_scheme == :postgres
|
|
976
|
-
describe "Postgres::Dataset #use_cursor" do
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1113
|
+
describe "Postgres::Dataset #use_cursor" do
|
|
1114
|
+
before(:all) do
|
|
1115
|
+
@db = POSTGRES_DB
|
|
1116
|
+
@db.create_table!(:test_cursor){Integer :x}
|
|
1117
|
+
@db.sqls.clear
|
|
1118
|
+
@ds = @db[:test_cursor]
|
|
1119
|
+
@db.transaction{1001.times{|i| @ds.insert(i)}}
|
|
1120
|
+
end
|
|
1121
|
+
after(:all) do
|
|
1122
|
+
@db.drop_table?(:test_cursor)
|
|
1123
|
+
end
|
|
1124
|
+
|
|
988
1125
|
specify "should return the same results as the non-cursor use" do
|
|
989
1126
|
@ds.all.should == @ds.use_cursor.all
|
|
990
1127
|
end
|
|
991
|
-
|
|
1128
|
+
|
|
992
1129
|
specify "should respect the :rows_per_fetch option" do
|
|
993
1130
|
@db.sqls.clear
|
|
994
1131
|
@ds.use_cursor.all
|
|
@@ -997,7 +1134,7 @@ describe "Postgres::Dataset #use_cursor" do
|
|
|
997
1134
|
@ds.use_cursor(:rows_per_fetch=>100).all
|
|
998
1135
|
@db.sqls.length.should == 15
|
|
999
1136
|
end
|
|
1000
|
-
|
|
1137
|
+
|
|
1001
1138
|
specify "should handle returning inside block" do
|
|
1002
1139
|
def @ds.check_return
|
|
1003
1140
|
use_cursor.each{|r| return}
|
|
@@ -1005,5 +1142,706 @@ describe "Postgres::Dataset #use_cursor" do
|
|
|
1005
1142
|
@ds.check_return
|
|
1006
1143
|
@ds.all.should == @ds.use_cursor.all
|
|
1007
1144
|
end
|
|
1145
|
+
end
|
|
1146
|
+
|
|
1147
|
+
describe "Postgres::PG_NAMED_TYPES" do
|
|
1148
|
+
before do
|
|
1149
|
+
@db = POSTGRES_DB
|
|
1150
|
+
Sequel::Postgres::PG_NAMED_TYPES[:interval] = lambda{|v| v.reverse}
|
|
1151
|
+
@db.reset_conversion_procs
|
|
1152
|
+
end
|
|
1153
|
+
after do
|
|
1154
|
+
Sequel::Postgres::PG_NAMED_TYPES.delete(:interval)
|
|
1155
|
+
@db.reset_conversion_procs
|
|
1156
|
+
@db.drop_table?(:foo)
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
specify "should look up conversion procs by name" do
|
|
1160
|
+
@db.create_table!(:foo){interval :bar}
|
|
1161
|
+
@db[:foo].insert('21 days'.cast(:interval))
|
|
1162
|
+
@db[:foo].get(:bar).should == 'syad 12'
|
|
1163
|
+
end
|
|
1164
|
+
end
|
|
1008
1165
|
end
|
|
1166
|
+
|
|
1167
|
+
if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && POSTGRES_DB.server_version >= 90000
|
|
1168
|
+
describe "Postgres::Database#copy_table" do
|
|
1169
|
+
before(:all) do
|
|
1170
|
+
@db = POSTGRES_DB
|
|
1171
|
+
@db.create_table!(:test_copy){Integer :x; Integer :y}
|
|
1172
|
+
ds = @db[:test_copy]
|
|
1173
|
+
ds.insert(1, 2)
|
|
1174
|
+
ds.insert(3, 4)
|
|
1175
|
+
end
|
|
1176
|
+
after(:all) do
|
|
1177
|
+
@db.drop_table?(:test_copy)
|
|
1178
|
+
end
|
|
1179
|
+
|
|
1180
|
+
specify "without a block or options should return a text version of the table as a single string" do
|
|
1181
|
+
@db.copy_table(:test_copy).should == "1\t2\n3\t4\n"
|
|
1182
|
+
end
|
|
1183
|
+
|
|
1184
|
+
specify "without a block and with :format=>:csv should return a csv version of the table as a single string" do
|
|
1185
|
+
@db.copy_table(:test_copy, :format=>:csv).should == "1,2\n3,4\n"
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
specify "should treat string as SQL code" do
|
|
1189
|
+
@db.copy_table('COPY "test_copy" TO STDOUT').should == "1\t2\n3\t4\n"
|
|
1190
|
+
end
|
|
1191
|
+
|
|
1192
|
+
specify "should respect given :options options" do
|
|
1193
|
+
@db.copy_table(:test_copy, :options=>"FORMAT csv, HEADER TRUE").should == "x,y\n1,2\n3,4\n"
|
|
1194
|
+
end
|
|
1195
|
+
|
|
1196
|
+
specify "should respect given :options options when :format is used" do
|
|
1197
|
+
@db.copy_table(:test_copy, :format=>:csv, :options=>"QUOTE '''', FORCE_QUOTE *").should == "'1','2'\n'3','4'\n"
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
specify "should accept dataset as first argument" do
|
|
1201
|
+
@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"
|
|
1202
|
+
end
|
|
1203
|
+
|
|
1204
|
+
specify "with a block and no options should yield each row as a string in text format" do
|
|
1205
|
+
buf = []
|
|
1206
|
+
@db.copy_table(:test_copy){|b| buf << b}
|
|
1207
|
+
buf.should == ["1\t2\n", "3\t4\n"]
|
|
1208
|
+
end
|
|
1209
|
+
|
|
1210
|
+
specify "with a block and :format=>:csv should yield each row as a string in csv format" do
|
|
1211
|
+
buf = []
|
|
1212
|
+
@db.copy_table(:test_copy, :format=>:csv){|b| buf << b}
|
|
1213
|
+
buf.should == ["1,2\n", "3,4\n"]
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
specify "should work fine when using a block that is terminated early with a following copy_table" do
|
|
1217
|
+
buf = []
|
|
1218
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1219
|
+
buf.should == ["1,2\n"]
|
|
1220
|
+
buf.clear
|
|
1221
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1222
|
+
buf.should == ["1,2\n"]
|
|
1223
|
+
buf.clear
|
|
1224
|
+
@db.copy_table(:test_copy){|b| buf << b}
|
|
1225
|
+
buf.should == ["1\t2\n", "3\t4\n"]
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1228
|
+
specify "should work fine when using a block that is terminated early with a following regular query" do
|
|
1229
|
+
buf = []
|
|
1230
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1231
|
+
buf.should == ["1,2\n"]
|
|
1232
|
+
buf.clear
|
|
1233
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1234
|
+
buf.should == ["1,2\n"]
|
|
1235
|
+
@db[:test_copy].select_order_map(:x).should == [1, 3]
|
|
1236
|
+
end
|
|
1237
|
+
end
|
|
1238
|
+
|
|
1239
|
+
describe "Postgres::Database LISTEN/NOTIFY" do
|
|
1240
|
+
before(:all) do
|
|
1241
|
+
@db = POSTGRES_DB
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
specify "should support listen and notify" do
|
|
1245
|
+
notify_pid = @db.synchronize{|conn| conn.backend_pid}
|
|
1246
|
+
|
|
1247
|
+
called = false
|
|
1248
|
+
@db.listen('foo', :after_listen=>proc{@db.notify('foo')}) do |ev, pid, payload|
|
|
1249
|
+
ev.should == 'foo'
|
|
1250
|
+
pid.should == notify_pid
|
|
1251
|
+
['', nil].should include(payload)
|
|
1252
|
+
called = true
|
|
1253
|
+
end.should == 'foo'
|
|
1254
|
+
called.should be_true
|
|
1255
|
+
|
|
1256
|
+
called = false
|
|
1257
|
+
@db.listen('foo', :after_listen=>proc{@db.notify('foo', :payload=>'bar')}) do |ev, pid, payload|
|
|
1258
|
+
ev.should == 'foo'
|
|
1259
|
+
pid.should == notify_pid
|
|
1260
|
+
payload.should == 'bar'
|
|
1261
|
+
called = true
|
|
1262
|
+
end.should == 'foo'
|
|
1263
|
+
called.should be_true
|
|
1264
|
+
|
|
1265
|
+
@db.listen('foo', :after_listen=>proc{@db.notify('foo')}).should == 'foo'
|
|
1266
|
+
|
|
1267
|
+
called = false
|
|
1268
|
+
called2 = false
|
|
1269
|
+
i = 0
|
|
1270
|
+
@db.listen(['foo', 'bar'], :after_listen=>proc{@db.notify('foo', :payload=>'bar'); @db.notify('bar', :payload=>'foo')}, :loop=>proc{i+=1}) do |ev, pid, payload|
|
|
1271
|
+
if !called
|
|
1272
|
+
ev.should == 'foo'
|
|
1273
|
+
pid.should == notify_pid
|
|
1274
|
+
payload.should == 'bar'
|
|
1275
|
+
called = true
|
|
1276
|
+
else
|
|
1277
|
+
ev.should == 'bar'
|
|
1278
|
+
pid.should == notify_pid
|
|
1279
|
+
payload.should == 'foo'
|
|
1280
|
+
called2 = true
|
|
1281
|
+
break
|
|
1282
|
+
end
|
|
1283
|
+
end.should be_nil
|
|
1284
|
+
called.should be_true
|
|
1285
|
+
called2.should be_true
|
|
1286
|
+
i.should == 1
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
specify "should accept a :timeout option in listen" do
|
|
1290
|
+
@db.listen('foo2', :timeout=>0.001).should == nil
|
|
1291
|
+
called = false
|
|
1292
|
+
@db.listen('foo2', :timeout=>0.001){|ev, pid, payload| called = true}.should == nil
|
|
1293
|
+
called.should be_false
|
|
1294
|
+
i = 0
|
|
1295
|
+
@db.listen('foo2', :timeout=>0.001, :loop=>proc{i+=1; throw :stop if i > 3}){|ev, pid, payload| called = true}.should == nil
|
|
1296
|
+
i.should == 4
|
|
1297
|
+
end unless RUBY_PLATFORM =~ /mingw/ # Ruby freezes on this spec on this platform/version
|
|
1298
|
+
end
|
|
1009
1299
|
end
|
|
1300
|
+
|
|
1301
|
+
describe 'PostgreSQL special float handling' do
|
|
1302
|
+
before do
|
|
1303
|
+
@db = POSTGRES_DB
|
|
1304
|
+
@db.create_table!(:test5){Float :value}
|
|
1305
|
+
@db.sqls.clear
|
|
1306
|
+
@ds = @db[:test5]
|
|
1307
|
+
end
|
|
1308
|
+
after do
|
|
1309
|
+
@db.drop_table?(:test5)
|
|
1310
|
+
end
|
|
1311
|
+
|
|
1312
|
+
if check_sqls
|
|
1313
|
+
specify 'should quote NaN' do
|
|
1314
|
+
nan = 0.0/0.0
|
|
1315
|
+
@ds.insert_sql(:value => nan).should == %q{INSERT INTO "test5" ("value") VALUES ('NaN')}
|
|
1316
|
+
end
|
|
1317
|
+
|
|
1318
|
+
specify 'should quote +Infinity' do
|
|
1319
|
+
inf = 1.0/0.0
|
|
1320
|
+
@ds.insert_sql(:value => inf).should == %q{INSERT INTO "test5" ("value") VALUES ('Infinity')}
|
|
1321
|
+
end
|
|
1322
|
+
|
|
1323
|
+
specify 'should quote -Infinity' do
|
|
1324
|
+
inf = -1.0/0.0
|
|
1325
|
+
@ds.insert_sql(:value => inf).should == %q{INSERT INTO "test5" ("value") VALUES ('-Infinity')}
|
|
1326
|
+
end
|
|
1327
|
+
end
|
|
1328
|
+
|
|
1329
|
+
if POSTGRES_DB.adapter_scheme == :postgres
|
|
1330
|
+
specify 'inserts NaN' do
|
|
1331
|
+
nan = 0.0/0.0
|
|
1332
|
+
@ds.insert(:value=>nan)
|
|
1333
|
+
@ds.all[0][:value].nan?.should be_true
|
|
1334
|
+
end
|
|
1335
|
+
|
|
1336
|
+
specify 'inserts +Infinity' do
|
|
1337
|
+
inf = 1.0/0.0
|
|
1338
|
+
@ds.insert(:value=>inf)
|
|
1339
|
+
@ds.all[0][:value].infinite?.should > 0
|
|
1340
|
+
end
|
|
1341
|
+
|
|
1342
|
+
specify 'inserts -Infinity' do
|
|
1343
|
+
inf = -1.0/0.0
|
|
1344
|
+
@ds.insert(:value=>inf)
|
|
1345
|
+
@ds.all[0][:value].infinite?.should < 0
|
|
1346
|
+
end
|
|
1347
|
+
end
|
|
1348
|
+
end
|
|
1349
|
+
|
|
1350
|
+
describe 'PostgreSQL array handling' do
|
|
1351
|
+
before(:all) do
|
|
1352
|
+
Sequel.extension :pg_array
|
|
1353
|
+
@db = POSTGRES_DB
|
|
1354
|
+
@db.extend Sequel::Postgres::PGArray::DatabaseMethods
|
|
1355
|
+
@ds = @db[:items]
|
|
1356
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1357
|
+
end
|
|
1358
|
+
after do
|
|
1359
|
+
@db.drop_table?(:items)
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
specify 'insert and retrieve integer and float arrays of various sizes' do
|
|
1363
|
+
@db.create_table!(:items) do
|
|
1364
|
+
column :i2, 'int2[]'
|
|
1365
|
+
column :i4, 'int4[]'
|
|
1366
|
+
column :i8, 'int8[]'
|
|
1367
|
+
column :r, 'real[]'
|
|
1368
|
+
column :dp, 'double precision[]'
|
|
1369
|
+
end
|
|
1370
|
+
@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"))
|
|
1371
|
+
@ds.count.should == 1
|
|
1372
|
+
if @native
|
|
1373
|
+
rs = @ds.all
|
|
1374
|
+
rs.should == [{:i2=>[1], :i4=>[nil, 2], :i8=>[3, nil], :r=>[4.0, nil, 4.5], :dp=>[5.0, nil, 5.5]}]
|
|
1375
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1376
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1377
|
+
@ds.delete
|
|
1378
|
+
@ds.insert(rs.first)
|
|
1379
|
+
@ds.all.should == rs
|
|
1380
|
+
|
|
1381
|
+
@ds.delete
|
|
1382
|
+
@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"))
|
|
1383
|
+
rs = @ds.all
|
|
1384
|
+
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]]}]
|
|
1385
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1386
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1387
|
+
@ds.delete
|
|
1388
|
+
@ds.insert(rs.first)
|
|
1389
|
+
@ds.all.should == rs
|
|
1390
|
+
end
|
|
1391
|
+
end
|
|
1392
|
+
|
|
1393
|
+
specify 'insert and retrieve decimal arrays' do
|
|
1394
|
+
@db.create_table!(:items) do
|
|
1395
|
+
column :n, 'numeric[]'
|
|
1396
|
+
end
|
|
1397
|
+
@ds.insert([BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')].pg_array(:numeric))
|
|
1398
|
+
@ds.count.should == 1
|
|
1399
|
+
if @native
|
|
1400
|
+
rs = @ds.all
|
|
1401
|
+
rs.should == [{:n=>[BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')]}]
|
|
1402
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1403
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1404
|
+
@ds.delete
|
|
1405
|
+
@ds.insert(rs.first)
|
|
1406
|
+
@ds.all.should == rs
|
|
1407
|
+
|
|
1408
|
+
@ds.delete
|
|
1409
|
+
@ds.insert([[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]].pg_array(:numeric))
|
|
1410
|
+
rs = @ds.all
|
|
1411
|
+
rs.should == [{:n=>[[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]]}]
|
|
1412
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1413
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1414
|
+
@ds.delete
|
|
1415
|
+
@ds.insert(rs.first)
|
|
1416
|
+
@ds.all.should == rs
|
|
1417
|
+
end
|
|
1418
|
+
end
|
|
1419
|
+
|
|
1420
|
+
specify 'insert and retrieve string arrays' do
|
|
1421
|
+
@db.create_table!(:items) do
|
|
1422
|
+
column :c, 'char(4)[]'
|
|
1423
|
+
column :vc, 'varchar[]'
|
|
1424
|
+
column :t, 'text[]'
|
|
1425
|
+
end
|
|
1426
|
+
@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))
|
|
1427
|
+
@ds.count.should == 1
|
|
1428
|
+
if @native
|
|
1429
|
+
rs = @ds.all
|
|
1430
|
+
rs.should == [{:c=>['a ', nil, 'NULL', 'b"\'c'], :vc=>['a', nil, 'NULL', 'b"\'c'], :t=>['a', nil, 'NULL', 'b"\'c']}]
|
|
1431
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1432
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1433
|
+
@ds.delete
|
|
1434
|
+
@ds.insert(rs.first)
|
|
1435
|
+
@ds.all.should == rs
|
|
1436
|
+
|
|
1437
|
+
@ds.delete
|
|
1438
|
+
@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))
|
|
1439
|
+
rs = @ds.all
|
|
1440
|
+
rs.should == [{:c=>[[['a '], [nil]], [['NULL'], ['b"\'c']]], :vc=>[[['a'], ['']], [['NULL'], ['b"\'c']]], :t=>[[['a'], [nil]], [['NULL'], ['b"\'c']]]}]
|
|
1441
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1442
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1443
|
+
@ds.delete
|
|
1444
|
+
@ds.insert(rs.first)
|
|
1445
|
+
@ds.all.should == rs
|
|
1446
|
+
end
|
|
1447
|
+
end
|
|
1448
|
+
|
|
1449
|
+
specify 'use arrays in bound variables' do
|
|
1450
|
+
@db.create_table!(:items) do
|
|
1451
|
+
column :i, 'int4[]'
|
|
1452
|
+
end
|
|
1453
|
+
@ds.call(:insert, {:i=>[1,2]}, {:i=>:$i})
|
|
1454
|
+
@ds.get(:i).should == [1, 2]
|
|
1455
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[1,2]).should == {:i=>[1,2]}
|
|
1456
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[1,3]).should == nil
|
|
1457
|
+
|
|
1458
|
+
@db.create_table!(:items) do
|
|
1459
|
+
column :i, 'text[]'
|
|
1460
|
+
end
|
|
1461
|
+
a = ["\"\\\\\"{}\n\t\r \v\b123afP", 'NULL', nil, '']
|
|
1462
|
+
@ds.call(:insert, {:i=>:$i}, :i=>a.pg_array)
|
|
1463
|
+
@ds.get(:i).should == a
|
|
1464
|
+
@ds.filter(:i=>:$i).call(:first, :i=>a).should == {:i=>a}
|
|
1465
|
+
@ds.filter(:i=>:$i).call(:first, :i=>['', nil, nil, 'a']).should == nil
|
|
1466
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1467
|
+
|
|
1468
|
+
specify 'with models' do
|
|
1469
|
+
@db.create_table!(:items) do
|
|
1470
|
+
primary_key :id
|
|
1471
|
+
column :i, 'integer[]'
|
|
1472
|
+
column :f, 'double precision[]'
|
|
1473
|
+
column :d, 'numeric[]'
|
|
1474
|
+
column :t, 'text[]'
|
|
1475
|
+
end
|
|
1476
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
1477
|
+
c.plugin :typecast_on_load, :i, :f, :d, :t unless @native
|
|
1478
|
+
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']])
|
|
1479
|
+
o.i.should == [1, 2, nil]
|
|
1480
|
+
o.f.should == [[1, 2.5], [3, 4.5]]
|
|
1481
|
+
o.d.should == [BigDecimal.new('1'), BigDecimal.new('1.000000000000000000001')]
|
|
1482
|
+
o.t.should == [%w'a b c', ['NULL', nil, '1']]
|
|
1483
|
+
end
|
|
1484
|
+
|
|
1485
|
+
specify 'operations/functions with pg_array_ops' do
|
|
1486
|
+
Sequel.extension :pg_array_ops
|
|
1487
|
+
@db.create_table!(:items){column :i, 'integer[]'; column :i2, 'integer[]'; column :i3, 'integer[]'; column :i4, 'integer[]'; column :i5, 'integer[]'}
|
|
1488
|
+
@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)
|
|
1489
|
+
|
|
1490
|
+
@ds.get(:i.pg_array > :i3).should be_false
|
|
1491
|
+
@ds.get(:i3.pg_array > :i).should be_true
|
|
1492
|
+
|
|
1493
|
+
@ds.get(:i.pg_array >= :i3).should be_false
|
|
1494
|
+
@ds.get(:i.pg_array >= :i).should be_true
|
|
1495
|
+
|
|
1496
|
+
@ds.get(:i3.pg_array < :i).should be_false
|
|
1497
|
+
@ds.get(:i.pg_array < :i3).should be_true
|
|
1498
|
+
|
|
1499
|
+
@ds.get(:i3.pg_array <= :i).should be_false
|
|
1500
|
+
@ds.get(:i.pg_array <= :i).should be_true
|
|
1501
|
+
|
|
1502
|
+
@ds.get({5=>:i.pg_array.any}.sql_expr).should be_false
|
|
1503
|
+
@ds.get({1=>:i.pg_array.any}.sql_expr).should be_true
|
|
1504
|
+
|
|
1505
|
+
@ds.get({1=>:i3.pg_array.all}.sql_expr).should be_false
|
|
1506
|
+
@ds.get({4=>:i3.pg_array.all}.sql_expr).should be_true
|
|
1507
|
+
|
|
1508
|
+
@ds.get(:i2.pg_array[1]).should == 2
|
|
1509
|
+
@ds.get(:i2.pg_array[2]).should == 1
|
|
1510
|
+
|
|
1511
|
+
@ds.get(:i4.pg_array[2][1]).should == 4
|
|
1512
|
+
@ds.get(:i4.pg_array[2][2]).should == 3
|
|
1513
|
+
|
|
1514
|
+
@ds.get(:i.pg_array.contains(:i2)).should be_true
|
|
1515
|
+
@ds.get(:i.pg_array.contains(:i3)).should be_false
|
|
1516
|
+
|
|
1517
|
+
@ds.get(:i2.pg_array.contained_by(:i)).should be_true
|
|
1518
|
+
@ds.get(:i.pg_array.contained_by(:i2)).should be_false
|
|
1519
|
+
|
|
1520
|
+
@ds.get(:i.pg_array.overlaps(:i2)).should be_true
|
|
1521
|
+
@ds.get(:i2.pg_array.overlaps(:i3)).should be_false
|
|
1522
|
+
|
|
1523
|
+
@ds.get(:i.pg_array.dims).should == '[1:3]'
|
|
1524
|
+
@ds.get(:i.pg_array.length).should == 3
|
|
1525
|
+
@ds.get(:i.pg_array.lower).should == 1
|
|
1526
|
+
|
|
1527
|
+
if @db.server_version >= 90000
|
|
1528
|
+
@ds.get(:i5.pg_array.join).should == '15'
|
|
1529
|
+
@ds.get(:i5.pg_array.join(':')).should == '1:5'
|
|
1530
|
+
@ds.get(:i5.pg_array.join(':', '*')).should == '1:*:5'
|
|
1531
|
+
end
|
|
1532
|
+
@ds.select(:i.pg_array.unnest).from_self.count.should == 3 if @db.server_version >= 80400
|
|
1533
|
+
|
|
1534
|
+
if @native
|
|
1535
|
+
@ds.get(:i.pg_array.push(4)).should == [1, 2, 3, 4]
|
|
1536
|
+
@ds.get(:i.pg_array.unshift(4)).should == [4, 1, 2, 3]
|
|
1537
|
+
@ds.get(:i.pg_array.concat(:i2)).should == [1, 2, 3, 2, 1]
|
|
1538
|
+
end
|
|
1539
|
+
end
|
|
1540
|
+
end
|
|
1541
|
+
|
|
1542
|
+
describe 'PostgreSQL hstore handling' do
|
|
1543
|
+
before(:all) do
|
|
1544
|
+
Sequel.extension :pg_hstore
|
|
1545
|
+
@db = POSTGRES_DB
|
|
1546
|
+
@db.extend Sequel::Postgres::HStore::DatabaseMethods
|
|
1547
|
+
@ds = @db[:items]
|
|
1548
|
+
@h = {'a'=>'b', 'c'=>nil, 'd'=>'NULL', 'e'=>'\\\\" \\\' ,=>'}
|
|
1549
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1550
|
+
end
|
|
1551
|
+
after do
|
|
1552
|
+
@db.drop_table?(:items)
|
|
1553
|
+
end
|
|
1554
|
+
|
|
1555
|
+
specify 'insert and retrieve hstore values' do
|
|
1556
|
+
@db.create_table!(:items) do
|
|
1557
|
+
column :h, :hstore
|
|
1558
|
+
end
|
|
1559
|
+
@ds.insert(@h.hstore)
|
|
1560
|
+
@ds.count.should == 1
|
|
1561
|
+
if @native
|
|
1562
|
+
rs = @ds.all
|
|
1563
|
+
v = rs.first[:h]
|
|
1564
|
+
v.should_not be_a_kind_of(Hash)
|
|
1565
|
+
v.to_hash.should be_a_kind_of(Hash)
|
|
1566
|
+
v.to_hash.should == @h
|
|
1567
|
+
@ds.delete
|
|
1568
|
+
@ds.insert(rs.first)
|
|
1569
|
+
@ds.all.should == rs
|
|
1570
|
+
end
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
specify 'use hstore in bound variables' do
|
|
1574
|
+
@db.create_table!(:items) do
|
|
1575
|
+
column :i, :hstore
|
|
1576
|
+
end
|
|
1577
|
+
@ds.call(:insert, {:i=>@h.hstore}, {:i=>:$i})
|
|
1578
|
+
@ds.get(:i).should == @h
|
|
1579
|
+
@ds.filter(:i=>:$i).call(:first, :i=>@h.hstore).should == {:i=>@h}
|
|
1580
|
+
@ds.filter(:i=>:$i).call(:first, :i=>{}.hstore).should == nil
|
|
1581
|
+
|
|
1582
|
+
@ds.delete
|
|
1583
|
+
@ds.call(:insert, {:i=>@h}, {:i=>:$i})
|
|
1584
|
+
@ds.get(:i).should == @h
|
|
1585
|
+
@ds.filter(:i=>:$i).call(:first, :i=>@h).should == {:i=>@h}
|
|
1586
|
+
@ds.filter(:i=>:$i).call(:first, :i=>{}).should == nil
|
|
1587
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1588
|
+
|
|
1589
|
+
specify 'with models' do
|
|
1590
|
+
@db.create_table!(:items) do
|
|
1591
|
+
primary_key :id
|
|
1592
|
+
column :h, :hstore
|
|
1593
|
+
end
|
|
1594
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
1595
|
+
c.plugin :typecast_on_load, :h unless @native
|
|
1596
|
+
c.create(:h=>@h.hstore).h.should == @h
|
|
1597
|
+
end
|
|
1598
|
+
|
|
1599
|
+
specify 'operations/functions with pg_hstore_ops' do
|
|
1600
|
+
Sequel.extension :pg_hstore_ops
|
|
1601
|
+
Sequel.extension :pg_array
|
|
1602
|
+
Sequel.extension :pg_array_ops
|
|
1603
|
+
@db.create_table!(:items){hstore :h1; hstore :h2; hstore :h3; String :t}
|
|
1604
|
+
@ds.insert({'a'=>'b', 'c'=>nil}.hstore, {'a'=>'b'}.hstore, {'d'=>'e'}.hstore)
|
|
1605
|
+
h1 = :h1.hstore
|
|
1606
|
+
h2 = :h2.hstore
|
|
1607
|
+
h3 = :h3.hstore
|
|
1608
|
+
|
|
1609
|
+
@ds.get(h1['a']).should == 'b'
|
|
1610
|
+
@ds.get(h1['d']).should == nil
|
|
1611
|
+
|
|
1612
|
+
@ds.get(h2.concat(h3).keys.pg_array.length).should == 2
|
|
1613
|
+
@ds.get(h1.concat(h3).keys.pg_array.length).should == 3
|
|
1614
|
+
@ds.get(h2.merge(h3).keys.pg_array.length).should == 2
|
|
1615
|
+
@ds.get(h1.merge(h3).keys.pg_array.length).should == 3
|
|
1616
|
+
|
|
1617
|
+
unless @db.adapter_scheme == :do
|
|
1618
|
+
# Broken DataObjects thinks operators with ? represent placeholders
|
|
1619
|
+
@ds.get(h1.contain_all(%w'a c'.pg_array)).should == true
|
|
1620
|
+
@ds.get(h1.contain_all(%w'a d'.pg_array)).should == false
|
|
1621
|
+
|
|
1622
|
+
@ds.get(h1.contain_any(%w'a d'.pg_array)).should == true
|
|
1623
|
+
@ds.get(h1.contain_any(%w'e d'.pg_array)).should == false
|
|
1624
|
+
end
|
|
1625
|
+
|
|
1626
|
+
@ds.get(h1.contains(h2)).should == true
|
|
1627
|
+
@ds.get(h1.contains(h3)).should == false
|
|
1628
|
+
|
|
1629
|
+
@ds.get(h2.contained_by(h1)).should == true
|
|
1630
|
+
@ds.get(h2.contained_by(h3)).should == false
|
|
1631
|
+
|
|
1632
|
+
@ds.get(h1.defined('a')).should == true
|
|
1633
|
+
@ds.get(h1.defined('c')).should == false
|
|
1634
|
+
@ds.get(h1.defined('d')).should == false
|
|
1635
|
+
|
|
1636
|
+
@ds.get(h1.delete('a')['c']).should == nil
|
|
1637
|
+
@ds.get(h1.delete(%w'a d'.pg_array)['c']).should == nil
|
|
1638
|
+
@ds.get(h1.delete(h2)['c']).should == nil
|
|
1639
|
+
|
|
1640
|
+
@ds.from({'a'=>'b', 'c'=>nil}.hstore.op.each).order(:key).all.should == [{:key=>'a', :value=>'b'}, {:key=>'c', :value=>nil}]
|
|
1641
|
+
|
|
1642
|
+
unless @db.adapter_scheme == :do
|
|
1643
|
+
@ds.get(h1.has_key?('c')).should == true
|
|
1644
|
+
@ds.get(h1.include?('c')).should == true
|
|
1645
|
+
@ds.get(h1.key?('c')).should == true
|
|
1646
|
+
@ds.get(h1.member?('c')).should == true
|
|
1647
|
+
@ds.get(h1.exist?('c')).should == true
|
|
1648
|
+
@ds.get(h1.has_key?('d')).should == false
|
|
1649
|
+
@ds.get(h1.include?('d')).should == false
|
|
1650
|
+
@ds.get(h1.key?('d')).should == false
|
|
1651
|
+
@ds.get(h1.member?('d')).should == false
|
|
1652
|
+
@ds.get(h1.exist?('d')).should == false
|
|
1653
|
+
end
|
|
1654
|
+
|
|
1655
|
+
@ds.get(h1.hstore.hstore.hstore.keys.pg_array.length).should == 2
|
|
1656
|
+
@ds.get(h1.keys.pg_array.length).should == 2
|
|
1657
|
+
@ds.get(h2.keys.pg_array.length).should == 1
|
|
1658
|
+
@ds.get(h1.akeys.pg_array.length).should == 2
|
|
1659
|
+
@ds.get(h2.akeys.pg_array.length).should == 1
|
|
1660
|
+
|
|
1661
|
+
@ds.from({'t'=>'s'}.hstore.op.populate(Sequel::SQL::Cast.new(nil, :items))).select_map(:t).should == ['s']
|
|
1662
|
+
@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']
|
|
1663
|
+
|
|
1664
|
+
@ds.from({'t'=>'s', 'a'=>'b'}.hstore.op.skeys.as(:s)).select_order_map(:s).should == %w'a t'
|
|
1665
|
+
|
|
1666
|
+
@ds.get(h1.slice(%w'a c'.pg_array).keys.pg_array.length).should == 2
|
|
1667
|
+
@ds.get(h1.slice(%w'd c'.pg_array).keys.pg_array.length).should == 1
|
|
1668
|
+
@ds.get(h1.slice(%w'd e'.pg_array).keys.pg_array.length).should == nil
|
|
1669
|
+
|
|
1670
|
+
@ds.from({'t'=>'s', 'a'=>'b'}.hstore.op.svals.as(:s)).select_order_map(:s).should == %w'b s'
|
|
1671
|
+
|
|
1672
|
+
@ds.get(h1.to_array.pg_array.length).should == 4
|
|
1673
|
+
@ds.get(h2.to_array.pg_array.length).should == 2
|
|
1674
|
+
|
|
1675
|
+
@ds.get(h1.to_matrix.pg_array.length).should == 2
|
|
1676
|
+
@ds.get(h2.to_matrix.pg_array.length).should == 1
|
|
1677
|
+
|
|
1678
|
+
@ds.get(h1.values.pg_array.length).should == 2
|
|
1679
|
+
@ds.get(h2.values.pg_array.length).should == 1
|
|
1680
|
+
@ds.get(h1.avals.pg_array.length).should == 2
|
|
1681
|
+
@ds.get(h2.avals.pg_array.length).should == 1
|
|
1682
|
+
end
|
|
1683
|
+
end if POSTGRES_DB.type_supported?(:hstore)
|
|
1684
|
+
|
|
1685
|
+
describe 'PostgreSQL json type' do
|
|
1686
|
+
before(:all) do
|
|
1687
|
+
Sequel.extension :pg_json
|
|
1688
|
+
@db = POSTGRES_DB
|
|
1689
|
+
@db.extend Sequel::Postgres::JSONDatabaseMethods
|
|
1690
|
+
@ds = @db[:items]
|
|
1691
|
+
@a = [1, 2, {'a'=>'b'}, 3.0]
|
|
1692
|
+
@h = {'a'=>'b', '1'=>[3, 4, 5]}
|
|
1693
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1694
|
+
end
|
|
1695
|
+
after do
|
|
1696
|
+
@db.drop_table?(:items)
|
|
1697
|
+
end
|
|
1698
|
+
|
|
1699
|
+
specify 'insert and retrieve json values' do
|
|
1700
|
+
@db.create_table!(:items){json :j}
|
|
1701
|
+
@ds.insert(@h.pg_json)
|
|
1702
|
+
@ds.count.should == 1
|
|
1703
|
+
if @native
|
|
1704
|
+
rs = @ds.all
|
|
1705
|
+
v = rs.first[:j]
|
|
1706
|
+
v.should_not be_a_kind_of(Hash)
|
|
1707
|
+
v.to_hash.should be_a_kind_of(Hash)
|
|
1708
|
+
v.should == @h
|
|
1709
|
+
v.to_hash.should == @h
|
|
1710
|
+
@ds.delete
|
|
1711
|
+
@ds.insert(rs.first)
|
|
1712
|
+
@ds.all.should == rs
|
|
1713
|
+
end
|
|
1714
|
+
|
|
1715
|
+
@ds.delete
|
|
1716
|
+
@ds.insert(@a.pg_json)
|
|
1717
|
+
@ds.count.should == 1
|
|
1718
|
+
if @native
|
|
1719
|
+
rs = @ds.all
|
|
1720
|
+
v = rs.first[:j]
|
|
1721
|
+
v.should_not be_a_kind_of(Array)
|
|
1722
|
+
v.to_a.should be_a_kind_of(Array)
|
|
1723
|
+
v.should == @a
|
|
1724
|
+
v.to_a.should == @a
|
|
1725
|
+
@ds.delete
|
|
1726
|
+
@ds.insert(rs.first)
|
|
1727
|
+
@ds.all.should == rs
|
|
1728
|
+
end
|
|
1729
|
+
end
|
|
1730
|
+
|
|
1731
|
+
specify 'use json in bound variables' do
|
|
1732
|
+
@db.create_table!(:items){json :i}
|
|
1733
|
+
@ds.call(:insert, {:i=>@h.pg_json}, {:i=>:$i})
|
|
1734
|
+
@ds.get(:i).should == @h
|
|
1735
|
+
@ds.filter(:i.cast(String)=>:$i).call(:first, :i=>@h.pg_json).should == {:i=>@h}
|
|
1736
|
+
@ds.filter(:i.cast(String)=>:$i).call(:first, :i=>{}.pg_json).should == nil
|
|
1737
|
+
@ds.filter(:i.cast(String)=>:$i).call(:delete, :i=>@h.pg_json).should == 1
|
|
1738
|
+
|
|
1739
|
+
@ds.call(:insert, {:i=>@a.pg_json}, {:i=>:$i})
|
|
1740
|
+
@ds.get(:i).should == @a
|
|
1741
|
+
@ds.filter(:i.cast(String)=>:$i).call(:first, :i=>@a.pg_json).should == {:i=>@a}
|
|
1742
|
+
@ds.filter(:i.cast(String)=>:$i).call(:first, :i=>[].pg_json).should == nil
|
|
1743
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1744
|
+
|
|
1745
|
+
specify 'with models' do
|
|
1746
|
+
@db.create_table!(:items) do
|
|
1747
|
+
primary_key :id
|
|
1748
|
+
json :h
|
|
1749
|
+
end
|
|
1750
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
1751
|
+
c.plugin :typecast_on_load, :h unless @native
|
|
1752
|
+
c.create(:h=>@h.pg_json).h.should == @h
|
|
1753
|
+
c.create(:h=>@a.pg_json).h.should == @a
|
|
1754
|
+
end
|
|
1755
|
+
end if POSTGRES_DB.server_version >= 90200
|
|
1756
|
+
|
|
1757
|
+
describe 'PostgreSQL inet/cidr types' do
|
|
1758
|
+
ipv6_broken = (IPAddr.new('::1'); false) rescue true
|
|
1759
|
+
|
|
1760
|
+
before(:all) do
|
|
1761
|
+
Sequel.extension :pg_inet
|
|
1762
|
+
@db = POSTGRES_DB
|
|
1763
|
+
@db.extend Sequel::Postgres::InetDatabaseMethods
|
|
1764
|
+
@ds = @db[:items]
|
|
1765
|
+
@v4 = '127.0.0.1'
|
|
1766
|
+
@v4nm = '127.0.0.0/8'
|
|
1767
|
+
@v6 = '2001:4f8:3:ba:2e0:81ff:fe22:d1f1'
|
|
1768
|
+
@v6nm = '2001:4f8:3:ba::/64'
|
|
1769
|
+
@ipv4 = IPAddr.new(@v4)
|
|
1770
|
+
@ipv4nm = IPAddr.new(@v4nm)
|
|
1771
|
+
unless ipv6_broken
|
|
1772
|
+
@ipv6 = IPAddr.new(@v6)
|
|
1773
|
+
@ipv6nm = IPAddr.new(@v6nm)
|
|
1774
|
+
end
|
|
1775
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1776
|
+
end
|
|
1777
|
+
after do
|
|
1778
|
+
@db.drop_table?(:items)
|
|
1779
|
+
end
|
|
1780
|
+
|
|
1781
|
+
specify 'insert and retrieve inet/cidr values' do
|
|
1782
|
+
@db.create_table!(:items){inet :i; cidr :c}
|
|
1783
|
+
@ds.insert(@ipv4, @ipv4nm)
|
|
1784
|
+
@ds.count.should == 1
|
|
1785
|
+
if @native
|
|
1786
|
+
rs = @ds.all
|
|
1787
|
+
rs.first[:i].should == @ipv4
|
|
1788
|
+
rs.first[:c].should == @ipv4nm
|
|
1789
|
+
rs.first[:i].should be_a_kind_of(IPAddr)
|
|
1790
|
+
rs.first[:c].should be_a_kind_of(IPAddr)
|
|
1791
|
+
@ds.delete
|
|
1792
|
+
@ds.insert(rs.first)
|
|
1793
|
+
@ds.all.should == rs
|
|
1794
|
+
end
|
|
1795
|
+
|
|
1796
|
+
unless ipv6_broken
|
|
1797
|
+
@ds.delete
|
|
1798
|
+
@ds.insert(@ipv6, @ipv6nm)
|
|
1799
|
+
@ds.count.should == 1
|
|
1800
|
+
if @native
|
|
1801
|
+
rs = @ds.all
|
|
1802
|
+
v = rs.first[:j]
|
|
1803
|
+
rs.first[:i].should == @ipv6
|
|
1804
|
+
rs.first[:c].should == @ipv6nm
|
|
1805
|
+
rs.first[:i].should be_a_kind_of(IPAddr)
|
|
1806
|
+
rs.first[:c].should be_a_kind_of(IPAddr)
|
|
1807
|
+
@ds.delete
|
|
1808
|
+
@ds.insert(rs.first)
|
|
1809
|
+
@ds.all.should == rs
|
|
1810
|
+
end
|
|
1811
|
+
end
|
|
1812
|
+
end
|
|
1813
|
+
|
|
1814
|
+
specify 'use ipaddr in bound variables' do
|
|
1815
|
+
@db.create_table!(:items){inet :i; cidr :c}
|
|
1816
|
+
|
|
1817
|
+
@ds.call(:insert, {:i=>@ipv4, :c=>@ipv4nm}, {:i=>:$i, :c=>:$c})
|
|
1818
|
+
@ds.get(:i).should == @ipv4
|
|
1819
|
+
@ds.get(:c).should == @ipv4nm
|
|
1820
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv4, :c=>@ipv4nm).should == {:i=>@ipv4, :c=>@ipv4nm}
|
|
1821
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv6, :c=>@ipv6nm).should == nil
|
|
1822
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:delete, :i=>@ipv4, :c=>@ipv4nm).should == 1
|
|
1823
|
+
|
|
1824
|
+
unless ipv6_broken
|
|
1825
|
+
@ds.call(:insert, {:i=>@ipv6, :c=>@ipv6nm}, {:i=>:$i, :c=>:$c})
|
|
1826
|
+
@ds.get(:i).should == @ipv6
|
|
1827
|
+
@ds.get(:c).should == @ipv6nm
|
|
1828
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv6, :c=>@ipv6nm).should == {:i=>@ipv6, :c=>@ipv6nm}
|
|
1829
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv4, :c=>@ipv4nm).should == nil
|
|
1830
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:delete, :i=>@ipv6, :c=>@ipv6nm).should == 1
|
|
1831
|
+
end
|
|
1832
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1833
|
+
|
|
1834
|
+
specify 'with models' do
|
|
1835
|
+
@db.create_table!(:items) do
|
|
1836
|
+
primary_key :id
|
|
1837
|
+
inet :i
|
|
1838
|
+
cidr :c
|
|
1839
|
+
end
|
|
1840
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
1841
|
+
c.plugin :typecast_on_load, :i, :c unless @native
|
|
1842
|
+
c.create(:i=>@v4, :c=>@v4nm).values.values_at(:i, :c).should == [@ipv4, @ipv4nm]
|
|
1843
|
+
unless ipv6_broken
|
|
1844
|
+
c.create(:i=>@ipv6, :c=>@ipv6nm).values.values_at(:i, :c).should == [@ipv6, @ipv6nm]
|
|
1845
|
+
end
|
|
1846
|
+
end
|
|
1847
|
+
end if POSTGRES_DB.server_version >= 90200
|