sequel 3.21.0 → 3.41.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 +1131 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +106 -65
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +68 -52
- data/doc/advanced_associations.rdoc +201 -75
- data/doc/association_basics.rdoc +327 -79
- data/doc/bin_sequel.rdoc +144 -0
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +10 -10
- data/doc/dataset_filtering.rdoc +54 -42
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +89 -557
- data/doc/model_hooks.rdoc +80 -29
- data/doc/object_model.rdoc +576 -0
- data/doc/opening_databases.rdoc +121 -53
- data/doc/prepared_statements.rdoc +41 -15
- data/doc/querying.rdoc +137 -56
- data/doc/reflection.rdoc +36 -10
- 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/release_notes/3.37.0.txt +338 -0
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/release_notes/3.40.0.txt +73 -0
- data/doc/release_notes/3.41.0.txt +155 -0
- data/doc/schema_modification.rdoc +585 -0
- data/doc/sharding.rdoc +99 -8
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +169 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +78 -43
- data/lib/sequel/adapters/ado/access.rb +334 -0
- data/lib/sequel/adapters/ado/mssql.rb +18 -12
- data/lib/sequel/adapters/ado.rb +69 -21
- data/lib/sequel/adapters/amalgalite.rb +17 -14
- data/lib/sequel/adapters/cubrid.rb +143 -0
- data/lib/sequel/adapters/db2.rb +178 -85
- data/lib/sequel/adapters/dbi.rb +19 -21
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +2 -61
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +20 -39
- data/lib/sequel/adapters/firebird.rb +33 -210
- data/lib/sequel/adapters/ibmdb.rb +452 -0
- data/lib/sequel/adapters/informix.rb +6 -29
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
- data/lib/sequel/adapters/jdbc/db2.rb +78 -0
- data/lib/sequel/adapters/jdbc/derby.rb +325 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +68 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
- 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 +72 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +308 -114
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +130 -230
- data/lib/sequel/adapters/mysql2.rb +64 -63
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +29 -10
- data/lib/sequel/adapters/openbase.rb +7 -11
- data/lib/sequel/adapters/oracle.rb +364 -57
- data/lib/sequel/adapters/postgres.rb +379 -145
- data/lib/sequel/adapters/shared/access.rb +236 -11
- data/lib/sequel/adapters/shared/cubrid.rb +216 -0
- data/lib/sequel/adapters/shared/db2.rb +353 -0
- data/lib/sequel/adapters/shared/firebird.rb +231 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +412 -116
- data/lib/sequel/adapters/shared/mysql.rb +396 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
- data/lib/sequel/adapters/shared/oracle.rb +262 -45
- data/lib/sequel/adapters/shared/postgres.rb +688 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +317 -96
- data/lib/sequel/adapters/sqlite.rb +109 -46
- data/lib/sequel/adapters/swift/mysql.rb +10 -12
- data/lib/sequel/adapters/swift/postgres.rb +13 -79
- data/lib/sequel/adapters/swift/sqlite.rb +9 -6
- data/lib/sequel/adapters/swift.rb +31 -27
- data/lib/sequel/adapters/tinytds.rb +177 -25
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
- data/lib/sequel/adapters/utils/pg_types.rb +81 -0
- data/lib/sequel/adapters/utils/split_alter_table.rb +36 -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 +23 -13
- data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
- data/lib/sequel/connection_pool/single.rb +11 -3
- data/lib/sequel/connection_pool/threaded.rb +69 -20
- data/lib/sequel/connection_pool.rb +20 -18
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +66 -29
- 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 +192 -51
- data/lib/sequel/database/query.rb +299 -114
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +310 -69
- data/lib/sequel/dataset/actions.rb +344 -90
- data/lib/sequel/dataset/features.rb +101 -8
- data/lib/sequel/dataset/graph.rb +42 -15
- data/lib/sequel/dataset/misc.rb +52 -25
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +322 -68
- data/lib/sequel/dataset/sql.rb +716 -293
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +83 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +72 -0
- data/lib/sequel/extensions/connection_validator.rb +109 -0
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
- data/lib/sequel/extensions/eval_inspect.rb +173 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +100 -11
- data/lib/sequel/extensions/named_timezones.rb +9 -0
- data/lib/sequel/extensions/null_dataset.rb +94 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +539 -0
- data/lib/sequel/extensions/pg_array_ops.rb +263 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
- data/lib/sequel/extensions/pg_hstore.rb +334 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
- data/lib/sequel/extensions/pg_inet.rb +113 -0
- data/lib/sequel/extensions/pg_interval.rb +191 -0
- data/lib/sequel/extensions/pg_json.rb +212 -0
- data/lib/sequel/extensions/pg_range.rb +513 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +576 -0
- data/lib/sequel/extensions/pg_row_ops.rb +182 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
- data/lib/sequel/extensions/pretty_table.rb +17 -72
- data/lib/sequel/extensions/query.rb +8 -4
- 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 +282 -76
- data/lib/sequel/extensions/select_remove.rb +39 -0
- data/lib/sequel/extensions/server_block.rb +140 -0
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +8 -110
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
- data/lib/sequel/extensions/to_dot.rb +99 -83
- data/lib/sequel/model/associations.rb +1263 -409
- data/lib/sequel/model/base.rb +624 -171
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +24 -2
- 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 +137 -16
- 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/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +72 -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 +134 -15
- 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 +77 -6
- data/lib/sequel/plugins/list.rb +13 -2
- data/lib/sequel/plugins/many_through_many.rb +103 -51
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +150 -66
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/prepared_statements.rb +168 -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 +31 -17
- data/lib/sequel/plugins/schema.rb +8 -3
- 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 +57 -12
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +29 -3
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/touch.rb +18 -6
- data/lib/sequel/plugins/tree.rb +3 -3
- 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 +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +57 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +721 -141
- data/lib/sequel/timezones.rb +67 -40
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +53 -39
- data/spec/adapters/mssql_spec.rb +261 -66
- data/spec/adapters/mysql_spec.rb +597 -352
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +2103 -341
- data/spec/adapters/spec_helper.rb +16 -6
- data/spec/adapters/sqlite_spec.rb +237 -76
- data/spec/core/connection_pool_spec.rb +270 -141
- data/spec/core/database_spec.rb +980 -524
- data/spec/core/dataset_spec.rb +1658 -1243
- data/spec/core/expression_filters_spec.rb +741 -334
- data/spec/core/mock_adapter_spec.rb +453 -0
- data/spec/core/object_graph_spec.rb +88 -129
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +556 -53
- data/spec/core/spec_helper.rb +7 -48
- data/spec/core_extensions_spec.rb +626 -0
- 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 +227 -33
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- 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/extensions/connection_validator_spec.rb +118 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +88 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/eval_inspect_spec.rb +67 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +97 -128
- data/spec/extensions/identity_map_spec.rb +142 -24
- 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 -12
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +49 -40
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +368 -254
- 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 +268 -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 +112 -0
- data/spec/extensions/pg_array_spec.rb +324 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
- data/spec/extensions/pg_hstore_spec.rb +200 -0
- data/spec/extensions/pg_inet_spec.rb +47 -0
- data/spec/extensions/pg_interval_spec.rb +72 -0
- data/spec/extensions/pg_json_spec.rb +99 -0
- data/spec/extensions/pg_range_ops_spec.rb +56 -0
- data/spec/extensions/pg_range_spec.rb +395 -0
- data/spec/extensions/pg_row_ops_spec.rb +58 -0
- data/spec/extensions/pg_row_plugin_spec.rb +49 -0
- data/spec/extensions/pg_row_spec.rb +340 -0
- data/spec/extensions/pg_statement_cache_spec.rb +208 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -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 +167 -0
- data/spec/extensions/query_spec.rb +9 -3
- 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 +434 -49
- data/spec/extensions/schema_spec.rb +30 -49
- 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 +86 -48
- 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 +65 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +34 -67
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/subclasses_spec.rb +14 -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 +8 -11
- data/spec/extensions/touch_spec.rb +53 -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 +77 -68
- data/spec/extensions/validation_helpers_spec.rb +48 -37
- 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 +25 -5
- data/spec/integration/dataset_test.rb +729 -141
- data/spec/integration/eager_loader_test.rb +38 -54
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +871 -160
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +377 -57
- data/spec/integration/spec_helper.rb +49 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +40 -8
- data/spec/model/association_reflection_spec.rb +207 -8
- data/spec/model/associations_spec.rb +1206 -693
- data/spec/model/base_spec.rb +334 -100
- data/spec/model/dataset_methods_spec.rb +45 -27
- data/spec/model/eager_loading_spec.rb +828 -692
- data/spec/model/hooks_spec.rb +355 -67
- data/spec/model/model_spec.rb +251 -179
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +506 -232
- data/spec/model/spec_helper.rb +16 -77
- data/spec/model/validations_spec.rb +38 -2
- data/spec/rcov.opts +2 -0
- metadata +223 -81
- data/spec/core/core_sql_spec.rb +0 -451
|
@@ -13,147 +13,296 @@ logger = Object.new
|
|
|
13
13
|
def logger.method_missing(m, msg)
|
|
14
14
|
POSTGRES_DB.sqls << msg
|
|
15
15
|
end
|
|
16
|
-
POSTGRES_DB.loggers
|
|
16
|
+
POSTGRES_DB.loggers << logger
|
|
17
17
|
|
|
18
|
-
#POSTGRES_DB.instance_variable_set(:@server_version,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
POSTGRES_DB.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
#POSTGRES_DB.instance_variable_set(:@server_version, 80200)
|
|
19
|
+
|
|
20
|
+
describe "PostgreSQL", '#create_table' do
|
|
21
|
+
before do
|
|
22
|
+
@db = POSTGRES_DB
|
|
23
|
+
POSTGRES_DB.sqls.clear
|
|
24
|
+
end
|
|
25
|
+
after do
|
|
26
|
+
@db.drop_table?(:tmp_dolls)
|
|
27
|
+
@db.drop_table?(:unlogged_dolls)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
specify "should create a temporary table" do
|
|
31
|
+
@db.create_table(:tmp_dolls, :temp => true){text :name}
|
|
32
|
+
check_sqls do
|
|
33
|
+
@db.sqls.should == ['CREATE TEMPORARY TABLE "tmp_dolls" ("name" text)']
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
specify "should create an unlogged table" do
|
|
38
|
+
@db.create_table(:unlogged_dolls, :unlogged => true){text :name}
|
|
39
|
+
check_sqls do
|
|
40
|
+
@db.sqls.should == ['CREATE UNLOGGED TABLE "unlogged_dolls" ("name" text)']
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
specify "should not allow to pass both :temp and :unlogged" do
|
|
45
|
+
proc do
|
|
46
|
+
@db.create_table(:temp_unlogged_dolls, :temp => true, :unlogged => true){text :name}
|
|
47
|
+
end.should raise_error(Sequel::Error, "can't provide both :temp and :unlogged to create_table")
|
|
48
|
+
end
|
|
34
49
|
end
|
|
35
50
|
|
|
36
51
|
describe "A PostgreSQL database" do
|
|
37
|
-
before do
|
|
52
|
+
before(:all) do
|
|
38
53
|
@db = POSTGRES_DB
|
|
54
|
+
@db.create_table!(:public__testfk){primary_key :id; foreign_key :i, :public__testfk}
|
|
55
|
+
end
|
|
56
|
+
after(:all) do
|
|
57
|
+
@db.drop_table?(:public__testfk)
|
|
39
58
|
end
|
|
40
|
-
|
|
59
|
+
|
|
41
60
|
specify "should provide the server version" do
|
|
42
61
|
@db.server_version.should > 70000
|
|
43
62
|
end
|
|
44
63
|
|
|
45
64
|
specify "should correctly parse the schema" do
|
|
46
|
-
@db.schema(:
|
|
47
|
-
[:
|
|
48
|
-
[:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
@db.schema(:public__testfk, :reload=>true).should == [
|
|
66
|
+
[:id, {:type=>:integer, :ruby_default=>nil, :db_type=>"integer", :default=>"nextval('testfk_id_seq'::regclass)", :oid=>23, :primary_key=>true, :allow_null=>false}],
|
|
67
|
+
[:i, {:type=>:integer, :ruby_default=>nil, :db_type=>"integer", :default=>nil, :oid=>23, :primary_key=>false, :allow_null=>true}]]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
specify "should parse foreign keys for tables in a schema" do
|
|
71
|
+
@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}]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
specify "should return uuid fields as strings" do
|
|
75
|
+
@db.get(Sequel.cast('550e8400-e29b-41d4-a716-446655440000', :uuid)).should == '550e8400-e29b-41d4-a716-446655440000'
|
|
54
76
|
end
|
|
55
77
|
end
|
|
56
78
|
|
|
57
79
|
describe "A PostgreSQL dataset" do
|
|
80
|
+
before(:all) do
|
|
81
|
+
@db = POSTGRES_DB
|
|
82
|
+
@d = @db[:test]
|
|
83
|
+
@db.create_table! :test do
|
|
84
|
+
text :name
|
|
85
|
+
integer :value, :index => true
|
|
86
|
+
end
|
|
87
|
+
end
|
|
58
88
|
before do
|
|
59
|
-
@d
|
|
60
|
-
@
|
|
89
|
+
@d.delete
|
|
90
|
+
@db.sqls.clear
|
|
61
91
|
end
|
|
62
|
-
|
|
92
|
+
after do
|
|
93
|
+
@db.drop_table?(:atest)
|
|
94
|
+
end
|
|
95
|
+
after(:all) do
|
|
96
|
+
@db.drop_table?(:test)
|
|
97
|
+
end
|
|
98
|
+
|
|
63
99
|
specify "should quote columns and tables using double quotes if quoting identifiers" do
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
'SELECT
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
'SELECT
|
|
100
|
+
check_sqls do
|
|
101
|
+
@d.select(:name).sql.should == 'SELECT "name" FROM "test"'
|
|
102
|
+
@d.select(Sequel.lit('COUNT(*)')).sql.should == 'SELECT COUNT(*) FROM "test"'
|
|
103
|
+
@d.select(Sequel.function(:max, :value)).sql.should == 'SELECT max("value") FROM "test"'
|
|
104
|
+
@d.select(Sequel.function(:NOW)).sql.should == 'SELECT NOW() FROM "test"'
|
|
105
|
+
@d.select(Sequel.function(:max, :items__value)).sql.should == 'SELECT max("items"."value") FROM "test"'
|
|
106
|
+
@d.order(Sequel.desc(:name)).sql.should == 'SELECT * FROM "test" ORDER BY "name" DESC'
|
|
107
|
+
@d.select(Sequel.lit('test.name AS item_name')).sql.should == 'SELECT test.name AS item_name FROM "test"'
|
|
108
|
+
@d.select(Sequel.lit('"name"')).sql.should == 'SELECT "name" FROM "test"'
|
|
109
|
+
@d.select(Sequel.lit('max(test."name") AS "max_name"')).sql.should == 'SELECT max(test."name") AS "max_name" FROM "test"'
|
|
110
|
+
@d.insert_sql(:x => :y).should =~ /\AINSERT INTO "test" \("x"\) VALUES \("y"\)( RETURNING NULL)?\z/
|
|
111
|
+
|
|
112
|
+
@d.select(Sequel.function(:test, :abc, 'hello')).sql.should == "SELECT test(\"abc\", 'hello') FROM \"test\""
|
|
113
|
+
@d.select(Sequel.function(:test, :abc__def, 'hello')).sql.should == "SELECT test(\"abc\".\"def\", 'hello') FROM \"test\""
|
|
114
|
+
@d.select(Sequel.function(:test, :abc__def, 'hello').as(:x2)).sql.should == "SELECT test(\"abc\".\"def\", 'hello') AS \"x2\" FROM \"test\""
|
|
115
|
+
@d.insert_sql(:value => 333).should =~ /\AINSERT INTO "test" \("value"\) VALUES \(333\)( RETURNING NULL)?\z/
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
specify "should quote fields correctly when reversing the order if quoting identifiers" do
|
|
120
|
+
check_sqls do
|
|
121
|
+
@d.reverse_order(:name).sql.should == 'SELECT * FROM "test" ORDER BY "name" DESC'
|
|
122
|
+
@d.reverse_order(Sequel.desc(:name)).sql.should == 'SELECT * FROM "test" ORDER BY "name" ASC'
|
|
123
|
+
@d.reverse_order(:name, Sequel.desc(:test)).sql.should == 'SELECT * FROM "test" ORDER BY "name" DESC, "test" ASC'
|
|
124
|
+
@d.reverse_order(Sequel.desc(:name), :test).sql.should == 'SELECT * FROM "test" ORDER BY "name" ASC, "test" DESC'
|
|
125
|
+
end
|
|
126
|
+
end
|
|
70
127
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@d.
|
|
75
|
-
|
|
128
|
+
specify "should support regexps" do
|
|
129
|
+
@d << {:name => 'abc', :value => 1}
|
|
130
|
+
@d << {:name => 'bcd', :value => 2}
|
|
131
|
+
@d.filter(:name => /bc/).count.should == 2
|
|
132
|
+
@d.filter(:name => /^bc/).count.should == 1
|
|
133
|
+
end
|
|
76
134
|
|
|
77
|
-
|
|
78
|
-
|
|
135
|
+
specify "should support NULLS FIRST and NULLS LAST" do
|
|
136
|
+
@d << {:name => 'abc'}
|
|
137
|
+
@d << {:name => 'bcd'}
|
|
138
|
+
@d << {:name => 'bcd', :value => 2}
|
|
139
|
+
@d.order(Sequel.asc(:value, :nulls=>:first), :name).select_map(:name).should == %w[abc bcd bcd]
|
|
140
|
+
@d.order(Sequel.asc(:value, :nulls=>:last), :name).select_map(:name).should == %w[bcd abc bcd]
|
|
141
|
+
@d.order(Sequel.asc(:value, :nulls=>:first), :name).reverse.select_map(:name).should == %w[bcd bcd abc]
|
|
142
|
+
end
|
|
79
143
|
|
|
80
|
-
|
|
81
|
-
|
|
144
|
+
specify "#lock should lock tables and yield if a block is given" do
|
|
145
|
+
@d.lock('EXCLUSIVE'){@d.insert(:name=>'a')}
|
|
146
|
+
end
|
|
82
147
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@
|
|
87
|
-
|
|
148
|
+
specify "should support exclusion constraints when creating or altering tables" do
|
|
149
|
+
@db.create_table!(:atest){Integer :t; exclude [[Sequel.desc(:t, :nulls=>:last), '=']], :using=>:btree, :where=>proc{t > 0}}
|
|
150
|
+
@db[:atest].insert(1)
|
|
151
|
+
@db[:atest].insert(2)
|
|
152
|
+
proc{@db[:atest].insert(2)}.should raise_error(Sequel::DatabaseError)
|
|
88
153
|
|
|
89
|
-
@
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
@
|
|
93
|
-
|
|
154
|
+
@db.create_table!(:atest){Integer :t}
|
|
155
|
+
@db.alter_table(:atest){add_exclusion_constraint [[:t, '=']], :using=>:btree, :name=>'atest_ex'}
|
|
156
|
+
@db[:atest].insert(1)
|
|
157
|
+
@db[:atest].insert(2)
|
|
158
|
+
proc{@db[:atest].insert(2)}.should raise_error(Sequel::DatabaseError)
|
|
159
|
+
@db.alter_table(:atest){drop_constraint 'atest_ex'}
|
|
160
|
+
end if POSTGRES_DB.server_version >= 90000
|
|
94
161
|
|
|
95
|
-
|
|
96
|
-
|
|
162
|
+
specify "should support adding foreign key constarints that are not yet valid, and validating them later" do
|
|
163
|
+
@db.create_table!(:atest){primary_key :id; Integer :fk}
|
|
164
|
+
@db[:atest].insert(1, 5)
|
|
165
|
+
@db.alter_table(:atest){add_foreign_key [:fk], :atest, :not_valid=>true, :name=>:atest_fk}
|
|
166
|
+
@db[:atest].insert(2, 1)
|
|
167
|
+
proc{@db[:atest].insert(3, 4)}.should raise_error(Sequel::DatabaseError)
|
|
97
168
|
|
|
98
|
-
@
|
|
99
|
-
|
|
169
|
+
proc{@db.alter_table(:atest){validate_constraint :atest_fk}}.should raise_error(Sequel::DatabaseError)
|
|
170
|
+
@db[:atest].where(:id=>1).update(:fk=>2)
|
|
171
|
+
@db.alter_table(:atest){validate_constraint :atest_fk}
|
|
172
|
+
proc{@db.alter_table(:atest){validate_constraint :atest_fk}}.should_not raise_error
|
|
173
|
+
end if POSTGRES_DB.server_version >= 90200
|
|
100
174
|
|
|
101
|
-
|
|
102
|
-
|
|
175
|
+
specify "should support :using when altering a column's type" do
|
|
176
|
+
@db.create_table!(:atest){Integer :t}
|
|
177
|
+
@db[:atest].insert(1262304000)
|
|
178
|
+
@db.alter_table(:atest){set_column_type :t, Time, :using=>Sequel.cast('epoch', Time) + Sequel.cast('1 second', :interval) * :t}
|
|
179
|
+
@db[:atest].get(Sequel.extract(:year, :t)).should == 2010
|
|
180
|
+
end
|
|
103
181
|
|
|
104
|
-
|
|
105
|
-
|
|
182
|
+
specify "should support :using with a string when altering a column's type" do
|
|
183
|
+
@db.create_table!(:atest){Integer :t}
|
|
184
|
+
@db[:atest].insert(1262304000)
|
|
185
|
+
@db.alter_table(:atest){set_column_type :t, Time, :using=>"'epoch'::timestamp + '1 second'::interval * t"}
|
|
186
|
+
@db[:atest].get(Sequel.extract(:year, :t)).should == 2010
|
|
187
|
+
end
|
|
106
188
|
|
|
107
|
-
|
|
108
|
-
|
|
189
|
+
specify "should be able to parse the default value for an interval type" do
|
|
190
|
+
@db.create_table!(:atest){interval :t, :default=>'1 week'}
|
|
191
|
+
@db.schema(:atest).first.last[:ruby_default].should == '7 days'
|
|
109
192
|
end
|
|
110
|
-
|
|
111
|
-
specify "should quote fields correctly when reversing the order if quoting identifiers" do
|
|
112
|
-
@d.quote_identifiers = true
|
|
113
|
-
@d.reverse_order(:name).sql.should == \
|
|
114
|
-
'SELECT * FROM "test" ORDER BY "name" DESC'
|
|
115
193
|
|
|
116
|
-
|
|
117
|
-
|
|
194
|
+
specify "should have #transaction support various types of synchronous options" do
|
|
195
|
+
@db.transaction(:synchronous=>:on){}
|
|
196
|
+
@db.transaction(:synchronous=>true){}
|
|
197
|
+
@db.transaction(:synchronous=>:off){}
|
|
198
|
+
@db.transaction(:synchronous=>false){}
|
|
199
|
+
@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"]
|
|
118
200
|
|
|
119
|
-
@
|
|
120
|
-
|
|
201
|
+
@db.sqls.clear
|
|
202
|
+
@db.transaction(:synchronous=>nil){}
|
|
203
|
+
check_sqls do
|
|
204
|
+
@db.sqls.should == ['BEGIN', 'COMMIT']
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
if @db.server_version >= 90100
|
|
208
|
+
@db.sqls.clear
|
|
209
|
+
@db.transaction(:synchronous=>:local){}
|
|
210
|
+
check_sqls do
|
|
211
|
+
@db.sqls.grep(/synchronous/).should == ["SET LOCAL synchronous_commit = local"]
|
|
212
|
+
end
|
|
121
213
|
|
|
122
|
-
|
|
123
|
-
|
|
214
|
+
if @db.server_version >= 90200
|
|
215
|
+
@db.sqls.clear
|
|
216
|
+
@db.transaction(:synchronous=>:remote_write){}
|
|
217
|
+
check_sqls do
|
|
218
|
+
@db.sqls.grep(/synchronous/).should == ["SET LOCAL synchronous_commit = remote_write"]
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
124
222
|
end
|
|
125
223
|
|
|
126
|
-
specify "should support
|
|
127
|
-
@
|
|
128
|
-
@
|
|
129
|
-
@
|
|
130
|
-
@
|
|
224
|
+
specify "should have #transaction support read only transactions" do
|
|
225
|
+
@db.transaction(:read_only=>true){}
|
|
226
|
+
@db.transaction(:read_only=>false){}
|
|
227
|
+
@db.transaction(:isolation=>:serializable, :read_only=>true){}
|
|
228
|
+
@db.transaction(:isolation=>:serializable, :read_only=>false){}
|
|
229
|
+
@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"]
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
specify "should have #transaction support deferrable transactions" do
|
|
233
|
+
@db.transaction(:deferrable=>true){}
|
|
234
|
+
@db.transaction(:deferrable=>false){}
|
|
235
|
+
@db.transaction(:deferrable=>true, :read_only=>true){}
|
|
236
|
+
@db.transaction(:deferrable=>false, :read_only=>false){}
|
|
237
|
+
@db.transaction(:isolation=>:serializable, :deferrable=>true, :read_only=>true){}
|
|
238
|
+
@db.transaction(:isolation=>:serializable, :deferrable=>false, :read_only=>false){}
|
|
239
|
+
@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"]
|
|
240
|
+
end if POSTGRES_DB.server_version >= 90100
|
|
241
|
+
|
|
242
|
+
specify "should support creating indexes concurrently" do
|
|
243
|
+
@db.add_index :test, [:name, :value], :concurrently=>true
|
|
244
|
+
check_sqls do
|
|
245
|
+
@db.sqls.should == ['CREATE INDEX CONCURRENTLY "test_name_value_index" ON "test" ("name", "value")']
|
|
246
|
+
end
|
|
131
247
|
end
|
|
132
|
-
|
|
133
|
-
specify "should support
|
|
134
|
-
@
|
|
135
|
-
@
|
|
136
|
-
@
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
248
|
+
|
|
249
|
+
specify "should support dropping indexes only if they already exist" do
|
|
250
|
+
@db.add_index :test, [:name, :value], :name=>'tnv1'
|
|
251
|
+
@db.sqls.clear
|
|
252
|
+
@db.drop_index :test, [:name, :value], :if_exists=>true, :name=>'tnv1'
|
|
253
|
+
check_sqls do
|
|
254
|
+
@db.sqls.should == ['DROP INDEX IF EXISTS "tnv1"']
|
|
255
|
+
end
|
|
140
256
|
end
|
|
141
|
-
|
|
142
|
-
specify "
|
|
143
|
-
@
|
|
257
|
+
|
|
258
|
+
specify "should support CASCADE when dropping indexes" do
|
|
259
|
+
@db.add_index :test, [:name, :value], :name=>'tnv2'
|
|
260
|
+
@db.sqls.clear
|
|
261
|
+
@db.drop_index :test, [:name, :value], :cascade=>true, :name=>'tnv2'
|
|
262
|
+
check_sqls do
|
|
263
|
+
@db.sqls.should == ['DROP INDEX "tnv2" CASCADE']
|
|
264
|
+
end
|
|
144
265
|
end
|
|
145
|
-
|
|
266
|
+
|
|
267
|
+
specify "should support dropping indexes concurrently" do
|
|
268
|
+
@db.add_index :test, [:name, :value], :name=>'tnv2'
|
|
269
|
+
@db.sqls.clear
|
|
270
|
+
@db.drop_index :test, [:name, :value], :concurrently=>true, :name=>'tnv2'
|
|
271
|
+
check_sqls do
|
|
272
|
+
@db.sqls.should == ['DROP INDEX CONCURRENTLY "tnv2"']
|
|
273
|
+
end
|
|
274
|
+
end if POSTGRES_DB.server_version >= 90200
|
|
275
|
+
|
|
146
276
|
specify "#lock should lock table if inside a transaction" do
|
|
147
|
-
|
|
277
|
+
@db.transaction{@d.lock('EXCLUSIVE'); @d.insert(:name=>'a')}
|
|
148
278
|
end
|
|
149
|
-
|
|
279
|
+
|
|
150
280
|
specify "#lock should return nil" do
|
|
151
281
|
@d.lock('EXCLUSIVE'){@d.insert(:name=>'a')}.should == nil
|
|
152
|
-
|
|
282
|
+
@db.transaction{@d.lock('EXCLUSIVE').should == nil; @d.insert(:name=>'a')}
|
|
153
283
|
end
|
|
154
|
-
|
|
284
|
+
|
|
155
285
|
specify "should raise an error if attempting to update a joined dataset with a single FROM table" do
|
|
156
|
-
proc{
|
|
286
|
+
proc{@db[:test].join(:test, [:name]).update(:name=>'a')}.should raise_error(Sequel::Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs')
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
specify "should truncate with options" do
|
|
290
|
+
@d << { :name => 'abc', :value => 1}
|
|
291
|
+
@d.count.should == 1
|
|
292
|
+
@d.truncate(:cascade => true)
|
|
293
|
+
@d.count.should == 0
|
|
294
|
+
if @d.db.server_version > 80400
|
|
295
|
+
@d << { :name => 'abc', :value => 1}
|
|
296
|
+
@d.truncate(:cascade => true, :only=>true, :restart=>true)
|
|
297
|
+
@d.count.should == 0
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
specify "should truncate multiple tables at once" do
|
|
302
|
+
tables = [:test, :test]
|
|
303
|
+
tables.each{|t| @d.from(t).insert}
|
|
304
|
+
@d.from(:test, :test).truncate
|
|
305
|
+
tables.each{|t| @d.from(t).count.should == 0}
|
|
157
306
|
end
|
|
158
307
|
end
|
|
159
308
|
|
|
@@ -167,16 +316,16 @@ describe "Dataset#distinct" do
|
|
|
167
316
|
@ds = @db[:a]
|
|
168
317
|
end
|
|
169
318
|
after do
|
|
170
|
-
@db.drop_table(:a)
|
|
319
|
+
@db.drop_table?(:a)
|
|
171
320
|
end
|
|
172
|
-
|
|
321
|
+
|
|
173
322
|
it "#distinct with arguments should return results distinct on those arguments" do
|
|
174
323
|
@ds.insert(20, 10)
|
|
175
324
|
@ds.insert(30, 10)
|
|
176
325
|
@ds.order(:b, :a).distinct.map(:a).should == [20, 30]
|
|
177
|
-
@ds.order(:b, :a
|
|
326
|
+
@ds.order(:b, Sequel.desc(:a)).distinct.map(:a).should == [30, 20]
|
|
178
327
|
@ds.order(:b, :a).distinct(:b).map(:a).should == [20]
|
|
179
|
-
@ds.order(:b, :a
|
|
328
|
+
@ds.order(:b, Sequel.desc(:a)).distinct(:b).map(:a).should == [30]
|
|
180
329
|
end
|
|
181
330
|
end
|
|
182
331
|
|
|
@@ -191,41 +340,45 @@ if POSTGRES_DB.pool.respond_to?(:max_size) and POSTGRES_DB.pool.max_size > 1
|
|
|
191
340
|
@ds = POSTGRES_DB[:items]
|
|
192
341
|
end
|
|
193
342
|
after do
|
|
194
|
-
POSTGRES_DB.drop_table(:items)
|
|
343
|
+
POSTGRES_DB.drop_table?(:items)
|
|
195
344
|
POSTGRES_DB.disconnect
|
|
196
345
|
end
|
|
197
|
-
|
|
346
|
+
|
|
198
347
|
specify "should handle FOR UPDATE" do
|
|
199
348
|
@ds.insert(:number=>20)
|
|
200
|
-
c = nil
|
|
201
|
-
|
|
349
|
+
c, t = nil, nil
|
|
350
|
+
q = Queue.new
|
|
202
351
|
POSTGRES_DB.transaction do
|
|
203
352
|
@ds.for_update.first(:id=>1)
|
|
204
353
|
t = Thread.new do
|
|
205
354
|
POSTGRES_DB.transaction do
|
|
355
|
+
q.push nil
|
|
206
356
|
@ds.filter(:id=>1).update(:name=>'Jim')
|
|
207
357
|
c = @ds.first(:id=>1)
|
|
358
|
+
q.push nil
|
|
208
359
|
end
|
|
209
360
|
end
|
|
210
|
-
|
|
361
|
+
q.pop
|
|
211
362
|
@ds.filter(:id=>1).update(:number=>30)
|
|
212
363
|
end
|
|
364
|
+
q.pop
|
|
213
365
|
t.join
|
|
214
366
|
c.should == {:id=>1, :number=>30, :name=>'Jim'}
|
|
215
367
|
end
|
|
216
|
-
|
|
368
|
+
|
|
217
369
|
specify "should handle FOR SHARE" do
|
|
218
370
|
@ds.insert(:number=>20)
|
|
219
|
-
c = nil
|
|
220
|
-
|
|
371
|
+
c, t = nil
|
|
372
|
+
q = Queue.new
|
|
221
373
|
POSTGRES_DB.transaction do
|
|
222
374
|
@ds.for_share.first(:id=>1)
|
|
223
375
|
t = Thread.new do
|
|
224
376
|
POSTGRES_DB.transaction do
|
|
225
377
|
c = @ds.for_share.filter(:id=>1).first
|
|
378
|
+
q.push nil
|
|
226
379
|
end
|
|
227
380
|
end
|
|
228
|
-
|
|
381
|
+
q.pop
|
|
229
382
|
@ds.filter(:id=>1).update(:name=>'Jim')
|
|
230
383
|
c.should == {:id=>1, :number=>20, :name=>nil}
|
|
231
384
|
end
|
|
@@ -235,41 +388,93 @@ if POSTGRES_DB.pool.respond_to?(:max_size) and POSTGRES_DB.pool.max_size > 1
|
|
|
235
388
|
end
|
|
236
389
|
|
|
237
390
|
describe "A PostgreSQL dataset with a timestamp field" do
|
|
391
|
+
before(:all) do
|
|
392
|
+
@db = POSTGRES_DB
|
|
393
|
+
@db.create_table! :test3 do
|
|
394
|
+
integer :value
|
|
395
|
+
timestamp :time
|
|
396
|
+
end
|
|
397
|
+
@d = @db[:test3]
|
|
398
|
+
end
|
|
238
399
|
before do
|
|
239
|
-
@d = POSTGRES_DB[:test3]
|
|
240
400
|
@d.delete
|
|
241
401
|
end
|
|
402
|
+
after do
|
|
403
|
+
@db.convert_infinite_timestamps = false if @db.adapter_scheme == :postgres
|
|
404
|
+
end
|
|
405
|
+
after(:all) do
|
|
406
|
+
@db.drop_table?(:test3)
|
|
407
|
+
end
|
|
242
408
|
|
|
243
|
-
cspecify "should store milliseconds in time fields for Time objects", :do do
|
|
409
|
+
cspecify "should store milliseconds in time fields for Time objects", :do, :swift do
|
|
244
410
|
t = Time.now
|
|
245
411
|
@d << {:value=>1, :time=>t}
|
|
246
|
-
t2 = @d[:value =>
|
|
412
|
+
t2 = @d[:value =>1][:time]
|
|
247
413
|
@d.literal(t2).should == @d.literal(t)
|
|
248
414
|
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
|
|
415
|
+
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).should == t.usec
|
|
250
416
|
end
|
|
251
417
|
|
|
252
|
-
cspecify "should store milliseconds in time fields for DateTime objects", :do do
|
|
418
|
+
cspecify "should store milliseconds in time fields for DateTime objects", :do, :swift do
|
|
253
419
|
t = DateTime.now
|
|
254
420
|
@d << {:value=>1, :time=>t}
|
|
255
|
-
t2 = @d[:value =>
|
|
421
|
+
t2 = @d[:value =>1][:time]
|
|
256
422
|
@d.literal(t2).should == @d.literal(t)
|
|
257
423
|
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
|
|
424
|
+
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).should == t.strftime('%N').to_i/1000
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
if POSTGRES_DB.adapter_scheme == :postgres
|
|
428
|
+
specify "should handle infinite timestamps if convert_infinite_timestamps is set" do
|
|
429
|
+
@d << {:time=>Sequel.cast('infinity', :timestamp)}
|
|
430
|
+
@db.convert_infinite_timestamps = :nil
|
|
431
|
+
@db[:test3].get(:time).should == nil
|
|
432
|
+
@db.convert_infinite_timestamps = :string
|
|
433
|
+
@db[:test3].get(:time).should == 'infinity'
|
|
434
|
+
@db.convert_infinite_timestamps = :float
|
|
435
|
+
@db[:test3].get(:time).should == 1.0/0.0
|
|
436
|
+
|
|
437
|
+
@d.update(:time=>Sequel.cast('-infinity', :timestamp))
|
|
438
|
+
@db.convert_infinite_timestamps = :nil
|
|
439
|
+
@db[:test3].get(:time).should == nil
|
|
440
|
+
@db.convert_infinite_timestamps = :string
|
|
441
|
+
@db[:test3].get(:time).should == '-infinity'
|
|
442
|
+
@db.convert_infinite_timestamps = :float
|
|
443
|
+
@db[:test3].get(:time).should == -1.0/0.0
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
specify "should handle conversions from infinite strings/floats in models" do
|
|
447
|
+
c = Class.new(Sequel::Model(:test3))
|
|
448
|
+
@db.convert_infinite_timestamps = :float
|
|
449
|
+
c.new(:time=>'infinity').time.should == 'infinity'
|
|
450
|
+
c.new(:time=>'-infinity').time.should == '-infinity'
|
|
451
|
+
c.new(:time=>1.0/0.0).time.should == 1.0/0.0
|
|
452
|
+
c.new(:time=>-1.0/0.0).time.should == -1.0/0.0
|
|
453
|
+
end
|
|
259
454
|
end
|
|
260
|
-
end
|
|
261
455
|
|
|
262
|
-
|
|
263
|
-
specify "should not raise errors" do
|
|
456
|
+
specify "explain and analyze should not raise errors" do
|
|
264
457
|
@d = POSTGRES_DB[:test3]
|
|
265
458
|
proc{@d.explain}.should_not raise_error
|
|
266
459
|
proc{@d.analyze}.should_not raise_error
|
|
267
460
|
end
|
|
461
|
+
|
|
462
|
+
specify "#locks should be a dataset returning database locks " do
|
|
463
|
+
@db.locks.should be_a_kind_of(Sequel::Dataset)
|
|
464
|
+
@db.locks.all.should be_a_kind_of(Array)
|
|
465
|
+
end
|
|
268
466
|
end
|
|
269
467
|
|
|
270
468
|
describe "A PostgreSQL database" do
|
|
271
469
|
before do
|
|
272
470
|
@db = POSTGRES_DB
|
|
471
|
+
@db.create_table! :test2 do
|
|
472
|
+
text :name
|
|
473
|
+
integer :value
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
after do
|
|
477
|
+
@db.drop_table?(:test2)
|
|
273
478
|
end
|
|
274
479
|
|
|
275
480
|
specify "should support column operations" do
|
|
@@ -281,12 +486,12 @@ describe "A PostgreSQL database" do
|
|
|
281
486
|
@db[:test2].columns.should == [:name, :value, :xyz]
|
|
282
487
|
@db[:test2] << {:name => 'mmm', :value => 111}
|
|
283
488
|
@db[:test2].first[:xyz].should == '000'
|
|
284
|
-
|
|
489
|
+
|
|
285
490
|
@db[:test2].columns.should == [:name, :value, :xyz]
|
|
286
491
|
@db.drop_column :test2, :xyz
|
|
287
|
-
|
|
492
|
+
|
|
288
493
|
@db[:test2].columns.should == [:name, :value]
|
|
289
|
-
|
|
494
|
+
|
|
290
495
|
@db[:test2].delete
|
|
291
496
|
@db.add_column :test2, :xyz, :text, :default => '000'
|
|
292
497
|
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 'qqqq'}
|
|
@@ -295,31 +500,26 @@ describe "A PostgreSQL database" do
|
|
|
295
500
|
@db.rename_column :test2, :xyz, :zyx
|
|
296
501
|
@db[:test2].columns.should == [:name, :value, :zyx]
|
|
297
502
|
@db[:test2].first[:zyx].should == 'qqqq'
|
|
298
|
-
|
|
503
|
+
|
|
299
504
|
@db.add_column :test2, :xyz, :float
|
|
300
505
|
@db[:test2].delete
|
|
301
506
|
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
|
|
302
507
|
@db.set_column_type :test2, :xyz, :integer
|
|
303
|
-
|
|
508
|
+
|
|
304
509
|
@db[:test2].first[:xyz].should == 57
|
|
305
510
|
end
|
|
306
|
-
|
|
307
|
-
specify "#locks should be a dataset returning database locks " do
|
|
308
|
-
@db.locks.should be_a_kind_of(Sequel::Dataset)
|
|
309
|
-
@db.locks.all.should be_a_kind_of(Array)
|
|
310
|
-
end
|
|
311
|
-
end
|
|
511
|
+
end
|
|
312
512
|
|
|
313
513
|
describe "A PostgreSQL database" do
|
|
314
514
|
before do
|
|
315
515
|
@db = POSTGRES_DB
|
|
316
|
-
@db.drop_table(:posts)
|
|
516
|
+
@db.drop_table?(:posts)
|
|
317
517
|
@db.sqls.clear
|
|
318
518
|
end
|
|
319
519
|
after do
|
|
320
|
-
@db.drop_table(:posts)
|
|
520
|
+
@db.drop_table?(:posts)
|
|
321
521
|
end
|
|
322
|
-
|
|
522
|
+
|
|
323
523
|
specify "should support resetting the primary key sequence" do
|
|
324
524
|
@db.create_table(:posts){primary_key :a}
|
|
325
525
|
@db[:posts].insert(:a=>20).should == 20
|
|
@@ -330,7 +530,7 @@ describe "A PostgreSQL database" do
|
|
|
330
530
|
@db[:posts].insert.should == 21
|
|
331
531
|
@db[:posts].order(:a).map(:a).should == [1, 2, 10, 20, 21]
|
|
332
532
|
end
|
|
333
|
-
|
|
533
|
+
|
|
334
534
|
specify "should support specifying Integer/Bignum/Fixnum types in primary keys and have them be auto incrementing" do
|
|
335
535
|
@db.create_table(:posts){primary_key :a, :type=>Integer}
|
|
336
536
|
@db[:posts].insert.should == 1
|
|
@@ -347,22 +547,26 @@ describe "A PostgreSQL database" do
|
|
|
347
547
|
@db.create_table(:posts){Integer :a}
|
|
348
548
|
@db.reset_primary_key_sequence(:posts).should == nil
|
|
349
549
|
end
|
|
350
|
-
|
|
550
|
+
|
|
351
551
|
specify "should support opclass specification" do
|
|
352
552
|
@db.create_table(:posts){text :title; text :body; integer :user_id; index(:user_id, :opclass => :int4_ops, :type => :btree)}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
553
|
+
check_sqls do
|
|
554
|
+
@db.sqls.should == [
|
|
555
|
+
'CREATE TABLE "posts" ("title" text, "body" text, "user_id" integer)',
|
|
556
|
+
'CREATE INDEX "posts_user_id_index" ON "posts" USING btree ("user_id" int4_ops)'
|
|
557
|
+
]
|
|
558
|
+
end
|
|
357
559
|
end
|
|
358
560
|
|
|
359
561
|
specify "should support fulltext indexes and searching" do
|
|
360
562
|
@db.create_table(:posts){text :title; text :body; full_text_index [:title, :body]; full_text_index :title, :language => 'french'}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
563
|
+
check_sqls do
|
|
564
|
+
@db.sqls.should == [
|
|
565
|
+
%{CREATE TABLE "posts" ("title" text, "body" text)},
|
|
566
|
+
%{CREATE INDEX "posts_title_body_index" ON "posts" USING gin (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))))},
|
|
567
|
+
%{CREATE INDEX "posts_title_index" ON "posts" USING gin (to_tsvector('french'::regconfig, (COALESCE("title", ''))))}
|
|
568
|
+
]
|
|
569
|
+
end
|
|
366
570
|
|
|
367
571
|
@db[:posts].insert(:title=>'ruby rails', :body=>'yowsa')
|
|
368
572
|
@db[:posts].insert(:title=>'sequel', :body=>'ruby')
|
|
@@ -372,52 +576,67 @@ describe "A PostgreSQL database" do
|
|
|
372
576
|
@db[:posts].full_text_search(:title, 'rails').all.should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
373
577
|
@db[:posts].full_text_search([:title, :body], ['yowsa', 'rails']).all.should == [:title=>'ruby rails', :body=>'yowsa']
|
|
374
578
|
@db[:posts].full_text_search(:title, 'scooby', :language => 'french').all.should == [{:title=>'ruby scooby', :body=>'x'}]
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
579
|
+
check_sqls do
|
|
580
|
+
@db.sqls.should == [
|
|
581
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('simple'::regconfig, 'rails'))},
|
|
582
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('simple'::regconfig, (COALESCE("title", '') || ' ' || COALESCE("body", ''))) @@ to_tsquery('simple'::regconfig, 'yowsa | rails'))},
|
|
583
|
+
%{SELECT * FROM "posts" WHERE (to_tsvector('french'::regconfig, (COALESCE("title", ''))) @@ to_tsquery('french'::regconfig, 'scooby'))}]
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
@db[:posts].full_text_search(:title, :$n).call(:select, :n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
587
|
+
@db[:posts].full_text_search(:title, :$n).prepare(:select, :fts_select).call(:n=>'rails').should == [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
379
588
|
end
|
|
380
589
|
|
|
381
590
|
specify "should support spatial indexes" do
|
|
382
591
|
@db.create_table(:posts){box :geom; spatial_index [:geom]}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
592
|
+
check_sqls do
|
|
593
|
+
@db.sqls.should == [
|
|
594
|
+
'CREATE TABLE "posts" ("geom" box)',
|
|
595
|
+
'CREATE INDEX "posts_geom_index" ON "posts" USING gist ("geom")'
|
|
596
|
+
]
|
|
597
|
+
end
|
|
387
598
|
end
|
|
388
|
-
|
|
599
|
+
|
|
389
600
|
specify "should support indexes with index type" do
|
|
390
601
|
@db.create_table(:posts){varchar :title, :size => 5; index :title, :type => 'hash'}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
602
|
+
check_sqls do
|
|
603
|
+
@db.sqls.should == [
|
|
604
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
605
|
+
'CREATE INDEX "posts_title_index" ON "posts" USING hash ("title")'
|
|
606
|
+
]
|
|
607
|
+
end
|
|
395
608
|
end
|
|
396
|
-
|
|
609
|
+
|
|
397
610
|
specify "should support unique indexes with index type" do
|
|
398
611
|
@db.create_table(:posts){varchar :title, :size => 5; index :title, :type => 'btree', :unique => true}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
612
|
+
check_sqls do
|
|
613
|
+
@db.sqls.should == [
|
|
614
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
615
|
+
'CREATE UNIQUE INDEX "posts_title_index" ON "posts" USING btree ("title")'
|
|
616
|
+
]
|
|
617
|
+
end
|
|
403
618
|
end
|
|
404
|
-
|
|
619
|
+
|
|
405
620
|
specify "should support partial indexes" do
|
|
406
621
|
@db.create_table(:posts){varchar :title, :size => 5; index :title, :where => {:title => '5'}}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
622
|
+
check_sqls do
|
|
623
|
+
@db.sqls.should == [
|
|
624
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
625
|
+
'CREATE INDEX "posts_title_index" ON "posts" ("title") WHERE ("title" = \'5\')'
|
|
626
|
+
]
|
|
627
|
+
end
|
|
411
628
|
end
|
|
412
|
-
|
|
629
|
+
|
|
413
630
|
specify "should support identifiers for table names in indicies" do
|
|
414
631
|
@db.create_table(Sequel::SQL::Identifier.new(:posts)){varchar :title, :size => 5; index :title, :where => {:title => '5'}}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
632
|
+
check_sqls do
|
|
633
|
+
@db.sqls.should == [
|
|
634
|
+
'CREATE TABLE "posts" ("title" varchar(5))',
|
|
635
|
+
'CREATE INDEX "posts_title_index" ON "posts" ("title") WHERE ("title" = \'5\')'
|
|
636
|
+
]
|
|
637
|
+
end
|
|
419
638
|
end
|
|
420
|
-
|
|
639
|
+
|
|
421
640
|
specify "should support renaming tables" do
|
|
422
641
|
@db.create_table!(:posts1){primary_key :a}
|
|
423
642
|
@db.rename_table(:posts1, :posts)
|
|
@@ -427,38 +646,35 @@ end
|
|
|
427
646
|
describe "Postgres::Dataset#import" do
|
|
428
647
|
before do
|
|
429
648
|
@db = POSTGRES_DB
|
|
430
|
-
@db.create_table!(:test){
|
|
649
|
+
@db.create_table!(:test){primary_key :x; Integer :y}
|
|
431
650
|
@db.sqls.clear
|
|
432
651
|
@ds = @db[:test]
|
|
433
652
|
end
|
|
434
653
|
after do
|
|
435
|
-
@db.drop_table(:test)
|
|
654
|
+
@db.drop_table?(:test)
|
|
436
655
|
end
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
specify "#import should a single insert statement" do
|
|
441
659
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
'INSERT INTO test (x, y) VALUES (1, 2)',
|
|
446
|
-
'INSERT INTO test (x, y) VALUES (3, 4)',
|
|
447
|
-
'COMMIT'
|
|
448
|
-
]
|
|
660
|
+
check_sqls do
|
|
661
|
+
@db.sqls.should == ['BEGIN', 'INSERT INTO "test" ("x", "y") VALUES (1, 2), (3, 4)', 'COMMIT']
|
|
662
|
+
end
|
|
449
663
|
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
450
664
|
end
|
|
451
|
-
|
|
452
|
-
specify "#import should
|
|
453
|
-
@ds.
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
665
|
+
|
|
666
|
+
specify "#import should work correctly when returning primary keys" do
|
|
667
|
+
@ds.import([:x, :y], [[1, 2], [3, 4]], :return=>:primary_key).should == [1, 3]
|
|
668
|
+
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
specify "#import should work correctly when returning primary keys with :slice option" do
|
|
672
|
+
@ds.import([:x, :y], [[1, 2], [3, 4]], :return=>:primary_key, :slice=>1).should == [1, 3]
|
|
673
|
+
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
specify "#import should work correctly with an arbitrary returning value" do
|
|
677
|
+
@ds.returning(:y, :x).import([:x, :y], [[1, 2], [3, 4]]).should == [{:y=>2, :x=>1}, {:y=>4, :x=>3}]
|
|
462
678
|
@ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
463
679
|
end
|
|
464
680
|
end
|
|
@@ -471,7 +687,7 @@ describe "Postgres::Dataset#insert" do
|
|
|
471
687
|
@ds = @db[:test5]
|
|
472
688
|
end
|
|
473
689
|
after do
|
|
474
|
-
@db.drop_table(:test5)
|
|
690
|
+
@db.drop_table?(:test5)
|
|
475
691
|
end
|
|
476
692
|
|
|
477
693
|
specify "should work with static SQL" do
|
|
@@ -480,56 +696,19 @@ describe "Postgres::Dataset#insert" do
|
|
|
480
696
|
@ds.all.should == [{:xid=>1, :value=>10}, {:xid=>2, :value=>20}]
|
|
481
697
|
end
|
|
482
698
|
|
|
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)
|
|
509
|
-
end
|
|
510
|
-
|
|
511
|
-
specify "should use INSERT RETURNING if server_version >= 80200" do
|
|
512
|
-
@ds.meta_def(:server_version){80201}
|
|
513
|
-
@ds.insert(:value=>10)
|
|
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
|
|
699
|
+
specify "should insert correctly if using a column array and a value array" do
|
|
700
|
+
@ds.insert([:value], [10]).should == 1
|
|
701
|
+
@ds.all.should == [{:xid=>1, :value=>10}]
|
|
525
702
|
end
|
|
526
703
|
|
|
527
|
-
specify "should
|
|
528
|
-
@ds.
|
|
704
|
+
specify "should use INSERT RETURNING" do
|
|
705
|
+
@ds.insert(:value=>10).should == 1
|
|
706
|
+
check_sqls do
|
|
707
|
+
@db.sqls.last.should == 'INSERT INTO "test5" ("value") VALUES (10) RETURNING "xid"'
|
|
708
|
+
end
|
|
529
709
|
end
|
|
530
710
|
|
|
531
|
-
specify "should have insert_select insert the record and return the inserted record
|
|
532
|
-
@ds.meta_def(:server_version){80201}
|
|
711
|
+
specify "should have insert_select insert the record and return the inserted record" do
|
|
533
712
|
h = @ds.insert_select(:value=>10)
|
|
534
713
|
h[:value].should == 10
|
|
535
714
|
@ds.first(:xid=>h[:xid])[:value].should == 10
|
|
@@ -545,9 +724,9 @@ describe "Postgres::Dataset#insert" do
|
|
|
545
724
|
end
|
|
546
725
|
|
|
547
726
|
specify "should return nil if the table has no primary key" do
|
|
548
|
-
|
|
549
|
-
ds.delete
|
|
550
|
-
ds.insert(:name=>'a').should == nil
|
|
727
|
+
@db.create_table!(:test5){String :name; Integer :value}
|
|
728
|
+
@ds.delete
|
|
729
|
+
@ds.insert(:name=>'a').should == nil
|
|
551
730
|
end
|
|
552
731
|
end
|
|
553
732
|
|
|
@@ -558,36 +737,35 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
558
737
|
POSTGRES_DB.instance_variable_set(:@primary_key_sequences, {})
|
|
559
738
|
end
|
|
560
739
|
after do
|
|
561
|
-
POSTGRES_DB.quote_identifiers = false
|
|
562
740
|
POSTGRES_DB << "DROP SCHEMA schema_test CASCADE"
|
|
563
741
|
POSTGRES_DB.default_schema = nil
|
|
564
742
|
end
|
|
565
|
-
|
|
743
|
+
|
|
566
744
|
specify "should be able to create, drop, select and insert into tables in a given schema" do
|
|
567
745
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
568
746
|
POSTGRES_DB[:schema_test__schema_test].first.should == nil
|
|
569
747
|
POSTGRES_DB[:schema_test__schema_test].insert(:i=>1).should == 1
|
|
570
748
|
POSTGRES_DB[:schema_test__schema_test].first.should == {:i=>1}
|
|
571
|
-
POSTGRES_DB.from('schema_test.schema_test'
|
|
749
|
+
POSTGRES_DB.from(Sequel.lit('schema_test.schema_test')).first.should == {:i=>1}
|
|
572
750
|
POSTGRES_DB.drop_table(:schema_test__schema_test)
|
|
573
|
-
POSTGRES_DB.create_table(
|
|
751
|
+
POSTGRES_DB.create_table(Sequel.qualify(:schema_test, :schema_test)){integer :i}
|
|
574
752
|
POSTGRES_DB[:schema_test__schema_test].first.should == nil
|
|
575
|
-
POSTGRES_DB.from('schema_test.schema_test'
|
|
576
|
-
POSTGRES_DB.drop_table(
|
|
753
|
+
POSTGRES_DB.from(Sequel.lit('schema_test.schema_test')).first.should == nil
|
|
754
|
+
POSTGRES_DB.drop_table(Sequel.qualify(:schema_test, :schema_test))
|
|
577
755
|
end
|
|
578
|
-
|
|
756
|
+
|
|
579
757
|
specify "#tables should not include tables in a default non-public schema" do
|
|
580
758
|
POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
|
|
581
759
|
POSTGRES_DB.tables.should include(:schema_test)
|
|
582
760
|
POSTGRES_DB.tables.should_not include(:pg_am)
|
|
583
761
|
POSTGRES_DB.tables.should_not include(:domain_udt_usage)
|
|
584
762
|
end
|
|
585
|
-
|
|
763
|
+
|
|
586
764
|
specify "#tables should return tables in the schema provided by the :schema argument" do
|
|
587
765
|
POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
|
|
588
766
|
POSTGRES_DB.tables(:schema=>:schema_test).should == [:schema_test]
|
|
589
767
|
end
|
|
590
|
-
|
|
768
|
+
|
|
591
769
|
specify "#schema should not include columns from tables in a default non-public schema" do
|
|
592
770
|
POSTGRES_DB.create_table(:schema_test__domains){integer :i}
|
|
593
771
|
sch = POSTGRES_DB.schema(:domains)
|
|
@@ -595,7 +773,7 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
595
773
|
cs.should include(:i)
|
|
596
774
|
cs.should_not include(:data_type)
|
|
597
775
|
end
|
|
598
|
-
|
|
776
|
+
|
|
599
777
|
specify "#schema should only include columns from the table in the given :schema argument" do
|
|
600
778
|
POSTGRES_DB.create_table!(:domains){integer :d}
|
|
601
779
|
POSTGRES_DB.create_table(:schema_test__domains){integer :i}
|
|
@@ -605,54 +783,58 @@ describe "Postgres::Database schema qualified tables" do
|
|
|
605
783
|
cs.should_not include(:d)
|
|
606
784
|
POSTGRES_DB.drop_table(:domains)
|
|
607
785
|
end
|
|
608
|
-
|
|
609
|
-
specify "#
|
|
610
|
-
POSTGRES_DB.create_table(:
|
|
611
|
-
POSTGRES_DB.
|
|
612
|
-
|
|
786
|
+
|
|
787
|
+
specify "#schema should raise an exception if columns from tables in two separate schema are returned" do
|
|
788
|
+
POSTGRES_DB.create_table!(:public__domains){integer :d}
|
|
789
|
+
POSTGRES_DB.create_table(:schema_test__domains){integer :i}
|
|
790
|
+
begin
|
|
791
|
+
proc{POSTGRES_DB.schema(:domains)}.should raise_error(Sequel::Error)
|
|
792
|
+
POSTGRES_DB.schema(:public__domains).map{|x| x.first}.should == [:d]
|
|
793
|
+
POSTGRES_DB.schema(:schema_test__domains).map{|x| x.first}.should == [:i]
|
|
794
|
+
ensure
|
|
795
|
+
POSTGRES_DB.drop_table?(:public__domains)
|
|
796
|
+
end
|
|
613
797
|
end
|
|
614
|
-
|
|
798
|
+
|
|
615
799
|
specify "#table_exists? should see if the table is in a given schema" do
|
|
616
800
|
POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
|
|
617
801
|
POSTGRES_DB.table_exists?(:schema_test__schema_test).should == true
|
|
618
802
|
end
|
|
619
|
-
|
|
803
|
+
|
|
620
804
|
specify "should be able to get primary keys for tables in a given schema" do
|
|
621
805
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
622
806
|
POSTGRES_DB.primary_key(:schema_test__schema_test).should == 'i'
|
|
623
807
|
end
|
|
624
|
-
|
|
808
|
+
|
|
625
809
|
specify "should be able to get serial sequences for tables in a given schema" do
|
|
626
810
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
627
|
-
POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test".schema_test_i_seq'
|
|
811
|
+
POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test"."schema_test_i_seq"'
|
|
628
812
|
end
|
|
629
|
-
|
|
813
|
+
|
|
630
814
|
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
815
|
POSTGRES_DB.create_table(:"schema_test__schema test"){primary_key :i}
|
|
633
816
|
POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."schema test_i_seq"'
|
|
634
817
|
end
|
|
635
|
-
|
|
818
|
+
|
|
636
819
|
specify "should be able to get custom sequences for tables in a given schema" do
|
|
637
820
|
POSTGRES_DB << "CREATE SEQUENCE schema_test.kseq"
|
|
638
|
-
POSTGRES_DB.create_table(:schema_test__schema_test){integer :j; primary_key :k, :type=>:integer, :default=>"nextval('schema_test.kseq'::regclass)"
|
|
821
|
+
POSTGRES_DB.create_table(:schema_test__schema_test){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.kseq'::regclass)")}
|
|
639
822
|
POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test".kseq'
|
|
640
823
|
end
|
|
641
|
-
|
|
824
|
+
|
|
642
825
|
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
826
|
POSTGRES_DB << "CREATE SEQUENCE schema_test.\"ks eq\""
|
|
645
|
-
POSTGRES_DB.create_table(:"schema_test__schema test"){integer :j; primary_key :k, :type=>:integer, :default=>"nextval('schema_test.\"ks eq\"'::regclass)"
|
|
827
|
+
POSTGRES_DB.create_table(:"schema_test__schema test"){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.\"ks eq\"'::regclass)")}
|
|
646
828
|
POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."ks eq"'
|
|
647
829
|
end
|
|
648
|
-
|
|
830
|
+
|
|
649
831
|
specify "#default_schema= should change the default schema used from public" do
|
|
650
832
|
POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
|
|
651
833
|
POSTGRES_DB.default_schema = :schema_test
|
|
652
834
|
POSTGRES_DB.table_exists?(:schema_test).should == true
|
|
653
835
|
POSTGRES_DB.tables.should == [:schema_test]
|
|
654
836
|
POSTGRES_DB.primary_key(:schema_test__schema_test).should == 'i'
|
|
655
|
-
POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test".schema_test_i_seq'
|
|
837
|
+
POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test"."schema_test_i_seq"'
|
|
656
838
|
end
|
|
657
839
|
end
|
|
658
840
|
|
|
@@ -661,13 +843,12 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
661
843
|
@db = POSTGRES_DB
|
|
662
844
|
@db.run "DROP SCHEMA s CASCADE" rescue nil
|
|
663
845
|
@db.run "CREATE SCHEMA s"
|
|
664
|
-
|
|
665
|
-
|
|
846
|
+
|
|
666
847
|
@db.create_table(:s__bands){primary_key :id; String :name}
|
|
667
848
|
@db.create_table(:s__albums){primary_key :id; String :name; foreign_key :band_id, :s__bands}
|
|
668
849
|
@db.create_table(:s__tracks){primary_key :id; String :name; foreign_key :album_id, :s__albums}
|
|
669
850
|
@db.create_table(:s__members){primary_key :id; String :name; foreign_key :band_id, :s__bands}
|
|
670
|
-
|
|
851
|
+
|
|
671
852
|
@Band = Class.new(Sequel::Model(:s__bands))
|
|
672
853
|
@Album = Class.new(Sequel::Model(:s__albums))
|
|
673
854
|
@Track = Class.new(Sequel::Model(:s__tracks))
|
|
@@ -676,17 +857,17 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
676
857
|
def @Album.name; :Album; end
|
|
677
858
|
def @Track.name; :Track; end
|
|
678
859
|
def @Member.name; :Member; end
|
|
679
|
-
|
|
860
|
+
|
|
680
861
|
@Band.one_to_many :albums, :class=>@Album, :order=>:name
|
|
681
862
|
@Band.one_to_many :members, :class=>@Member, :order=>:name
|
|
682
863
|
@Album.many_to_one :band, :class=>@Band, :order=>:name
|
|
683
864
|
@Album.one_to_many :tracks, :class=>@Track, :order=>:name
|
|
684
865
|
@Track.many_to_one :album, :class=>@Album, :order=>:name
|
|
685
866
|
@Member.many_to_one :band, :class=>@Band, :order=>:name
|
|
686
|
-
|
|
867
|
+
|
|
687
868
|
@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
869
|
@Band.many_to_many :tracks, :class=>@Track, :join_table=>:s__albums, :right_key=>:id, :right_primary_key=>:album_id, :order=>:name
|
|
689
|
-
|
|
870
|
+
|
|
690
871
|
@b1 = @Band.create(:name=>"BM")
|
|
691
872
|
@b2 = @Band.create(:name=>"J")
|
|
692
873
|
@a1 = @Album.create(:name=>"BM1", :band=>@b1)
|
|
@@ -703,10 +884,9 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
703
884
|
@m4 = @Member.create(:name=>"JC", :band=>@b2)
|
|
704
885
|
end
|
|
705
886
|
after(:all) do
|
|
706
|
-
@db.quote_identifiers = false
|
|
707
887
|
@db.run "DROP SCHEMA s CASCADE"
|
|
708
888
|
end
|
|
709
|
-
|
|
889
|
+
|
|
710
890
|
specify "should return all eager graphs correctly" do
|
|
711
891
|
bands = @Band.order(:bands__name).eager_graph(:albums).all
|
|
712
892
|
bands.should == [@b1, @b2]
|
|
@@ -725,14 +905,14 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
725
905
|
end
|
|
726
906
|
|
|
727
907
|
specify "should have eager graphs work with previous joins" do
|
|
728
|
-
bands = @Band.order(:bands__name).
|
|
908
|
+
bands = @Band.order(:bands__name).select_all(:s__bands).join(:s__members, :band_id=>:id).from_self(:alias=>:bands0).eager_graph(:albums=>:tracks).all
|
|
729
909
|
bands.should == [@b1, @b2]
|
|
730
910
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
731
911
|
bands.map{|x| x.albums.map{|y| y.tracks}}.should == [[[@t1, @t2], [@t3, @t4]], [[], []]]
|
|
732
912
|
end
|
|
733
913
|
|
|
734
914
|
specify "should have eager graphs work with joins with the same tables" do
|
|
735
|
-
bands = @Band.order(:bands__name).
|
|
915
|
+
bands = @Band.order(:bands__name).select_all(:s__bands).join(:s__members, :band_id=>:id).eager_graph({:albums=>:tracks}, :members).all
|
|
736
916
|
bands.should == [@b1, @b2]
|
|
737
917
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
738
918
|
bands.map{|x| x.albums.map{|y| y.tracks}}.should == [[[@t1, @t2], [@t3, @t4]], [[], []]]
|
|
@@ -770,62 +950,62 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
770
950
|
bands.should == [@b1, @b2]
|
|
771
951
|
bands.map{|x| x.tracks}.should == [[@t1, @t2, @t3, @t4], []]
|
|
772
952
|
|
|
773
|
-
bands = @Band.order(:tracks__name).from(:s__bands.as(:tracks)).eager_graph(:tracks).all
|
|
953
|
+
bands = @Band.order(:tracks__name).from(Sequel.expr(:s__bands).as(:tracks)).eager_graph(:tracks).all
|
|
774
954
|
bands.should == [@b1, @b2]
|
|
775
955
|
bands.map{|x| x.tracks}.should == [[@t1, @t2, @t3, @t4], []]
|
|
776
956
|
|
|
777
|
-
bands = @Band.order(:tracks__name).from(:s__bands.as(:tracks
|
|
957
|
+
bands = @Band.order(:tracks__name).from(Sequel.expr(:s__bands).as(Sequel.identifier(:tracks))).eager_graph(:tracks).all
|
|
778
958
|
bands.should == [@b1, @b2]
|
|
779
959
|
bands.map{|x| x.tracks}.should == [[@t1, @t2, @t3, @t4], []]
|
|
780
960
|
|
|
781
|
-
bands = @Band.order(:tracks__name).from(:s__bands.as('tracks')).eager_graph(:tracks).all
|
|
961
|
+
bands = @Band.order(:tracks__name).from(Sequel.expr(:s__bands).as('tracks')).eager_graph(:tracks).all
|
|
782
962
|
bands.should == [@b1, @b2]
|
|
783
963
|
bands.map{|x| x.tracks}.should == [[@t1, @t2, @t3, @t4], []]
|
|
784
964
|
end
|
|
785
965
|
|
|
786
966
|
specify "should have eager graphs work with join tables with aliases" do
|
|
787
|
-
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums___tracks, :band_id
|
|
967
|
+
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums___tracks, :band_id=>Sequel.qualify(:s__bands, :id)).eager_graph(:albums=>:tracks).all
|
|
788
968
|
bands.should == [@b1, @b2]
|
|
789
969
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
790
970
|
bands.map{|x| x.members}.should == [[@m1, @m2], [@m4, @m3]]
|
|
791
971
|
|
|
792
|
-
bands = @Band.order(:bands__name).eager_graph(:members).join(
|
|
972
|
+
bands = @Band.order(:bands__name).eager_graph(:members).join(Sequel.as(:s__albums, :tracks), :band_id=>Sequel.qualify(:s__bands, :id)).eager_graph(:albums=>:tracks).all
|
|
793
973
|
bands.should == [@b1, @b2]
|
|
794
974
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
795
975
|
bands.map{|x| x.members}.should == [[@m1, @m2], [@m4, @m3]]
|
|
796
976
|
|
|
797
|
-
bands = @Band.order(:bands__name).eager_graph(:members).join(
|
|
977
|
+
bands = @Band.order(:bands__name).eager_graph(:members).join(Sequel.as(:s__albums, 'tracks'), :band_id=>Sequel.qualify(:s__bands, :id)).eager_graph(:albums=>:tracks).all
|
|
798
978
|
bands.should == [@b1, @b2]
|
|
799
979
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
800
980
|
bands.map{|x| x.members}.should == [[@m1, @m2], [@m4, @m3]]
|
|
801
981
|
|
|
802
|
-
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums.
|
|
982
|
+
bands = @Band.order(:bands__name).eager_graph(:members).join(Sequel.as(:s__albums, Sequel.identifier(:tracks)), :band_id=>Sequel.qualify(:s__bands, :id)).eager_graph(:albums=>:tracks).all
|
|
803
983
|
bands.should == [@b1, @b2]
|
|
804
984
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
805
985
|
bands.map{|x| x.members}.should == [[@m1, @m2], [@m4, @m3]]
|
|
806
986
|
|
|
807
|
-
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums, {:band_id
|
|
987
|
+
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums, {:band_id=>Sequel.qualify(:s__bands, :id)}, :table_alias=>:tracks).eager_graph(:albums=>:tracks).all
|
|
808
988
|
bands.should == [@b1, @b2]
|
|
809
989
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
810
990
|
bands.map{|x| x.members}.should == [[@m1, @m2], [@m4, @m3]]
|
|
811
991
|
|
|
812
|
-
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums, {:band_id
|
|
992
|
+
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums, {:band_id=>Sequel.qualify(:s__bands, :id)}, :table_alias=>'tracks').eager_graph(:albums=>:tracks).all
|
|
813
993
|
bands.should == [@b1, @b2]
|
|
814
994
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
815
995
|
bands.map{|x| x.members}.should == [[@m1, @m2], [@m4, @m3]]
|
|
816
996
|
|
|
817
|
-
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums, {:band_id
|
|
997
|
+
bands = @Band.order(:bands__name).eager_graph(:members).join(:s__albums, {:band_id=>Sequel.qualify(:s__bands, :id)}, :table_alias=>Sequel.identifier(:tracks)).eager_graph(:albums=>:tracks).all
|
|
818
998
|
bands.should == [@b1, @b2]
|
|
819
999
|
bands.map{|x| x.albums}.should == [[@a1, @a2], [@a3, @a4]]
|
|
820
1000
|
bands.map{|x| x.members}.should == [[@m1, @m2], [@m4, @m3]]
|
|
821
1001
|
end
|
|
822
1002
|
|
|
823
1003
|
specify "should have eager graphs work with different types of qualified from tables" do
|
|
824
|
-
bands = @Band.order(:bands__name).from(
|
|
1004
|
+
bands = @Band.order(:bands__name).from(Sequel.qualify(:s, :bands)).eager_graph(:tracks).all
|
|
825
1005
|
bands.should == [@b1, @b2]
|
|
826
1006
|
bands.map{|x| x.tracks}.should == [[@t1, @t2, @t3, @t4], []]
|
|
827
1007
|
|
|
828
|
-
bands = @Band.order(:bands__name).from(:bands.
|
|
1008
|
+
bands = @Band.order(:bands__name).from(Sequel.identifier(:bands).qualify(:s)).eager_graph(:tracks).all
|
|
829
1009
|
bands.should == [@b1, @b2]
|
|
830
1010
|
bands.map{|x| x.tracks}.should == [[@t1, @t2, @t3, @t4], []]
|
|
831
1011
|
|
|
@@ -837,20 +1017,21 @@ describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
|
837
1017
|
end
|
|
838
1018
|
|
|
839
1019
|
if POSTGRES_DB.server_version >= 80300
|
|
840
|
-
|
|
841
|
-
POSTGRES_DB.create_table! :test6 do
|
|
842
|
-
text :title
|
|
843
|
-
text :body
|
|
844
|
-
full_text_index [:title, :body]
|
|
845
|
-
end
|
|
846
|
-
|
|
847
1020
|
describe "PostgreSQL tsearch2" do
|
|
848
|
-
before do
|
|
1021
|
+
before(:all) do
|
|
1022
|
+
POSTGRES_DB.create_table! :test6 do
|
|
1023
|
+
text :title
|
|
1024
|
+
text :body
|
|
1025
|
+
full_text_index [:title, :body]
|
|
1026
|
+
end
|
|
849
1027
|
@ds = POSTGRES_DB[:test6]
|
|
850
1028
|
end
|
|
851
1029
|
after do
|
|
852
1030
|
POSTGRES_DB[:test6].delete
|
|
853
1031
|
end
|
|
1032
|
+
after(:all) do
|
|
1033
|
+
POSTGRES_DB.drop_table?(:test6)
|
|
1034
|
+
end
|
|
854
1035
|
|
|
855
1036
|
specify "should search by indexed column" do
|
|
856
1037
|
record = {:title => "oopsla conference", :body => "test"}
|
|
@@ -886,9 +1067,9 @@ if POSTGRES_DB.dataset.supports_window_functions?
|
|
|
886
1067
|
@ds.insert(:id=>6, :group_id=>2, :amount=>100000)
|
|
887
1068
|
end
|
|
888
1069
|
after do
|
|
889
|
-
@db.drop_table(:i1)
|
|
1070
|
+
@db.drop_table?(:i1)
|
|
890
1071
|
end
|
|
891
|
-
|
|
1072
|
+
|
|
892
1073
|
specify "should give correct results for window functions" do
|
|
893
1074
|
@ds.window(:win, :partition=>:group_id, :order=>:id).select(:id){sum(:over, :args=>amount, :window=>win){}}.all.should ==
|
|
894
1075
|
[{: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 +1083,16 @@ if POSTGRES_DB.dataset.supports_window_functions?
|
|
|
902
1083
|
end
|
|
903
1084
|
end
|
|
904
1085
|
|
|
905
|
-
describe "Postgres::Database functions, languages, and triggers" do
|
|
1086
|
+
describe "Postgres::Database functions, languages, schemas, and triggers" do
|
|
906
1087
|
before do
|
|
907
1088
|
@d = POSTGRES_DB
|
|
908
1089
|
end
|
|
909
1090
|
after do
|
|
910
1091
|
@d.drop_function('tf', :if_exists=>true, :cascade=>true)
|
|
911
1092
|
@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.
|
|
1093
|
+
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
|
|
1094
|
+
@d.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
|
|
1095
|
+
@d.drop_table?(:test)
|
|
914
1096
|
end
|
|
915
1097
|
|
|
916
1098
|
specify "#create_function and #drop_function should create and drop functions" do
|
|
@@ -923,7 +1105,7 @@ describe "Postgres::Database functions, languages, and triggers" do
|
|
|
923
1105
|
@d.drop_function('tf')
|
|
924
1106
|
proc{@d['SELECT tf()'].all}.should raise_error(Sequel::DatabaseError)
|
|
925
1107
|
end
|
|
926
|
-
|
|
1108
|
+
|
|
927
1109
|
specify "#create_function and #drop_function should support options" do
|
|
928
1110
|
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
1111
|
@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 +1119,33 @@ describe "Postgres::Database functions, languages, and triggers" do
|
|
|
937
1119
|
# Make sure if exists works
|
|
938
1120
|
@d.drop_function(*args)
|
|
939
1121
|
end
|
|
940
|
-
|
|
1122
|
+
|
|
941
1123
|
specify "#create_language and #drop_language should create and drop languages" do
|
|
942
1124
|
@d.send(:create_language_sql, :plpgsql).should == 'CREATE LANGUAGE plpgsql'
|
|
943
|
-
@d.create_language(:plpgsql, :replace=>true)
|
|
1125
|
+
@d.create_language(:plpgsql, :replace=>true) if @d.server_version < 90000
|
|
944
1126
|
proc{@d.create_language(:plpgsql)}.should raise_error(Sequel::DatabaseError)
|
|
945
1127
|
@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)
|
|
1128
|
+
@d.drop_language(:plpgsql) if @d.server_version < 90000
|
|
1129
|
+
proc{@d.drop_language(:plpgsql)}.should raise_error(Sequel::DatabaseError) if @d.server_version < 90000
|
|
948
1130
|
@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
1131
|
@d.send(:drop_language_sql, :plpgsql, :if_exists=>true, :cascade=>true).should == 'DROP LANGUAGE IF EXISTS plpgsql CASCADE'
|
|
950
1132
|
# Make sure if exists works
|
|
951
|
-
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true)
|
|
1133
|
+
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
specify "#create_schema and #drop_schema should create and drop schemas" do
|
|
1137
|
+
@d.send(:create_schema_sql, :sequel).should == 'CREATE SCHEMA "sequel"'
|
|
1138
|
+
@d.send(:drop_schema_sql, :sequel).should == 'DROP SCHEMA "sequel"'
|
|
1139
|
+
@d.send(:drop_schema_sql, :sequel, :if_exists=>true, :cascade=>true).should == 'DROP SCHEMA IF EXISTS "sequel" CASCADE'
|
|
1140
|
+
@d.create_schema(:sequel)
|
|
1141
|
+
@d.create_table(:sequel__test){Integer :a}
|
|
1142
|
+
@d.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
|
|
952
1143
|
end
|
|
953
|
-
|
|
1144
|
+
|
|
954
1145
|
specify "#create_trigger and #drop_trigger should create and drop triggers" do
|
|
955
|
-
@d.create_language(:plpgsql)
|
|
1146
|
+
@d.create_language(:plpgsql) if @d.server_version < 90000
|
|
956
1147
|
@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()'
|
|
1148
|
+
@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
1149
|
@d.create_table(:test){String :name; Integer :value}
|
|
959
1150
|
@d.create_trigger(:test, :identity, :tf, :each_row=>true)
|
|
960
1151
|
@d[:test].insert(:name=>'a', :value=>1)
|
|
@@ -963,41 +1154,45 @@ describe "Postgres::Database functions, languages, and triggers" do
|
|
|
963
1154
|
@d[:test].filter(:name=>'a').all.should == [{:name=>'a', :value=>1}]
|
|
964
1155
|
@d[:test].filter(:name=>'a').update(:value=>3)
|
|
965
1156
|
@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'
|
|
1157
|
+
@d.send(:drop_trigger_sql, :test, :identity).should == 'DROP TRIGGER identity ON "test"'
|
|
967
1158
|
@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'
|
|
1159
|
+
@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\')'
|
|
1160
|
+
@d.send(:drop_trigger_sql, :test, :identity, :if_exists=>true, :cascade=>true).should == 'DROP TRIGGER IF EXISTS identity ON "test" CASCADE'
|
|
970
1161
|
# Make sure if exists works
|
|
971
1162
|
@d.drop_trigger(:test, :identity, :if_exists=>true, :cascade=>true)
|
|
972
1163
|
end
|
|
973
1164
|
end
|
|
974
1165
|
|
|
975
1166
|
if POSTGRES_DB.adapter_scheme == :postgres
|
|
976
|
-
describe "Postgres::Dataset #use_cursor" do
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1167
|
+
describe "Postgres::Dataset #use_cursor" do
|
|
1168
|
+
before(:all) do
|
|
1169
|
+
@db = POSTGRES_DB
|
|
1170
|
+
@db.create_table!(:test_cursor){Integer :x}
|
|
1171
|
+
@db.sqls.clear
|
|
1172
|
+
@ds = @db[:test_cursor]
|
|
1173
|
+
@db.transaction{1001.times{|i| @ds.insert(i)}}
|
|
1174
|
+
end
|
|
1175
|
+
after(:all) do
|
|
1176
|
+
@db.drop_table?(:test_cursor)
|
|
1177
|
+
end
|
|
1178
|
+
|
|
988
1179
|
specify "should return the same results as the non-cursor use" do
|
|
989
1180
|
@ds.all.should == @ds.use_cursor.all
|
|
990
1181
|
end
|
|
991
|
-
|
|
1182
|
+
|
|
992
1183
|
specify "should respect the :rows_per_fetch option" do
|
|
993
1184
|
@db.sqls.clear
|
|
994
1185
|
@ds.use_cursor.all
|
|
995
|
-
|
|
996
|
-
|
|
1186
|
+
check_sqls do
|
|
1187
|
+
@db.sqls.length.should == 6
|
|
1188
|
+
@db.sqls.clear
|
|
1189
|
+
end
|
|
997
1190
|
@ds.use_cursor(:rows_per_fetch=>100).all
|
|
998
|
-
|
|
1191
|
+
check_sqls do
|
|
1192
|
+
@db.sqls.length.should == 15
|
|
1193
|
+
end
|
|
999
1194
|
end
|
|
1000
|
-
|
|
1195
|
+
|
|
1001
1196
|
specify "should handle returning inside block" do
|
|
1002
1197
|
def @ds.check_return
|
|
1003
1198
|
use_cursor.each{|r| return}
|
|
@@ -1005,5 +1200,1572 @@ describe "Postgres::Dataset #use_cursor" do
|
|
|
1005
1200
|
@ds.check_return
|
|
1006
1201
|
@ds.all.should == @ds.use_cursor.all
|
|
1007
1202
|
end
|
|
1203
|
+
end
|
|
1204
|
+
|
|
1205
|
+
describe "Postgres::PG_NAMED_TYPES" do
|
|
1206
|
+
before do
|
|
1207
|
+
@db = POSTGRES_DB
|
|
1208
|
+
Sequel::Postgres::PG_NAMED_TYPES[:interval] = lambda{|v| v.reverse}
|
|
1209
|
+
@db.reset_conversion_procs
|
|
1210
|
+
end
|
|
1211
|
+
after do
|
|
1212
|
+
Sequel::Postgres::PG_NAMED_TYPES.delete(:interval)
|
|
1213
|
+
@db.reset_conversion_procs
|
|
1214
|
+
@db.drop_table?(:foo)
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
specify "should look up conversion procs by name" do
|
|
1218
|
+
@db.create_table!(:foo){interval :bar}
|
|
1219
|
+
@db[:foo].insert(Sequel.cast('21 days', :interval))
|
|
1220
|
+
@db[:foo].get(:bar).should == 'syad 12'
|
|
1221
|
+
end
|
|
1222
|
+
end
|
|
1008
1223
|
end
|
|
1224
|
+
|
|
1225
|
+
if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && POSTGRES_DB.server_version >= 90000
|
|
1226
|
+
describe "Postgres::Database#copy_table" do
|
|
1227
|
+
before(:all) do
|
|
1228
|
+
@db = POSTGRES_DB
|
|
1229
|
+
@db.create_table!(:test_copy){Integer :x; Integer :y}
|
|
1230
|
+
ds = @db[:test_copy]
|
|
1231
|
+
ds.insert(1, 2)
|
|
1232
|
+
ds.insert(3, 4)
|
|
1233
|
+
end
|
|
1234
|
+
after(:all) do
|
|
1235
|
+
@db.drop_table?(:test_copy)
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
specify "without a block or options should return a text version of the table as a single string" do
|
|
1239
|
+
@db.copy_table(:test_copy).should == "1\t2\n3\t4\n"
|
|
1240
|
+
end
|
|
1241
|
+
|
|
1242
|
+
specify "without a block and with :format=>:csv should return a csv version of the table as a single string" do
|
|
1243
|
+
@db.copy_table(:test_copy, :format=>:csv).should == "1,2\n3,4\n"
|
|
1244
|
+
end
|
|
1245
|
+
|
|
1246
|
+
specify "should treat string as SQL code" do
|
|
1247
|
+
@db.copy_table('COPY "test_copy" TO STDOUT').should == "1\t2\n3\t4\n"
|
|
1248
|
+
end
|
|
1249
|
+
|
|
1250
|
+
specify "should respect given :options options" do
|
|
1251
|
+
@db.copy_table(:test_copy, :options=>"FORMAT csv, HEADER TRUE").should == "x,y\n1,2\n3,4\n"
|
|
1252
|
+
end
|
|
1253
|
+
|
|
1254
|
+
specify "should respect given :options options when :format is used" do
|
|
1255
|
+
@db.copy_table(:test_copy, :format=>:csv, :options=>"QUOTE '''', FORCE_QUOTE *").should == "'1','2'\n'3','4'\n"
|
|
1256
|
+
end
|
|
1257
|
+
|
|
1258
|
+
specify "should accept dataset as first argument" do
|
|
1259
|
+
@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"
|
|
1260
|
+
end
|
|
1261
|
+
|
|
1262
|
+
specify "with a block and no options should yield each row as a string in text format" do
|
|
1263
|
+
buf = []
|
|
1264
|
+
@db.copy_table(:test_copy){|b| buf << b}
|
|
1265
|
+
buf.should == ["1\t2\n", "3\t4\n"]
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
specify "with a block and :format=>:csv should yield each row as a string in csv format" do
|
|
1269
|
+
buf = []
|
|
1270
|
+
@db.copy_table(:test_copy, :format=>:csv){|b| buf << b}
|
|
1271
|
+
buf.should == ["1,2\n", "3,4\n"]
|
|
1272
|
+
end
|
|
1273
|
+
|
|
1274
|
+
specify "should work fine when using a block that is terminated early with a following copy_table" do
|
|
1275
|
+
buf = []
|
|
1276
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1277
|
+
buf.should == ["1,2\n"]
|
|
1278
|
+
buf.clear
|
|
1279
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1280
|
+
buf.should == ["1,2\n"]
|
|
1281
|
+
buf.clear
|
|
1282
|
+
@db.copy_table(:test_copy){|b| buf << b}
|
|
1283
|
+
buf.should == ["1\t2\n", "3\t4\n"]
|
|
1284
|
+
end
|
|
1285
|
+
|
|
1286
|
+
specify "should work fine when using a block that is terminated early with a following regular query" do
|
|
1287
|
+
buf = []
|
|
1288
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1289
|
+
buf.should == ["1,2\n"]
|
|
1290
|
+
buf.clear
|
|
1291
|
+
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
1292
|
+
buf.should == ["1,2\n"]
|
|
1293
|
+
@db[:test_copy].select_order_map(:x).should == [1, 3]
|
|
1294
|
+
end
|
|
1295
|
+
end
|
|
1296
|
+
|
|
1297
|
+
describe "Postgres::Database#copy_table_from" do
|
|
1298
|
+
before(:all) do
|
|
1299
|
+
@db = POSTGRES_DB
|
|
1300
|
+
@db.create_table!(:test_copy){Integer :x; Integer :y}
|
|
1301
|
+
@ds = @db[:test_copy].order(:x, :y)
|
|
1302
|
+
end
|
|
1303
|
+
before do
|
|
1304
|
+
@db[:test_copy].delete
|
|
1305
|
+
end
|
|
1306
|
+
after(:all) do
|
|
1307
|
+
@db.drop_table?(:test_copy)
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
specify "should work with a :data option containing data in PostgreSQL text format" do
|
|
1311
|
+
@db.copy_into(:test_copy, :data=>"1\t2\n3\t4\n")
|
|
1312
|
+
@ds.select_map([:x, :y]).should == [[1, 2], [3, 4]]
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
specify "should work with :format=>:csv option and :data option containing data in CSV format" do
|
|
1316
|
+
@db.copy_into(:test_copy, :format=>:csv, :data=>"1,2\n3,4\n")
|
|
1317
|
+
@ds.select_map([:x, :y]).should == [[1, 2], [3, 4]]
|
|
1318
|
+
end
|
|
1319
|
+
|
|
1320
|
+
specify "should respect given :options" do
|
|
1321
|
+
@db.copy_into(:test_copy, :options=>"FORMAT csv, HEADER TRUE", :data=>"x,y\n1,2\n3,4\n")
|
|
1322
|
+
@ds.select_map([:x, :y]).should == [[1, 2], [3, 4]]
|
|
1323
|
+
end
|
|
1324
|
+
|
|
1325
|
+
specify "should respect given :options options when :format is used" do
|
|
1326
|
+
@db.copy_into(:test_copy, :options=>"QUOTE '''', DELIMITER '|'", :format=>:csv, :data=>"'1'|'2'\n'3'|'4'\n")
|
|
1327
|
+
@ds.select_map([:x, :y]).should == [[1, 2], [3, 4]]
|
|
1328
|
+
end
|
|
1329
|
+
|
|
1330
|
+
specify "should accept :columns option to online copy the given columns" do
|
|
1331
|
+
@db.copy_into(:test_copy, :data=>"1\t2\n3\t4\n", :columns=>[:y, :x])
|
|
1332
|
+
@ds.select_map([:x, :y]).should == [[2, 1], [4, 3]]
|
|
1333
|
+
end
|
|
1334
|
+
|
|
1335
|
+
specify "should accept a block and use returned values for the copy in data stream" do
|
|
1336
|
+
buf = ["1\t2\n", "3\t4\n"]
|
|
1337
|
+
@db.copy_into(:test_copy){buf.shift}
|
|
1338
|
+
@ds.select_map([:x, :y]).should == [[1, 2], [3, 4]]
|
|
1339
|
+
end
|
|
1340
|
+
|
|
1341
|
+
specify "should work correctly with a block and :format=>:csv" do
|
|
1342
|
+
buf = ["1,2\n", "3,4\n"]
|
|
1343
|
+
@db.copy_into(:test_copy, :format=>:csv){buf.shift}
|
|
1344
|
+
@ds.select_map([:x, :y]).should == [[1, 2], [3, 4]]
|
|
1345
|
+
end
|
|
1346
|
+
|
|
1347
|
+
specify "should accept an enumerable as the :data option" do
|
|
1348
|
+
@db.copy_into(:test_copy, :data=>["1\t2\n", "3\t4\n"])
|
|
1349
|
+
@ds.select_map([:x, :y]).should == [[1, 2], [3, 4]]
|
|
1350
|
+
end
|
|
1351
|
+
|
|
1352
|
+
specify "should have an exception should cause a rollback of copied data and still have a usable connection" do
|
|
1353
|
+
2.times do
|
|
1354
|
+
sent = false
|
|
1355
|
+
proc{@db.copy_into(:test_copy){raise ArgumentError if sent; sent = true; "1\t2\n"}}.should raise_error(ArgumentError)
|
|
1356
|
+
@ds.select_map([:x, :y]).should == []
|
|
1357
|
+
end
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1360
|
+
specify "should raise an Error if both :data and a block are provided" do
|
|
1361
|
+
proc{@db.copy_into(:test_copy, :data=>["1\t2\n", "3\t4\n"]){}}.should raise_error(Sequel::Error)
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
specify "should raise an Error if neither :data or a block are provided" do
|
|
1365
|
+
proc{@db.copy_into(:test_copy)}.should raise_error(Sequel::Error)
|
|
1366
|
+
end
|
|
1367
|
+
end
|
|
1368
|
+
|
|
1369
|
+
describe "Postgres::Database LISTEN/NOTIFY" do
|
|
1370
|
+
before(:all) do
|
|
1371
|
+
@db = POSTGRES_DB
|
|
1372
|
+
end
|
|
1373
|
+
|
|
1374
|
+
specify "should support listen and notify" do
|
|
1375
|
+
notify_pid = @db.synchronize{|conn| conn.backend_pid}
|
|
1376
|
+
|
|
1377
|
+
called = false
|
|
1378
|
+
@db.listen('foo', :after_listen=>proc{@db.notify('foo')}) do |ev, pid, payload|
|
|
1379
|
+
ev.should == 'foo'
|
|
1380
|
+
pid.should == notify_pid
|
|
1381
|
+
['', nil].should include(payload)
|
|
1382
|
+
called = true
|
|
1383
|
+
end.should == 'foo'
|
|
1384
|
+
called.should be_true
|
|
1385
|
+
|
|
1386
|
+
# Check weird identifier names
|
|
1387
|
+
called = false
|
|
1388
|
+
@db.listen('FOO bar', :after_listen=>proc{@db.notify('FOO bar')}) do |ev, pid, payload|
|
|
1389
|
+
ev.should == 'FOO bar'
|
|
1390
|
+
pid.should == notify_pid
|
|
1391
|
+
['', nil].should include(payload)
|
|
1392
|
+
called = true
|
|
1393
|
+
end.should == 'FOO bar'
|
|
1394
|
+
called.should be_true
|
|
1395
|
+
|
|
1396
|
+
# Check identifier symbols
|
|
1397
|
+
called = false
|
|
1398
|
+
@db.listen(:foo, :after_listen=>proc{@db.notify(:foo)}) do |ev, pid, payload|
|
|
1399
|
+
ev.should == 'foo'
|
|
1400
|
+
pid.should == notify_pid
|
|
1401
|
+
['', nil].should include(payload)
|
|
1402
|
+
called = true
|
|
1403
|
+
end.should == 'foo'
|
|
1404
|
+
called.should be_true
|
|
1405
|
+
|
|
1406
|
+
called = false
|
|
1407
|
+
@db.listen('foo', :after_listen=>proc{@db.notify('foo', :payload=>'bar')}) do |ev, pid, payload|
|
|
1408
|
+
ev.should == 'foo'
|
|
1409
|
+
pid.should == notify_pid
|
|
1410
|
+
payload.should == 'bar'
|
|
1411
|
+
called = true
|
|
1412
|
+
end.should == 'foo'
|
|
1413
|
+
called.should be_true
|
|
1414
|
+
|
|
1415
|
+
@db.listen('foo', :after_listen=>proc{@db.notify('foo')}).should == 'foo'
|
|
1416
|
+
|
|
1417
|
+
called = false
|
|
1418
|
+
called2 = false
|
|
1419
|
+
i = 0
|
|
1420
|
+
@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|
|
|
1421
|
+
if !called
|
|
1422
|
+
ev.should == 'foo'
|
|
1423
|
+
pid.should == notify_pid
|
|
1424
|
+
payload.should == 'bar'
|
|
1425
|
+
called = true
|
|
1426
|
+
else
|
|
1427
|
+
ev.should == 'bar'
|
|
1428
|
+
pid.should == notify_pid
|
|
1429
|
+
payload.should == 'foo'
|
|
1430
|
+
called2 = true
|
|
1431
|
+
break
|
|
1432
|
+
end
|
|
1433
|
+
end.should be_nil
|
|
1434
|
+
called.should be_true
|
|
1435
|
+
called2.should be_true
|
|
1436
|
+
i.should == 1
|
|
1437
|
+
end
|
|
1438
|
+
|
|
1439
|
+
specify "should accept a :timeout option in listen" do
|
|
1440
|
+
@db.listen('foo2', :timeout=>0.001).should == nil
|
|
1441
|
+
called = false
|
|
1442
|
+
@db.listen('foo2', :timeout=>0.001){|ev, pid, payload| called = true}.should == nil
|
|
1443
|
+
called.should be_false
|
|
1444
|
+
i = 0
|
|
1445
|
+
@db.listen('foo2', :timeout=>0.001, :loop=>proc{i+=1; throw :stop if i > 3}){|ev, pid, payload| called = true}.should == nil
|
|
1446
|
+
i.should == 4
|
|
1447
|
+
end unless RUBY_PLATFORM =~ /mingw/ # Ruby freezes on this spec on this platform/version
|
|
1448
|
+
end
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
describe 'PostgreSQL special float handling' do
|
|
1452
|
+
before do
|
|
1453
|
+
@db = POSTGRES_DB
|
|
1454
|
+
@db.create_table!(:test5){Float :value}
|
|
1455
|
+
@db.sqls.clear
|
|
1456
|
+
@ds = @db[:test5]
|
|
1457
|
+
end
|
|
1458
|
+
after do
|
|
1459
|
+
@db.drop_table?(:test5)
|
|
1460
|
+
end
|
|
1461
|
+
|
|
1462
|
+
check_sqls do
|
|
1463
|
+
specify 'should quote NaN' do
|
|
1464
|
+
nan = 0.0/0.0
|
|
1465
|
+
@ds.insert_sql(:value => nan).should == %q{INSERT INTO "test5" ("value") VALUES ('NaN')}
|
|
1466
|
+
end
|
|
1467
|
+
|
|
1468
|
+
specify 'should quote +Infinity' do
|
|
1469
|
+
inf = 1.0/0.0
|
|
1470
|
+
@ds.insert_sql(:value => inf).should == %q{INSERT INTO "test5" ("value") VALUES ('Infinity')}
|
|
1471
|
+
end
|
|
1472
|
+
|
|
1473
|
+
specify 'should quote -Infinity' do
|
|
1474
|
+
inf = -1.0/0.0
|
|
1475
|
+
@ds.insert_sql(:value => inf).should == %q{INSERT INTO "test5" ("value") VALUES ('-Infinity')}
|
|
1476
|
+
end
|
|
1477
|
+
end
|
|
1478
|
+
|
|
1479
|
+
if POSTGRES_DB.adapter_scheme == :postgres
|
|
1480
|
+
specify 'inserts NaN' do
|
|
1481
|
+
nan = 0.0/0.0
|
|
1482
|
+
@ds.insert(:value=>nan)
|
|
1483
|
+
@ds.all[0][:value].nan?.should be_true
|
|
1484
|
+
end
|
|
1485
|
+
|
|
1486
|
+
specify 'inserts +Infinity' do
|
|
1487
|
+
inf = 1.0/0.0
|
|
1488
|
+
@ds.insert(:value=>inf)
|
|
1489
|
+
@ds.all[0][:value].infinite?.should > 0
|
|
1490
|
+
end
|
|
1491
|
+
|
|
1492
|
+
specify 'inserts -Infinity' do
|
|
1493
|
+
inf = -1.0/0.0
|
|
1494
|
+
@ds.insert(:value=>inf)
|
|
1495
|
+
@ds.all[0][:value].infinite?.should < 0
|
|
1496
|
+
end
|
|
1497
|
+
end
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
describe 'PostgreSQL array handling' do
|
|
1501
|
+
before(:all) do
|
|
1502
|
+
@db = POSTGRES_DB
|
|
1503
|
+
@db.extension :pg_array
|
|
1504
|
+
@ds = @db[:items]
|
|
1505
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1506
|
+
@jdbc = POSTGRES_DB.adapter_scheme == :jdbc
|
|
1507
|
+
@tp = lambda{@db.schema(:items).map{|a| a.last[:type]}}
|
|
1508
|
+
end
|
|
1509
|
+
after do
|
|
1510
|
+
@db.drop_table?(:items)
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
specify 'insert and retrieve integer and float arrays of various sizes' do
|
|
1514
|
+
@db.create_table!(:items) do
|
|
1515
|
+
column :i2, 'int2[]'
|
|
1516
|
+
column :i4, 'int4[]'
|
|
1517
|
+
column :i8, 'int8[]'
|
|
1518
|
+
column :r, 'real[]'
|
|
1519
|
+
column :dp, 'double precision[]'
|
|
1520
|
+
end
|
|
1521
|
+
@tp.call.should == [:integer_array, :integer_array, :bigint_array, :float_array, :float_array]
|
|
1522
|
+
@ds.insert(Sequel.pg_array([1], :int2), Sequel.pg_array([nil, 2], :int4), Sequel.pg_array([3, nil], :int8), Sequel.pg_array([4, nil, 4.5], :real), Sequel.pg_array([5, nil, 5.5], "double precision"))
|
|
1523
|
+
@ds.count.should == 1
|
|
1524
|
+
rs = @ds.all
|
|
1525
|
+
if @jdbc || @native
|
|
1526
|
+
rs.should == [{:i2=>[1], :i4=>[nil, 2], :i8=>[3, nil], :r=>[4.0, nil, 4.5], :dp=>[5.0, nil, 5.5]}]
|
|
1527
|
+
end
|
|
1528
|
+
if @native
|
|
1529
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1530
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1531
|
+
@ds.delete
|
|
1532
|
+
@ds.insert(rs.first)
|
|
1533
|
+
@ds.all.should == rs
|
|
1534
|
+
end
|
|
1535
|
+
|
|
1536
|
+
@ds.delete
|
|
1537
|
+
@ds.insert(Sequel.pg_array([[1], [2]], :int2), Sequel.pg_array([[nil, 2], [3, 4]], :int4), Sequel.pg_array([[3, nil], [nil, nil]], :int8), Sequel.pg_array([[4, nil], [nil, 4.5]], :real), Sequel.pg_array([[5, nil], [nil, 5.5]], "double precision"))
|
|
1538
|
+
|
|
1539
|
+
rs = @ds.all
|
|
1540
|
+
if @jdbc || @native
|
|
1541
|
+
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]]}]
|
|
1542
|
+
end
|
|
1543
|
+
if @native
|
|
1544
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1545
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1546
|
+
@ds.delete
|
|
1547
|
+
@ds.insert(rs.first)
|
|
1548
|
+
@ds.all.should == rs
|
|
1549
|
+
end
|
|
1550
|
+
end
|
|
1551
|
+
|
|
1552
|
+
specify 'insert and retrieve decimal arrays' do
|
|
1553
|
+
@db.create_table!(:items) do
|
|
1554
|
+
column :n, 'numeric[]'
|
|
1555
|
+
end
|
|
1556
|
+
@tp.call.should == [:decimal_array]
|
|
1557
|
+
@ds.insert(Sequel.pg_array([BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')], :numeric))
|
|
1558
|
+
@ds.count.should == 1
|
|
1559
|
+
rs = @ds.all
|
|
1560
|
+
if @jdbc || @native
|
|
1561
|
+
rs.should == [{:n=>[BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')]}]
|
|
1562
|
+
end
|
|
1563
|
+
if @native
|
|
1564
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1565
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1566
|
+
@ds.delete
|
|
1567
|
+
@ds.insert(rs.first)
|
|
1568
|
+
@ds.all.should == rs
|
|
1569
|
+
end
|
|
1570
|
+
|
|
1571
|
+
@ds.delete
|
|
1572
|
+
@ds.insert(Sequel.pg_array([[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]], :numeric))
|
|
1573
|
+
rs = @ds.all
|
|
1574
|
+
if @jdbc || @native
|
|
1575
|
+
rs.should == [{:n=>[[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]]}]
|
|
1576
|
+
end
|
|
1577
|
+
if @native
|
|
1578
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1579
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1580
|
+
@ds.delete
|
|
1581
|
+
@ds.insert(rs.first)
|
|
1582
|
+
@ds.all.should == rs
|
|
1583
|
+
end
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
specify 'insert and retrieve string arrays' do
|
|
1587
|
+
@db.create_table!(:items) do
|
|
1588
|
+
column :c, 'char(4)[]'
|
|
1589
|
+
column :vc, 'varchar[]'
|
|
1590
|
+
column :t, 'text[]'
|
|
1591
|
+
end
|
|
1592
|
+
@tp.call.should == [:string_array, :string_array, :string_array]
|
|
1593
|
+
@ds.insert(Sequel.pg_array(['a', nil, 'NULL', 'b"\'c'], 'char(4)'), Sequel.pg_array(['a', nil, 'NULL', 'b"\'c'], :varchar), Sequel.pg_array(['a', nil, 'NULL', 'b"\'c'], :text))
|
|
1594
|
+
@ds.count.should == 1
|
|
1595
|
+
rs = @ds.all
|
|
1596
|
+
if @jdbc || @native
|
|
1597
|
+
rs.should == [{:c=>['a ', nil, 'NULL', 'b"\'c'], :vc=>['a', nil, 'NULL', 'b"\'c'], :t=>['a', nil, 'NULL', 'b"\'c']}]
|
|
1598
|
+
end
|
|
1599
|
+
if @native
|
|
1600
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1601
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1602
|
+
@ds.delete
|
|
1603
|
+
@ds.insert(rs.first)
|
|
1604
|
+
@ds.all.should == rs
|
|
1605
|
+
end
|
|
1606
|
+
|
|
1607
|
+
@ds.delete
|
|
1608
|
+
@ds.insert(Sequel.pg_array([[['a'], [nil]], [['NULL'], ['b"\'c']]], 'char(4)'), Sequel.pg_array([[['a'], ['']], [['NULL'], ['b"\'c']]], :varchar), Sequel.pg_array([[['a'], [nil]], [['NULL'], ['b"\'c']]], :text))
|
|
1609
|
+
rs = @ds.all
|
|
1610
|
+
if @jdbc || @native
|
|
1611
|
+
rs.should == [{:c=>[[['a '], [nil]], [['NULL'], ['b"\'c']]], :vc=>[[['a'], ['']], [['NULL'], ['b"\'c']]], :t=>[[['a'], [nil]], [['NULL'], ['b"\'c']]]}]
|
|
1612
|
+
end
|
|
1613
|
+
if @native
|
|
1614
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1615
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1616
|
+
@ds.delete
|
|
1617
|
+
@ds.insert(rs.first)
|
|
1618
|
+
@ds.all.should == rs
|
|
1619
|
+
end
|
|
1620
|
+
end
|
|
1621
|
+
|
|
1622
|
+
specify 'insert and retrieve arrays of other types' do
|
|
1623
|
+
@db.create_table!(:items) do
|
|
1624
|
+
column :b, 'bool[]'
|
|
1625
|
+
column :d, 'date[]'
|
|
1626
|
+
column :t, 'time[]'
|
|
1627
|
+
column :ts, 'timestamp[]'
|
|
1628
|
+
column :tstz, 'timestamptz[]'
|
|
1629
|
+
end
|
|
1630
|
+
@tp.call.should == [:boolean_array, :date_array, :time_array, :datetime_array, :datetime_timezone_array]
|
|
1631
|
+
|
|
1632
|
+
d = Date.today
|
|
1633
|
+
t = Sequel::SQLTime.create(10, 20, 30)
|
|
1634
|
+
ts = Time.local(2011, 1, 2, 3, 4, 5)
|
|
1635
|
+
|
|
1636
|
+
@ds.insert(Sequel.pg_array([true, false], :bool), Sequel.pg_array([d, nil], :date), Sequel.pg_array([t, nil], :time), Sequel.pg_array([ts, nil], :timestamp), Sequel.pg_array([ts, nil], :timestamptz))
|
|
1637
|
+
@ds.count.should == 1
|
|
1638
|
+
rs = @ds.all
|
|
1639
|
+
if @jdbc || @native
|
|
1640
|
+
rs.should == [{:b=>[true, false], :d=>[d, nil], :t=>[t, nil], :ts=>[ts, nil], :tstz=>[ts, nil]}]
|
|
1641
|
+
end
|
|
1642
|
+
if @native
|
|
1643
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1644
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1645
|
+
@ds.delete
|
|
1646
|
+
@ds.insert(rs.first)
|
|
1647
|
+
@ds.all.should == rs
|
|
1648
|
+
end
|
|
1649
|
+
|
|
1650
|
+
@db.create_table!(:items) do
|
|
1651
|
+
column :ba, 'bytea[]'
|
|
1652
|
+
column :tz, 'timetz[]'
|
|
1653
|
+
column :o, 'oid[]'
|
|
1654
|
+
end
|
|
1655
|
+
@tp.call.should == [:blob_array, :time_timezone_array, :integer_array]
|
|
1656
|
+
@ds.insert(Sequel.pg_array([Sequel.blob("a\0"), nil], :bytea), Sequel.pg_array([t, nil], :timetz), Sequel.pg_array([1, 2, 3], :oid))
|
|
1657
|
+
@ds.count.should == 1
|
|
1658
|
+
if @native
|
|
1659
|
+
rs = @ds.all
|
|
1660
|
+
rs.should == [{:ba=>[Sequel.blob("a\0"), nil], :tz=>[t, nil], :o=>[1, 2, 3]}]
|
|
1661
|
+
rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
|
|
1662
|
+
rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
|
|
1663
|
+
@ds.delete
|
|
1664
|
+
@ds.insert(rs.first)
|
|
1665
|
+
@ds.all.should == rs
|
|
1666
|
+
end
|
|
1667
|
+
end
|
|
1668
|
+
|
|
1669
|
+
specify 'use arrays in bound variables' do
|
|
1670
|
+
@db.create_table!(:items) do
|
|
1671
|
+
column :i, 'int4[]'
|
|
1672
|
+
end
|
|
1673
|
+
@ds.call(:insert, {:i=>[1,2]}, {:i=>:$i})
|
|
1674
|
+
@ds.get(:i).should == [1, 2]
|
|
1675
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[1,2]).should == {:i=>[1,2]}
|
|
1676
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[1,3]).should == nil
|
|
1677
|
+
|
|
1678
|
+
# NULL values
|
|
1679
|
+
@ds.delete
|
|
1680
|
+
@ds.call(:insert, {:i=>[nil,nil]}, {:i=>:$i})
|
|
1681
|
+
@ds.first.should == {:i=>[nil, nil]}
|
|
1682
|
+
|
|
1683
|
+
@db.create_table!(:items) do
|
|
1684
|
+
column :i, 'text[]'
|
|
1685
|
+
end
|
|
1686
|
+
a = ["\"\\\\\"{}\n\t\r \v\b123afP", 'NULL', nil, '']
|
|
1687
|
+
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a))
|
|
1688
|
+
@ds.get(:i).should == a
|
|
1689
|
+
@ds.filter(:i=>:$i).call(:first, :i=>a).should == {:i=>a}
|
|
1690
|
+
@ds.filter(:i=>:$i).call(:first, :i=>['', nil, nil, 'a']).should == nil
|
|
1691
|
+
|
|
1692
|
+
@db.create_table!(:items) do
|
|
1693
|
+
column :i, 'date[]'
|
|
1694
|
+
end
|
|
1695
|
+
a = [Date.today]
|
|
1696
|
+
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'date'))
|
|
1697
|
+
@ds.get(:i).should == a
|
|
1698
|
+
@ds.filter(:i=>:$i).call(:first, :i=>a).should == {:i=>a}
|
|
1699
|
+
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([Date.today-1], 'date')).should == nil
|
|
1700
|
+
|
|
1701
|
+
@db.create_table!(:items) do
|
|
1702
|
+
column :i, 'timestamp[]'
|
|
1703
|
+
end
|
|
1704
|
+
a = [Time.local(2011, 1, 2, 3, 4, 5)]
|
|
1705
|
+
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'timestamp'))
|
|
1706
|
+
@ds.get(:i).should == a
|
|
1707
|
+
@ds.filter(:i=>:$i).call(:first, :i=>a).should == {:i=>a}
|
|
1708
|
+
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([a.first-1], 'timestamp')).should == nil
|
|
1709
|
+
|
|
1710
|
+
@db.create_table!(:items) do
|
|
1711
|
+
column :i, 'boolean[]'
|
|
1712
|
+
end
|
|
1713
|
+
a = [true, false]
|
|
1714
|
+
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'boolean'))
|
|
1715
|
+
@ds.get(:i).should == a
|
|
1716
|
+
@ds.filter(:i=>:$i).call(:first, :i=>a).should == {:i=>a}
|
|
1717
|
+
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([false, true], 'boolean')).should == nil
|
|
1718
|
+
|
|
1719
|
+
@db.create_table!(:items) do
|
|
1720
|
+
column :i, 'bytea[]'
|
|
1721
|
+
end
|
|
1722
|
+
a = [Sequel.blob("a\0'\"")]
|
|
1723
|
+
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'bytea'))
|
|
1724
|
+
@ds.get(:i).should == a
|
|
1725
|
+
@ds.filter(:i=>:$i).call(:first, :i=>a).should == {:i=>a}
|
|
1726
|
+
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([Sequel.blob("b\0")], 'bytea')).should == nil
|
|
1727
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1728
|
+
|
|
1729
|
+
specify 'with models' do
|
|
1730
|
+
@db.create_table!(:items) do
|
|
1731
|
+
primary_key :id
|
|
1732
|
+
column :i, 'integer[]'
|
|
1733
|
+
column :f, 'double precision[]'
|
|
1734
|
+
column :d, 'numeric[]'
|
|
1735
|
+
column :t, 'text[]'
|
|
1736
|
+
end
|
|
1737
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
1738
|
+
c.plugin :pg_typecast_on_load, :i, :f, :d, :t unless @native
|
|
1739
|
+
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']])
|
|
1740
|
+
o.i.should == [1, 2, nil]
|
|
1741
|
+
o.f.should == [[1, 2.5], [3, 4.5]]
|
|
1742
|
+
o.d.should == [BigDecimal.new('1'), BigDecimal.new('1.000000000000000000001')]
|
|
1743
|
+
o.t.should == [%w'a b c', ['NULL', nil, '1']]
|
|
1744
|
+
end
|
|
1745
|
+
|
|
1746
|
+
specify 'operations/functions with pg_array_ops' do
|
|
1747
|
+
Sequel.extension :pg_array_ops
|
|
1748
|
+
@db.create_table!(:items){column :i, 'integer[]'; column :i2, 'integer[]'; column :i3, 'integer[]'; column :i4, 'integer[]'; column :i5, 'integer[]'}
|
|
1749
|
+
@ds.insert(Sequel.pg_array([1, 2, 3]), Sequel.pg_array([2, 1]), Sequel.pg_array([4, 4]), Sequel.pg_array([[5, 5], [4, 3]]), Sequel.pg_array([1, nil, 5]))
|
|
1750
|
+
|
|
1751
|
+
@ds.get(Sequel.pg_array(:i) > :i3).should be_false
|
|
1752
|
+
@ds.get(Sequel.pg_array(:i3) > :i).should be_true
|
|
1753
|
+
|
|
1754
|
+
@ds.get(Sequel.pg_array(:i) >= :i3).should be_false
|
|
1755
|
+
@ds.get(Sequel.pg_array(:i) >= :i).should be_true
|
|
1756
|
+
|
|
1757
|
+
@ds.get(Sequel.pg_array(:i3) < :i).should be_false
|
|
1758
|
+
@ds.get(Sequel.pg_array(:i) < :i3).should be_true
|
|
1759
|
+
|
|
1760
|
+
@ds.get(Sequel.pg_array(:i3) <= :i).should be_false
|
|
1761
|
+
@ds.get(Sequel.pg_array(:i) <= :i).should be_true
|
|
1762
|
+
|
|
1763
|
+
@ds.get(Sequel.expr(5=>Sequel.pg_array(:i).any)).should be_false
|
|
1764
|
+
@ds.get(Sequel.expr(1=>Sequel.pg_array(:i).any)).should be_true
|
|
1765
|
+
|
|
1766
|
+
@ds.get(Sequel.expr(1=>Sequel.pg_array(:i3).all)).should be_false
|
|
1767
|
+
@ds.get(Sequel.expr(4=>Sequel.pg_array(:i3).all)).should be_true
|
|
1768
|
+
|
|
1769
|
+
@ds.get(Sequel.pg_array(:i2)[1]).should == 2
|
|
1770
|
+
@ds.get(Sequel.pg_array(:i2)[2]).should == 1
|
|
1771
|
+
|
|
1772
|
+
@ds.get(Sequel.pg_array(:i4)[2][1]).should == 4
|
|
1773
|
+
@ds.get(Sequel.pg_array(:i4)[2][2]).should == 3
|
|
1774
|
+
|
|
1775
|
+
@ds.get(Sequel.pg_array(:i).contains(:i2)).should be_true
|
|
1776
|
+
@ds.get(Sequel.pg_array(:i).contains(:i3)).should be_false
|
|
1777
|
+
|
|
1778
|
+
@ds.get(Sequel.pg_array(:i2).contained_by(:i)).should be_true
|
|
1779
|
+
@ds.get(Sequel.pg_array(:i).contained_by(:i2)).should be_false
|
|
1780
|
+
|
|
1781
|
+
@ds.get(Sequel.pg_array(:i).overlaps(:i2)).should be_true
|
|
1782
|
+
@ds.get(Sequel.pg_array(:i2).overlaps(:i3)).should be_false
|
|
1783
|
+
|
|
1784
|
+
@ds.get(Sequel.pg_array(:i).dims).should == '[1:3]'
|
|
1785
|
+
@ds.get(Sequel.pg_array(:i).length).should == 3
|
|
1786
|
+
@ds.get(Sequel.pg_array(:i).lower).should == 1
|
|
1787
|
+
|
|
1788
|
+
if @db.server_version >= 90000
|
|
1789
|
+
@ds.get(Sequel.pg_array(:i5).join).should == '15'
|
|
1790
|
+
@ds.get(Sequel.pg_array(:i5).join(':')).should == '1:5'
|
|
1791
|
+
@ds.get(Sequel.pg_array(:i5).join(':', '*')).should == '1:*:5'
|
|
1792
|
+
end
|
|
1793
|
+
@ds.select(Sequel.pg_array(:i).unnest).from_self.count.should == 3 if @db.server_version >= 80400
|
|
1794
|
+
|
|
1795
|
+
if @native
|
|
1796
|
+
@ds.get(Sequel.pg_array(:i).push(4)).should == [1, 2, 3, 4]
|
|
1797
|
+
@ds.get(Sequel.pg_array(:i).unshift(4)).should == [4, 1, 2, 3]
|
|
1798
|
+
@ds.get(Sequel.pg_array(:i).concat(:i2)).should == [1, 2, 3, 2, 1]
|
|
1799
|
+
end
|
|
1800
|
+
end
|
|
1801
|
+
end
|
|
1802
|
+
|
|
1803
|
+
describe 'PostgreSQL hstore handling' do
|
|
1804
|
+
before(:all) do
|
|
1805
|
+
@db = POSTGRES_DB
|
|
1806
|
+
@db.extension :pg_hstore
|
|
1807
|
+
@ds = @db[:items]
|
|
1808
|
+
@h = {'a'=>'b', 'c'=>nil, 'd'=>'NULL', 'e'=>'\\\\" \\\' ,=>'}
|
|
1809
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
1810
|
+
end
|
|
1811
|
+
after do
|
|
1812
|
+
@db.drop_table?(:items)
|
|
1813
|
+
end
|
|
1814
|
+
|
|
1815
|
+
specify 'insert and retrieve hstore values' do
|
|
1816
|
+
@db.create_table!(:items) do
|
|
1817
|
+
column :h, :hstore
|
|
1818
|
+
end
|
|
1819
|
+
@ds.insert(Sequel.hstore(@h))
|
|
1820
|
+
@ds.count.should == 1
|
|
1821
|
+
if @native
|
|
1822
|
+
rs = @ds.all
|
|
1823
|
+
v = rs.first[:h]
|
|
1824
|
+
v.should_not be_a_kind_of(Hash)
|
|
1825
|
+
v.to_hash.should be_a_kind_of(Hash)
|
|
1826
|
+
v.to_hash.should == @h
|
|
1827
|
+
@ds.delete
|
|
1828
|
+
@ds.insert(rs.first)
|
|
1829
|
+
@ds.all.should == rs
|
|
1830
|
+
end
|
|
1831
|
+
end
|
|
1832
|
+
|
|
1833
|
+
specify 'use hstore in bound variables' do
|
|
1834
|
+
@db.create_table!(:items) do
|
|
1835
|
+
column :i, :hstore
|
|
1836
|
+
end
|
|
1837
|
+
@ds.call(:insert, {:i=>Sequel.hstore(@h)}, {:i=>:$i})
|
|
1838
|
+
@ds.get(:i).should == @h
|
|
1839
|
+
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.hstore(@h)).should == {:i=>@h}
|
|
1840
|
+
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.hstore({})).should == nil
|
|
1841
|
+
|
|
1842
|
+
@ds.delete
|
|
1843
|
+
@ds.call(:insert, {:i=>Sequel.hstore('a'=>nil)}, {:i=>:$i})
|
|
1844
|
+
@ds.get(:i).should == Sequel.hstore('a'=>nil)
|
|
1845
|
+
|
|
1846
|
+
@ds.delete
|
|
1847
|
+
@ds.call(:insert, {:i=>@h}, {:i=>:$i})
|
|
1848
|
+
@ds.get(:i).should == @h
|
|
1849
|
+
@ds.filter(:i=>:$i).call(:first, :i=>@h).should == {:i=>@h}
|
|
1850
|
+
@ds.filter(:i=>:$i).call(:first, :i=>{}).should == nil
|
|
1851
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
1852
|
+
|
|
1853
|
+
specify 'with models and associations' do
|
|
1854
|
+
@db.create_table!(:items) do
|
|
1855
|
+
primary_key :id
|
|
1856
|
+
column :h, :hstore
|
|
1857
|
+
end
|
|
1858
|
+
c = Class.new(Sequel::Model(@db[:items])) do
|
|
1859
|
+
def self.name
|
|
1860
|
+
'Item'
|
|
1861
|
+
end
|
|
1862
|
+
unrestrict_primary_key
|
|
1863
|
+
def item_id
|
|
1864
|
+
h['item_id'].to_i if h
|
|
1865
|
+
end
|
|
1866
|
+
def left_item_id
|
|
1867
|
+
h['left_item_id'].to_i if h
|
|
1868
|
+
end
|
|
1869
|
+
end
|
|
1870
|
+
Sequel.extension :pg_hstore_ops
|
|
1871
|
+
c.plugin :many_through_many
|
|
1872
|
+
c.plugin :pg_typecast_on_load, :h unless @native
|
|
1873
|
+
|
|
1874
|
+
h = {'item_id'=>"2", 'left_item_id'=>"1"}
|
|
1875
|
+
o2 = c.create(:id=>2)
|
|
1876
|
+
o = c.create(:id=>1, :h=>h)
|
|
1877
|
+
o.h.should == h
|
|
1878
|
+
|
|
1879
|
+
c.many_to_one :item, :class=>c, :key_column=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer)
|
|
1880
|
+
c.one_to_many :items, :class=>c, :key=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer), :key_method=>:item_id
|
|
1881
|
+
c.many_to_many :related_items, :class=>c, :join_table=>:items___i, :left_key=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer), :right_key=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer)
|
|
1882
|
+
|
|
1883
|
+
c.many_to_one :other_item, :class=>c, :key=>:id, :primary_key_method=>:item_id, :primary_key=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer)
|
|
1884
|
+
c.one_to_many :other_items, :class=>c, :primary_key=>:item_id, :key=>:id, :primary_key_column=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer)
|
|
1885
|
+
c.many_to_many :other_related_items, :class=>c, :join_table=>:items___i, :left_key=>:id, :right_key=>:id,
|
|
1886
|
+
:left_primary_key_column=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer),
|
|
1887
|
+
:left_primary_key=>:left_item_id,
|
|
1888
|
+
:right_primary_key=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer),
|
|
1889
|
+
:right_primary_key_method=>:left_item_id
|
|
1890
|
+
|
|
1891
|
+
c.many_through_many :mtm_items, [
|
|
1892
|
+
[:items, Sequel.cast(Sequel.hstore(:h)['item_id'], Integer), Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer)],
|
|
1893
|
+
[:items, Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer), Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer)]
|
|
1894
|
+
],
|
|
1895
|
+
:class=>c,
|
|
1896
|
+
:left_primary_key_column=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer),
|
|
1897
|
+
:left_primary_key=>:item_id,
|
|
1898
|
+
:right_primary_key=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer),
|
|
1899
|
+
:right_primary_key_method=>:left_item_id
|
|
1900
|
+
|
|
1901
|
+
# Lazily Loading
|
|
1902
|
+
o.item.should == o2
|
|
1903
|
+
o2.items.should == [o]
|
|
1904
|
+
o.related_items.should == [o2]
|
|
1905
|
+
o2.other_item.should == o
|
|
1906
|
+
o.other_items.should == [o2]
|
|
1907
|
+
o.other_related_items.should == [o]
|
|
1908
|
+
o.mtm_items.should == [o]
|
|
1909
|
+
|
|
1910
|
+
# Eager Loading via eager
|
|
1911
|
+
os = c.eager(:item, :related_items, :other_items, :other_related_items, :mtm_items).where(:id=>1).all.first
|
|
1912
|
+
os.item.should == o2
|
|
1913
|
+
os.related_items.should == [o2]
|
|
1914
|
+
os.other_items.should == [o2]
|
|
1915
|
+
os.other_related_items.should == [o]
|
|
1916
|
+
os.mtm_items.should == [o]
|
|
1917
|
+
os = c.eager(:items, :other_item).where(:id=>2).all.first
|
|
1918
|
+
os.items.should == [o]
|
|
1919
|
+
os.other_item.should == o
|
|
1920
|
+
|
|
1921
|
+
# Eager Loading via eager_graph
|
|
1922
|
+
c.eager_graph(:item).where(:items__id=>1).all.first.item.should == o2
|
|
1923
|
+
c.eager_graph(:items).where(:items__id=>2).all.first.items.should == [o]
|
|
1924
|
+
c.eager_graph(:related_items).where(:items__id=>1).all.first.related_items.should == [o2]
|
|
1925
|
+
c.eager_graph(:other_item).where(:items__id=>2).all.first.other_item.should == o
|
|
1926
|
+
c.eager_graph(:other_items).where(:items__id=>1).all.first.other_items.should == [o2]
|
|
1927
|
+
c.eager_graph(:other_related_items).where(:items__id=>1).all.first.other_related_items.should == [o]
|
|
1928
|
+
c.eager_graph(:mtm_items).where(:items__id=>1).all.first.mtm_items.should == [o]
|
|
1929
|
+
|
|
1930
|
+
# Filter By Associations - Model Instances
|
|
1931
|
+
c.filter(:item=>o2).all.should == [o]
|
|
1932
|
+
c.filter(:items=>o).all.should == [o2]
|
|
1933
|
+
c.filter(:related_items=>o2).all.should == [o]
|
|
1934
|
+
c.filter(:other_item=>o).all.should == [o2]
|
|
1935
|
+
c.filter(:other_items=>o2).all.should == [o]
|
|
1936
|
+
c.filter(:other_related_items=>o).all.should == [o]
|
|
1937
|
+
c.filter(:mtm_items=>o).all.should == [o]
|
|
1938
|
+
|
|
1939
|
+
# Filter By Associations - Model Datasets
|
|
1940
|
+
c.filter(:item=>c.filter(:id=>o2.id)).all.should == [o]
|
|
1941
|
+
c.filter(:items=>c.filter(:id=>o.id)).all.should == [o2]
|
|
1942
|
+
c.filter(:related_items=>c.filter(:id=>o2.id)).all.should == [o]
|
|
1943
|
+
c.filter(:other_item=>c.filter(:id=>o.id)).all.should == [o2]
|
|
1944
|
+
c.filter(:other_items=>c.filter(:id=>o2.id)).all.should == [o]
|
|
1945
|
+
c.filter(:other_related_items=>c.filter(:id=>o.id)).all.should == [o]
|
|
1946
|
+
c.filter(:mtm_items=>c.filter(:id=>o.id)).all.should == [o]
|
|
1947
|
+
end
|
|
1948
|
+
|
|
1949
|
+
specify 'operations/functions with pg_hstore_ops' do
|
|
1950
|
+
Sequel.extension :pg_hstore_ops, :pg_array, :pg_array_ops
|
|
1951
|
+
@db.create_table!(:items){hstore :h1; hstore :h2; hstore :h3; String :t}
|
|
1952
|
+
@ds.insert(Sequel.hstore('a'=>'b', 'c'=>nil), Sequel.hstore('a'=>'b'), Sequel.hstore('d'=>'e'))
|
|
1953
|
+
h1 = Sequel.hstore(:h1)
|
|
1954
|
+
h2 = Sequel.hstore(:h2)
|
|
1955
|
+
h3 = Sequel.hstore(:h3)
|
|
1956
|
+
|
|
1957
|
+
@ds.get(h1['a']).should == 'b'
|
|
1958
|
+
@ds.get(h1['d']).should == nil
|
|
1959
|
+
|
|
1960
|
+
@ds.get(h2.concat(h3).keys.pg_array.length).should == 2
|
|
1961
|
+
@ds.get(h1.concat(h3).keys.pg_array.length).should == 3
|
|
1962
|
+
@ds.get(h2.merge(h3).keys.pg_array.length).should == 2
|
|
1963
|
+
@ds.get(h1.merge(h3).keys.pg_array.length).should == 3
|
|
1964
|
+
|
|
1965
|
+
unless [:do].include?(@db.adapter_scheme)
|
|
1966
|
+
# Broken DataObjects thinks operators with ? represent placeholders
|
|
1967
|
+
@ds.get(h1.contain_all(Sequel.pg_array(%w'a c'))).should == true
|
|
1968
|
+
@ds.get(h1.contain_all(Sequel.pg_array(%w'a d'))).should == false
|
|
1969
|
+
|
|
1970
|
+
@ds.get(h1.contain_any(Sequel.pg_array(%w'a d'))).should == true
|
|
1971
|
+
@ds.get(h1.contain_any(Sequel.pg_array(%w'e d'))).should == false
|
|
1972
|
+
end
|
|
1973
|
+
|
|
1974
|
+
@ds.get(h1.contains(h2)).should == true
|
|
1975
|
+
@ds.get(h1.contains(h3)).should == false
|
|
1976
|
+
|
|
1977
|
+
@ds.get(h2.contained_by(h1)).should == true
|
|
1978
|
+
@ds.get(h2.contained_by(h3)).should == false
|
|
1979
|
+
|
|
1980
|
+
@ds.get(h1.defined('a')).should == true
|
|
1981
|
+
@ds.get(h1.defined('c')).should == false
|
|
1982
|
+
@ds.get(h1.defined('d')).should == false
|
|
1983
|
+
|
|
1984
|
+
@ds.get(h1.delete('a')['c']).should == nil
|
|
1985
|
+
@ds.get(h1.delete(Sequel.pg_array(%w'a d'))['c']).should == nil
|
|
1986
|
+
@ds.get(h1.delete(h2)['c']).should == nil
|
|
1987
|
+
|
|
1988
|
+
@ds.from(Sequel.hstore('a'=>'b', 'c'=>nil).op.each).order(:key).all.should == [{:key=>'a', :value=>'b'}, {:key=>'c', :value=>nil}]
|
|
1989
|
+
|
|
1990
|
+
unless [:do].include?(@db.adapter_scheme)
|
|
1991
|
+
@ds.get(h1.has_key?('c')).should == true
|
|
1992
|
+
@ds.get(h1.include?('c')).should == true
|
|
1993
|
+
@ds.get(h1.key?('c')).should == true
|
|
1994
|
+
@ds.get(h1.member?('c')).should == true
|
|
1995
|
+
@ds.get(h1.exist?('c')).should == true
|
|
1996
|
+
@ds.get(h1.has_key?('d')).should == false
|
|
1997
|
+
@ds.get(h1.include?('d')).should == false
|
|
1998
|
+
@ds.get(h1.key?('d')).should == false
|
|
1999
|
+
@ds.get(h1.member?('d')).should == false
|
|
2000
|
+
@ds.get(h1.exist?('d')).should == false
|
|
2001
|
+
end
|
|
2002
|
+
|
|
2003
|
+
@ds.get(h1.hstore.hstore.hstore.keys.pg_array.length).should == 2
|
|
2004
|
+
@ds.get(h1.keys.pg_array.length).should == 2
|
|
2005
|
+
@ds.get(h2.keys.pg_array.length).should == 1
|
|
2006
|
+
@ds.get(h1.akeys.pg_array.length).should == 2
|
|
2007
|
+
@ds.get(h2.akeys.pg_array.length).should == 1
|
|
2008
|
+
|
|
2009
|
+
@ds.from(Sequel.hstore('t'=>'s').op.populate(Sequel::SQL::Cast.new(nil, :items))).select_map(:t).should == ['s']
|
|
2010
|
+
@ds.from(:items___i).select(Sequel.hstore('t'=>'s').op.record_set(:i).as(:r)).from_self(:alias=>:s).select(Sequel.lit('(r).*')).from_self.select_map(:t).should == ['s']
|
|
2011
|
+
|
|
2012
|
+
@ds.from(Sequel.hstore('t'=>'s', 'a'=>'b').op.skeys.as(:s)).select_order_map(:s).should == %w'a t'
|
|
2013
|
+
|
|
2014
|
+
@ds.get(h1.slice(Sequel.pg_array(%w'a c')).keys.pg_array.length).should == 2
|
|
2015
|
+
@ds.get(h1.slice(Sequel.pg_array(%w'd c')).keys.pg_array.length).should == 1
|
|
2016
|
+
@ds.get(h1.slice(Sequel.pg_array(%w'd e')).keys.pg_array.length).should == nil
|
|
2017
|
+
|
|
2018
|
+
@ds.from(Sequel.hstore('t'=>'s', 'a'=>'b').op.svals.as(:s)).select_order_map(:s).should == %w'b s'
|
|
2019
|
+
|
|
2020
|
+
@ds.get(h1.to_array.pg_array.length).should == 4
|
|
2021
|
+
@ds.get(h2.to_array.pg_array.length).should == 2
|
|
2022
|
+
|
|
2023
|
+
@ds.get(h1.to_matrix.pg_array.length).should == 2
|
|
2024
|
+
@ds.get(h2.to_matrix.pg_array.length).should == 1
|
|
2025
|
+
|
|
2026
|
+
@ds.get(h1.values.pg_array.length).should == 2
|
|
2027
|
+
@ds.get(h2.values.pg_array.length).should == 1
|
|
2028
|
+
@ds.get(h1.avals.pg_array.length).should == 2
|
|
2029
|
+
@ds.get(h2.avals.pg_array.length).should == 1
|
|
2030
|
+
end
|
|
2031
|
+
end if POSTGRES_DB.type_supported?(:hstore)
|
|
2032
|
+
|
|
2033
|
+
describe 'PostgreSQL json type' do
|
|
2034
|
+
before(:all) do
|
|
2035
|
+
@db = POSTGRES_DB
|
|
2036
|
+
@db.extension :pg_array, :pg_json
|
|
2037
|
+
@ds = @db[:items]
|
|
2038
|
+
@a = [1, 2, {'a'=>'b'}, 3.0]
|
|
2039
|
+
@h = {'a'=>'b', '1'=>[3, 4, 5]}
|
|
2040
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
2041
|
+
end
|
|
2042
|
+
after do
|
|
2043
|
+
@db.drop_table?(:items)
|
|
2044
|
+
end
|
|
2045
|
+
|
|
2046
|
+
specify 'insert and retrieve json values' do
|
|
2047
|
+
@db.create_table!(:items){json :j}
|
|
2048
|
+
@ds.insert(Sequel.pg_json(@h))
|
|
2049
|
+
@ds.count.should == 1
|
|
2050
|
+
if @native
|
|
2051
|
+
rs = @ds.all
|
|
2052
|
+
v = rs.first[:j]
|
|
2053
|
+
v.should_not be_a_kind_of(Hash)
|
|
2054
|
+
v.to_hash.should be_a_kind_of(Hash)
|
|
2055
|
+
v.should == @h
|
|
2056
|
+
v.to_hash.should == @h
|
|
2057
|
+
@ds.delete
|
|
2058
|
+
@ds.insert(rs.first)
|
|
2059
|
+
@ds.all.should == rs
|
|
2060
|
+
end
|
|
2061
|
+
|
|
2062
|
+
@ds.delete
|
|
2063
|
+
@ds.insert(Sequel.pg_json(@a))
|
|
2064
|
+
@ds.count.should == 1
|
|
2065
|
+
if @native
|
|
2066
|
+
rs = @ds.all
|
|
2067
|
+
v = rs.first[:j]
|
|
2068
|
+
v.should_not be_a_kind_of(Array)
|
|
2069
|
+
v.to_a.should be_a_kind_of(Array)
|
|
2070
|
+
v.should == @a
|
|
2071
|
+
v.to_a.should == @a
|
|
2072
|
+
@ds.delete
|
|
2073
|
+
@ds.insert(rs.first)
|
|
2074
|
+
@ds.all.should == rs
|
|
2075
|
+
end
|
|
2076
|
+
end
|
|
2077
|
+
|
|
2078
|
+
specify 'insert and retrieve json[] values' do
|
|
2079
|
+
@db.create_table!(:items){column :j, 'json[]'}
|
|
2080
|
+
j = Sequel.pg_array([Sequel.pg_json('a'=>1), Sequel.pg_json(['b', 2])])
|
|
2081
|
+
@ds.insert(j)
|
|
2082
|
+
@ds.count.should == 1
|
|
2083
|
+
if @native
|
|
2084
|
+
rs = @ds.all
|
|
2085
|
+
v = rs.first[:j]
|
|
2086
|
+
v.should_not be_a_kind_of(Array)
|
|
2087
|
+
v.to_a.should be_a_kind_of(Array)
|
|
2088
|
+
v.should == j
|
|
2089
|
+
v.to_a.should == j
|
|
2090
|
+
@ds.delete
|
|
2091
|
+
@ds.insert(rs.first)
|
|
2092
|
+
@ds.all.should == rs
|
|
2093
|
+
end
|
|
2094
|
+
end
|
|
2095
|
+
|
|
2096
|
+
specify 'use json in bound variables' do
|
|
2097
|
+
@db.create_table!(:items){json :i}
|
|
2098
|
+
@ds.call(:insert, {:i=>Sequel.pg_json(@h)}, {:i=>:$i})
|
|
2099
|
+
@ds.get(:i).should == @h
|
|
2100
|
+
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:first, :i=>Sequel.pg_json(@h)).should == {:i=>@h}
|
|
2101
|
+
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:first, :i=>Sequel.pg_json({})).should == nil
|
|
2102
|
+
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:delete, :i=>Sequel.pg_json(@h)).should == 1
|
|
2103
|
+
|
|
2104
|
+
@ds.call(:insert, {:i=>Sequel.pg_json(@a)}, {:i=>:$i})
|
|
2105
|
+
@ds.get(:i).should == @a
|
|
2106
|
+
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:first, :i=>Sequel.pg_json(@a)).should == {:i=>@a}
|
|
2107
|
+
@ds.filter(Sequel.cast(:i, String)=>:$i).call(:first, :i=>Sequel.pg_json([])).should == nil
|
|
2108
|
+
|
|
2109
|
+
@ds.delete
|
|
2110
|
+
@ds.call(:insert, {:i=>Sequel.pg_json('a'=>nil)}, {:i=>:$i})
|
|
2111
|
+
@ds.get(:i).should == Sequel.pg_json('a'=>nil)
|
|
2112
|
+
|
|
2113
|
+
@db.create_table!(:items){column :i, 'json[]'}
|
|
2114
|
+
j = Sequel.pg_array([Sequel.pg_json('a'=>1), Sequel.pg_json(['b', 2])], :text)
|
|
2115
|
+
@ds.call(:insert, {:i=>j}, {:i=>:$i})
|
|
2116
|
+
@ds.get(:i).should == j
|
|
2117
|
+
@ds.filter(Sequel.cast(:i, 'text[]')=>:$i).call(:first, :i=>j).should == {:i=>j}
|
|
2118
|
+
@ds.filter(Sequel.cast(:i, 'text[]')=>:$i).call(:first, :i=>Sequel.pg_array([])).should == nil
|
|
2119
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2120
|
+
|
|
2121
|
+
specify 'with models' do
|
|
2122
|
+
@db.create_table!(:items) do
|
|
2123
|
+
primary_key :id
|
|
2124
|
+
json :h
|
|
2125
|
+
end
|
|
2126
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
2127
|
+
c.plugin :pg_typecast_on_load, :h unless @native
|
|
2128
|
+
c.create(:h=>Sequel.pg_json(@h)).h.should == @h
|
|
2129
|
+
c.create(:h=>Sequel.pg_json(@a)).h.should == @a
|
|
2130
|
+
end
|
|
2131
|
+
end if POSTGRES_DB.server_version >= 90200
|
|
2132
|
+
|
|
2133
|
+
describe 'PostgreSQL inet/cidr types' do
|
|
2134
|
+
ipv6_broken = (IPAddr.new('::1'); false) rescue true
|
|
2135
|
+
|
|
2136
|
+
before(:all) do
|
|
2137
|
+
@db = POSTGRES_DB
|
|
2138
|
+
@db.extension :pg_array, :pg_inet
|
|
2139
|
+
@ds = @db[:items]
|
|
2140
|
+
@v4 = '127.0.0.1'
|
|
2141
|
+
@v4nm = '127.0.0.0/8'
|
|
2142
|
+
@v6 = '2001:4f8:3:ba:2e0:81ff:fe22:d1f1'
|
|
2143
|
+
@v6nm = '2001:4f8:3:ba::/64'
|
|
2144
|
+
@ipv4 = IPAddr.new(@v4)
|
|
2145
|
+
@ipv4nm = IPAddr.new(@v4nm)
|
|
2146
|
+
unless ipv6_broken
|
|
2147
|
+
@ipv6 = IPAddr.new(@v6)
|
|
2148
|
+
@ipv6nm = IPAddr.new(@v6nm)
|
|
2149
|
+
end
|
|
2150
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
2151
|
+
end
|
|
2152
|
+
after do
|
|
2153
|
+
@db.drop_table?(:items)
|
|
2154
|
+
end
|
|
2155
|
+
|
|
2156
|
+
specify 'insert and retrieve inet/cidr values' do
|
|
2157
|
+
@db.create_table!(:items){inet :i; cidr :c}
|
|
2158
|
+
@ds.insert(@ipv4, @ipv4nm)
|
|
2159
|
+
@ds.count.should == 1
|
|
2160
|
+
if @native
|
|
2161
|
+
rs = @ds.all
|
|
2162
|
+
rs.first[:i].should == @ipv4
|
|
2163
|
+
rs.first[:c].should == @ipv4nm
|
|
2164
|
+
rs.first[:i].should be_a_kind_of(IPAddr)
|
|
2165
|
+
rs.first[:c].should be_a_kind_of(IPAddr)
|
|
2166
|
+
@ds.delete
|
|
2167
|
+
@ds.insert(rs.first)
|
|
2168
|
+
@ds.all.should == rs
|
|
2169
|
+
end
|
|
2170
|
+
|
|
2171
|
+
unless ipv6_broken
|
|
2172
|
+
@ds.delete
|
|
2173
|
+
@ds.insert(@ipv6, @ipv6nm)
|
|
2174
|
+
@ds.count.should == 1
|
|
2175
|
+
if @native
|
|
2176
|
+
rs = @ds.all
|
|
2177
|
+
v = rs.first[:j]
|
|
2178
|
+
rs.first[:i].should == @ipv6
|
|
2179
|
+
rs.first[:c].should == @ipv6nm
|
|
2180
|
+
rs.first[:i].should be_a_kind_of(IPAddr)
|
|
2181
|
+
rs.first[:c].should be_a_kind_of(IPAddr)
|
|
2182
|
+
@ds.delete
|
|
2183
|
+
@ds.insert(rs.first)
|
|
2184
|
+
@ds.all.should == rs
|
|
2185
|
+
end
|
|
2186
|
+
end
|
|
2187
|
+
end
|
|
2188
|
+
|
|
2189
|
+
specify 'insert and retrieve inet/cidr/macaddr array values' do
|
|
2190
|
+
@db.create_table!(:items){column :i, 'inet[]'; column :c, 'cidr[]'; column :m, 'macaddr[]'}
|
|
2191
|
+
@ds.insert(Sequel.pg_array([@ipv4], 'inet'), Sequel.pg_array([@ipv4nm], 'cidr'), Sequel.pg_array(['12:34:56:78:90:ab'], 'macaddr'))
|
|
2192
|
+
@ds.count.should == 1
|
|
2193
|
+
if @native
|
|
2194
|
+
rs = @ds.all
|
|
2195
|
+
rs.first.values.all?{|c| c.is_a?(Sequel::Postgres::PGArray)}.should be_true
|
|
2196
|
+
rs.first[:i].first.should == @ipv4
|
|
2197
|
+
rs.first[:c].first.should == @ipv4nm
|
|
2198
|
+
rs.first[:m].first.should == '12:34:56:78:90:ab'
|
|
2199
|
+
rs.first[:i].first.should be_a_kind_of(IPAddr)
|
|
2200
|
+
rs.first[:c].first.should be_a_kind_of(IPAddr)
|
|
2201
|
+
@ds.delete
|
|
2202
|
+
@ds.insert(rs.first)
|
|
2203
|
+
@ds.all.should == rs
|
|
2204
|
+
end
|
|
2205
|
+
end
|
|
2206
|
+
|
|
2207
|
+
specify 'use ipaddr in bound variables' do
|
|
2208
|
+
@db.create_table!(:items){inet :i; cidr :c}
|
|
2209
|
+
|
|
2210
|
+
@ds.call(:insert, {:i=>@ipv4, :c=>@ipv4nm}, {:i=>:$i, :c=>:$c})
|
|
2211
|
+
@ds.get(:i).should == @ipv4
|
|
2212
|
+
@ds.get(:c).should == @ipv4nm
|
|
2213
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv4, :c=>@ipv4nm).should == {:i=>@ipv4, :c=>@ipv4nm}
|
|
2214
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv6, :c=>@ipv6nm).should == nil
|
|
2215
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:delete, :i=>@ipv4, :c=>@ipv4nm).should == 1
|
|
2216
|
+
|
|
2217
|
+
unless ipv6_broken
|
|
2218
|
+
@ds.call(:insert, {:i=>@ipv6, :c=>@ipv6nm}, {:i=>:$i, :c=>:$c})
|
|
2219
|
+
@ds.get(:i).should == @ipv6
|
|
2220
|
+
@ds.get(:c).should == @ipv6nm
|
|
2221
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv6, :c=>@ipv6nm).should == {:i=>@ipv6, :c=>@ipv6nm}
|
|
2222
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv4, :c=>@ipv4nm).should == nil
|
|
2223
|
+
@ds.filter(:i=>:$i, :c=>:$c).call(:delete, :i=>@ipv6, :c=>@ipv6nm).should == 1
|
|
2224
|
+
end
|
|
2225
|
+
|
|
2226
|
+
@db.create_table!(:items){column :i, 'inet[]'; column :c, 'cidr[]'; column :m, 'macaddr[]'}
|
|
2227
|
+
@ds.call(:insert, {:i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab']}, {:i=>:$i, :c=>:$c, :m=>:$m})
|
|
2228
|
+
@ds.filter(:i=>:$i, :c=>:$c, :m=>:$m).call(:first, :i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab']).should == {:i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab']}
|
|
2229
|
+
@ds.filter(:i=>:$i, :c=>:$c, :m=>:$m).call(:first, :i=>[], :c=>[], :m=>[]).should == nil
|
|
2230
|
+
@ds.filter(:i=>:$i, :c=>:$c, :m=>:$m).call(:delete, :i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab']).should == 1
|
|
2231
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2232
|
+
|
|
2233
|
+
specify 'with models' do
|
|
2234
|
+
@db.create_table!(:items) do
|
|
2235
|
+
primary_key :id
|
|
2236
|
+
inet :i
|
|
2237
|
+
cidr :c
|
|
2238
|
+
end
|
|
2239
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
2240
|
+
c.plugin :pg_typecast_on_load, :i, :c unless @native
|
|
2241
|
+
c.create(:i=>@v4, :c=>@v4nm).values.values_at(:i, :c).should == [@ipv4, @ipv4nm]
|
|
2242
|
+
unless ipv6_broken
|
|
2243
|
+
c.create(:i=>@ipv6, :c=>@ipv6nm).values.values_at(:i, :c).should == [@ipv6, @ipv6nm]
|
|
2244
|
+
end
|
|
2245
|
+
end
|
|
2246
|
+
end
|
|
2247
|
+
|
|
2248
|
+
describe 'PostgreSQL range types' do
|
|
2249
|
+
before(:all) do
|
|
2250
|
+
@db = POSTGRES_DB
|
|
2251
|
+
@db.extension :pg_array, :pg_range
|
|
2252
|
+
@ds = @db[:items]
|
|
2253
|
+
@map = {:i4=>'int4range', :i8=>'int8range', :n=>'numrange', :d=>'daterange', :t=>'tsrange', :tz=>'tstzrange'}
|
|
2254
|
+
@r = {:i4=>1...2, :i8=>2...3, :n=>BigDecimal.new('1.0')..BigDecimal.new('2.0'), :d=>Date.today...(Date.today+1), :t=>Time.local(2011, 1)..Time.local(2011, 2), :tz=>Time.local(2011, 1)..Time.local(2011, 2)}
|
|
2255
|
+
@ra = {}
|
|
2256
|
+
@pgr = {}
|
|
2257
|
+
@pgra = {}
|
|
2258
|
+
@r.each{|k, v| @ra[k] = Sequel.pg_array([v], @map[k])}
|
|
2259
|
+
@r.each{|k, v| @pgr[k] = Sequel.pg_range(v)}
|
|
2260
|
+
@r.each{|k, v| @pgra[k] = Sequel.pg_array([Sequel.pg_range(v)], @map[k])}
|
|
2261
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
2262
|
+
end
|
|
2263
|
+
after do
|
|
2264
|
+
@db.drop_table?(:items)
|
|
2265
|
+
end
|
|
2266
|
+
|
|
2267
|
+
specify 'insert and retrieve range type values' do
|
|
2268
|
+
@db.create_table!(:items){int4range :i4; int8range :i8; numrange :n; daterange :d; tsrange :t; tstzrange :tz}
|
|
2269
|
+
[@r, @pgr].each do |input|
|
|
2270
|
+
h = {}
|
|
2271
|
+
input.each{|k, v| h[k] = Sequel.cast(v, @map[k])}
|
|
2272
|
+
@ds.insert(h)
|
|
2273
|
+
@ds.count.should == 1
|
|
2274
|
+
if @native
|
|
2275
|
+
rs = @ds.all
|
|
2276
|
+
rs.first.each do |k, v|
|
|
2277
|
+
v.should_not be_a_kind_of(Range)
|
|
2278
|
+
v.to_range.should be_a_kind_of(Range)
|
|
2279
|
+
v.should == @r[k]
|
|
2280
|
+
v.to_range.should == @r[k]
|
|
2281
|
+
end
|
|
2282
|
+
@ds.delete
|
|
2283
|
+
@ds.insert(rs.first)
|
|
2284
|
+
@ds.all.should == rs
|
|
2285
|
+
end
|
|
2286
|
+
@ds.delete
|
|
2287
|
+
end
|
|
2288
|
+
end
|
|
2289
|
+
|
|
2290
|
+
specify 'insert and retrieve arrays of range type values' do
|
|
2291
|
+
@db.create_table!(:items){column :i4, 'int4range[]'; column :i8, 'int8range[]'; column :n, 'numrange[]'; column :d, 'daterange[]'; column :t, 'tsrange[]'; column :tz, 'tstzrange[]'}
|
|
2292
|
+
[@ra, @pgra].each do |input|
|
|
2293
|
+
@ds.insert(input)
|
|
2294
|
+
@ds.count.should == 1
|
|
2295
|
+
if @native
|
|
2296
|
+
rs = @ds.all
|
|
2297
|
+
rs.first.each do |k, v|
|
|
2298
|
+
v.should_not be_a_kind_of(Array)
|
|
2299
|
+
v.to_a.should be_a_kind_of(Array)
|
|
2300
|
+
v.first.should_not be_a_kind_of(Range)
|
|
2301
|
+
v.first.to_range.should be_a_kind_of(Range)
|
|
2302
|
+
v.should == @ra[k].to_a
|
|
2303
|
+
v.first.should == @r[k]
|
|
2304
|
+
end
|
|
2305
|
+
@ds.delete
|
|
2306
|
+
@ds.insert(rs.first)
|
|
2307
|
+
@ds.all.should == rs
|
|
2308
|
+
end
|
|
2309
|
+
@ds.delete
|
|
2310
|
+
end
|
|
2311
|
+
end
|
|
2312
|
+
|
|
2313
|
+
specify 'use range types in bound variables' do
|
|
2314
|
+
@db.create_table!(:items){int4range :i4; int8range :i8; numrange :n; daterange :d; tsrange :t; tstzrange :tz}
|
|
2315
|
+
h = {}
|
|
2316
|
+
@r.keys.each{|k| h[k] = :"$#{k}"}
|
|
2317
|
+
r2 = {}
|
|
2318
|
+
@r.each{|k, v| r2[k] = Range.new(v.begin, v.end+2)}
|
|
2319
|
+
@ds.call(:insert, @r, h)
|
|
2320
|
+
@ds.first.should == @r
|
|
2321
|
+
@ds.filter(h).call(:first, @r).should == @r
|
|
2322
|
+
@ds.filter(h).call(:first, @pgr).should == @r
|
|
2323
|
+
@ds.filter(h).call(:first, r2).should == nil
|
|
2324
|
+
@ds.filter(h).call(:delete, @r).should == 1
|
|
2325
|
+
|
|
2326
|
+
@db.create_table!(:items){column :i4, 'int4range[]'; column :i8, 'int8range[]'; column :n, 'numrange[]'; column :d, 'daterange[]'; column :t, 'tsrange[]'; column :tz, 'tstzrange[]'}
|
|
2327
|
+
@r.each{|k, v| r2[k] = [Range.new(v.begin, v.end+2)]}
|
|
2328
|
+
@ds.call(:insert, @ra, h)
|
|
2329
|
+
@ds.filter(h).call(:first, @ra).each{|k, v| v.should == @ra[k].to_a}
|
|
2330
|
+
@ds.filter(h).call(:first, @pgra).each{|k, v| v.should == @ra[k].to_a}
|
|
2331
|
+
@ds.filter(h).call(:first, r2).should == nil
|
|
2332
|
+
@ds.filter(h).call(:delete, @ra).should == 1
|
|
2333
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2334
|
+
|
|
2335
|
+
specify 'with models' do
|
|
2336
|
+
@db.create_table!(:items){primary_key :id; int4range :i4; int8range :i8; numrange :n; daterange :d; tsrange :t; tstzrange :tz}
|
|
2337
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
2338
|
+
c.plugin :pg_typecast_on_load, :i4, :i8, :n, :d, :t, :tz unless @native
|
|
2339
|
+
v = c.create(@r).values
|
|
2340
|
+
v.delete(:id)
|
|
2341
|
+
v.should == @r
|
|
2342
|
+
|
|
2343
|
+
unless @db.adapter_scheme == :jdbc
|
|
2344
|
+
@db.create_table!(:items){primary_key :id; column :i4, 'int4range[]'; column :i8, 'int8range[]'; column :n, 'numrange[]'; column :d, 'daterange[]'; column :t, 'tsrange[]'; column :tz, 'tstzrange[]'}
|
|
2345
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
2346
|
+
c.plugin :pg_typecast_on_load, :i4, :i8, :n, :d, :t, :tz unless @native
|
|
2347
|
+
v = c.create(@ra).values
|
|
2348
|
+
v.delete(:id)
|
|
2349
|
+
v.each{|k,v| v.should == @ra[k].to_a}
|
|
2350
|
+
end
|
|
2351
|
+
end
|
|
2352
|
+
|
|
2353
|
+
specify 'operations/functions with pg_range_ops' do
|
|
2354
|
+
Sequel.extension :pg_range_ops
|
|
2355
|
+
|
|
2356
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.contains(2..4)).should be_true
|
|
2357
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.contains(3..6)).should be_false
|
|
2358
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.contains(0..6)).should be_false
|
|
2359
|
+
|
|
2360
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.contained_by(0..6)).should be_true
|
|
2361
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.contained_by(3..6)).should be_false
|
|
2362
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.contained_by(2..4)).should be_false
|
|
2363
|
+
|
|
2364
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.overlaps(5..6)).should be_true
|
|
2365
|
+
@db.get(Sequel.pg_range(1...5, :int4range).op.overlaps(5..6)).should be_false
|
|
2366
|
+
|
|
2367
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(6..10)).should be_true
|
|
2368
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(5..10)).should be_false
|
|
2369
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(-1..0)).should be_false
|
|
2370
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(-1..3)).should be_false
|
|
2371
|
+
|
|
2372
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(6..10)).should be_false
|
|
2373
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(5..10)).should be_false
|
|
2374
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(-1..0)).should be_true
|
|
2375
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(-1..3)).should be_false
|
|
2376
|
+
|
|
2377
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_before(6..10)).should be_true
|
|
2378
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_before(5..10)).should be_true
|
|
2379
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_before(-1..0)).should be_false
|
|
2380
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_before(-1..3)).should be_false
|
|
2381
|
+
|
|
2382
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_after(6..10)).should be_false
|
|
2383
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_after(5..10)).should be_false
|
|
2384
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_after(-1..0)).should be_true
|
|
2385
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_after(-1..3)).should be_true
|
|
2386
|
+
|
|
2387
|
+
@db.get(Sequel.pg_range(1..5, :int4range).op.adjacent_to(6..10)).should be_true
|
|
2388
|
+
@db.get(Sequel.pg_range(1...5, :int4range).op.adjacent_to(6..10)).should be_false
|
|
2389
|
+
|
|
2390
|
+
@db.get((Sequel.pg_range(1..5, :int4range).op + (6..10)).adjacent_to(6..10)).should be_false
|
|
2391
|
+
@db.get((Sequel.pg_range(1..5, :int4range).op + (6..10)).adjacent_to(11..20)).should be_true
|
|
2392
|
+
|
|
2393
|
+
@db.get((Sequel.pg_range(1..5, :int4range).op * (2..6)).adjacent_to(6..10)).should be_true
|
|
2394
|
+
@db.get((Sequel.pg_range(1..4, :int4range).op * (2..6)).adjacent_to(6..10)).should be_false
|
|
2395
|
+
|
|
2396
|
+
@db.get((Sequel.pg_range(1..5, :int4range).op - (2..6)).adjacent_to(2..10)).should be_true
|
|
2397
|
+
@db.get((Sequel.pg_range(0..4, :int4range).op - (3..6)).adjacent_to(4..10)).should be_false
|
|
2398
|
+
|
|
2399
|
+
@db.get(Sequel.pg_range(0..4, :int4range).op.lower).should == 0
|
|
2400
|
+
@db.get(Sequel.pg_range(0..4, :int4range).op.upper).should == 5
|
|
2401
|
+
|
|
2402
|
+
@db.get(Sequel.pg_range(0..4, :int4range).op.isempty).should be_false
|
|
2403
|
+
@db.get(Sequel::Postgres::PGRange.empty(:int4range).op.isempty).should be_true
|
|
2404
|
+
|
|
2405
|
+
@db.get(Sequel.pg_range(1..5, :numrange).op.lower_inc).should be_true
|
|
2406
|
+
@db.get(Sequel::Postgres::PGRange.new(1, 5, :exclude_begin=>true, :db_type=>:numrange).op.lower_inc).should be_false
|
|
2407
|
+
|
|
2408
|
+
@db.get(Sequel.pg_range(1..5, :numrange).op.upper_inc).should be_true
|
|
2409
|
+
@db.get(Sequel.pg_range(1...5, :numrange).op.upper_inc).should be_false
|
|
2410
|
+
|
|
2411
|
+
@db.get(Sequel::Postgres::PGRange.new(1, 5, :db_type=>:int4range).op.lower_inf).should be_false
|
|
2412
|
+
@db.get(Sequel::Postgres::PGRange.new(nil, 5, :db_type=>:int4range).op.lower_inf).should be_true
|
|
2413
|
+
|
|
2414
|
+
@db.get(Sequel::Postgres::PGRange.new(1, 5, :db_type=>:int4range).op.upper_inf).should be_false
|
|
2415
|
+
@db.get(Sequel::Postgres::PGRange.new(1, nil, :db_type=>:int4range).op.upper_inf).should be_true
|
|
2416
|
+
end
|
|
2417
|
+
end if POSTGRES_DB.server_version >= 90200
|
|
2418
|
+
|
|
2419
|
+
describe 'PostgreSQL interval types' do
|
|
2420
|
+
before(:all) do
|
|
2421
|
+
@db = POSTGRES_DB
|
|
2422
|
+
@db.extension :pg_array, :pg_interval
|
|
2423
|
+
@ds = @db[:items]
|
|
2424
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
2425
|
+
end
|
|
2426
|
+
after(:all) do
|
|
2427
|
+
Sequel::Postgres::PG_TYPES.delete(1186)
|
|
2428
|
+
end
|
|
2429
|
+
after do
|
|
2430
|
+
@db.drop_table?(:items)
|
|
2431
|
+
end
|
|
2432
|
+
|
|
2433
|
+
specify 'insert and retrieve interval values' do
|
|
2434
|
+
@db.create_table!(:items){interval :i}
|
|
2435
|
+
[
|
|
2436
|
+
['0', '00:00:00', 0, [[:seconds, 0]]],
|
|
2437
|
+
['1 microsecond', '00:00:00.000001', 0.000001, [[:seconds, 0.000001]]],
|
|
2438
|
+
['1 millisecond', '00:00:00.001', 0.001, [[:seconds, 0.001]]],
|
|
2439
|
+
['1 second', '00:00:01', 1, [[:seconds, 1]]],
|
|
2440
|
+
['1 minute', '00:01:00', 60, [[:seconds, 60]]],
|
|
2441
|
+
['1 hour', '01:00:00', 3600, [[:seconds, 3600]]],
|
|
2442
|
+
['1 day', '1 day', 86400, [[:days, 1]]],
|
|
2443
|
+
['1 week', '7 days', 86400*7, [[:days, 7]]],
|
|
2444
|
+
['1 month', '1 mon', 86400*30, [[:months, 1]]],
|
|
2445
|
+
['1 year', '1 year', 31557600, [[:years, 1]]],
|
|
2446
|
+
['1 decade', '10 years', 31557600*10, [[:years, 10]]],
|
|
2447
|
+
['1 century', '100 years', 31557600*100, [[:years, 100]]],
|
|
2448
|
+
['1 millennium', '1000 years', 31557600*1000, [[:years, 1000]]],
|
|
2449
|
+
['1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds', '1 year 2 mons 25 days 05:06:07', 31557600 + 2*86400*30 + 3*86400*7 + 4*86400 + 5*3600 + 6*60 + 7, [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]]],
|
|
2450
|
+
['-1 year +2 months -3 weeks +4 days -5 hours +6 minutes -7 seconds', '-10 mons -17 days -04:54:07', -10*86400*30 - 3*86400*7 + 4*86400 - 5*3600 + 6*60 - 7, [[:months, -10], [:days, -17], [:seconds, -17647]]],
|
|
2451
|
+
['+2 years -1 months +3 weeks -4 days +5 hours -6 minutes +7 seconds', '1 year 11 mons 17 days 04:54:07', 31557600 + 11*86400*30 + 3*86400*7 - 4*86400 + 5*3600 - 6*60 + 7, [[:years, 1], [:months, 11], [:days, 17], [:seconds, 17647]]],
|
|
2452
|
+
].each do |instr, outstr, value, parts|
|
|
2453
|
+
@ds.insert(instr)
|
|
2454
|
+
@ds.count.should == 1
|
|
2455
|
+
if @native
|
|
2456
|
+
@ds.get(Sequel.cast(:i, String)).should == outstr
|
|
2457
|
+
rs = @ds.all
|
|
2458
|
+
rs.first[:i].is_a?(ActiveSupport::Duration).should be_true
|
|
2459
|
+
rs.first[:i].should == ActiveSupport::Duration.new(value, parts)
|
|
2460
|
+
rs.first[:i].parts.sort_by{|k,v| k.to_s}.should == parts.sort_by{|k,v| k.to_s}
|
|
2461
|
+
@ds.delete
|
|
2462
|
+
@ds.insert(rs.first)
|
|
2463
|
+
@ds.all.should == rs
|
|
2464
|
+
end
|
|
2465
|
+
@ds.delete
|
|
2466
|
+
end
|
|
2467
|
+
end
|
|
2468
|
+
|
|
2469
|
+
specify 'insert and retrieve interval array values' do
|
|
2470
|
+
@db.create_table!(:items){column :i, 'interval[]'}
|
|
2471
|
+
@ds.insert(Sequel.pg_array(['1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds'], 'interval'))
|
|
2472
|
+
@ds.count.should == 1
|
|
2473
|
+
if @native
|
|
2474
|
+
rs = @ds.all
|
|
2475
|
+
rs.first[:i].is_a?(Sequel::Postgres::PGArray).should be_true
|
|
2476
|
+
rs.first[:i].first.is_a?(ActiveSupport::Duration).should be_true
|
|
2477
|
+
rs.first[:i].first.should == ActiveSupport::Duration.new(31557600 + 2*86400*30 + 3*86400*7 + 4*86400 + 5*3600 + 6*60 + 7, [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]])
|
|
2478
|
+
rs.first[:i].first.parts.sort_by{|k,v| k.to_s}.should == [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]].sort_by{|k,v| k.to_s}
|
|
2479
|
+
@ds.delete
|
|
2480
|
+
@ds.insert(rs.first)
|
|
2481
|
+
@ds.all.should == rs
|
|
2482
|
+
end
|
|
2483
|
+
end
|
|
2484
|
+
|
|
2485
|
+
specify 'use intervals in bound variables' do
|
|
2486
|
+
@db.create_table!(:items){interval :i}
|
|
2487
|
+
@ds.insert('1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds')
|
|
2488
|
+
d = @ds.get(:i)
|
|
2489
|
+
@ds.delete
|
|
2490
|
+
|
|
2491
|
+
@ds.call(:insert, {:i=>d}, {:i=>:$i})
|
|
2492
|
+
@ds.get(:i).should == d
|
|
2493
|
+
@ds.filter(:i=>:$i).call(:first, :i=>d).should == {:i=>d}
|
|
2494
|
+
@ds.filter(:i=>:$i).call(:first, :i=>'0').should == nil
|
|
2495
|
+
@ds.filter(:i=>:$i).call(:delete, :i=>d).should == 1
|
|
2496
|
+
|
|
2497
|
+
@db.create_table!(:items){column :i, 'interval[]'}
|
|
2498
|
+
@ds.call(:insert, {:i=>[d]}, {:i=>:$i})
|
|
2499
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[d]).should == {:i=>[d]}
|
|
2500
|
+
@ds.filter(:i=>:$i).call(:first, :i=>[]).should == nil
|
|
2501
|
+
@ds.filter(:i=>:$i).call(:delete, :i=>[d]).should == 1
|
|
2502
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2503
|
+
|
|
2504
|
+
specify 'with models' do
|
|
2505
|
+
@db.create_table!(:items) do
|
|
2506
|
+
primary_key :id
|
|
2507
|
+
interval :i
|
|
2508
|
+
end
|
|
2509
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
|
2510
|
+
c.plugin :pg_typecast_on_load, :i, :c unless @native
|
|
2511
|
+
v = c.create(:i=>'1 year 2 mons 25 days 05:06:07').i
|
|
2512
|
+
v.is_a?(ActiveSupport::Duration).should be_true
|
|
2513
|
+
v.should == ActiveSupport::Duration.new(31557600 + 2*86400*30 + 3*86400*7 + 4*86400 + 5*3600 + 6*60 + 7, [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]])
|
|
2514
|
+
v.parts.sort_by{|k,v| k.to_s}.should == [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]].sort_by{|k,v| k.to_s}
|
|
2515
|
+
end
|
|
2516
|
+
end if ((require 'active_support/duration'; require 'active_support/inflector'; require 'active_support/core_ext/string/inflections'; true) rescue false)
|
|
2517
|
+
|
|
2518
|
+
describe 'PostgreSQL row-valued/composite types' do
|
|
2519
|
+
before(:all) do
|
|
2520
|
+
@db = POSTGRES_DB
|
|
2521
|
+
Sequel.extension :pg_array_ops, :pg_row_ops
|
|
2522
|
+
@db.extension :pg_array, :pg_row
|
|
2523
|
+
@ds = @db[:person]
|
|
2524
|
+
|
|
2525
|
+
@db.create_table!(:address) do
|
|
2526
|
+
String :street
|
|
2527
|
+
String :city
|
|
2528
|
+
String :zip
|
|
2529
|
+
end
|
|
2530
|
+
@db.create_table!(:person) do
|
|
2531
|
+
Integer :id
|
|
2532
|
+
address :address
|
|
2533
|
+
end
|
|
2534
|
+
@db.create_table!(:company) do
|
|
2535
|
+
Integer :id
|
|
2536
|
+
column :employees, 'person[]'
|
|
2537
|
+
end
|
|
2538
|
+
@db.register_row_type(:address)
|
|
2539
|
+
@db.register_row_type(:person)
|
|
2540
|
+
@db.register_row_type(:company)
|
|
2541
|
+
|
|
2542
|
+
@native = POSTGRES_DB.adapter_scheme == :postgres
|
|
2543
|
+
end
|
|
2544
|
+
after(:all) do
|
|
2545
|
+
@db.drop_table?(:company, :person, :address)
|
|
2546
|
+
@db.row_types.clear
|
|
2547
|
+
@db.reset_conversion_procs if @native
|
|
2548
|
+
end
|
|
2549
|
+
after do
|
|
2550
|
+
[:company, :person, :address].each{|t| @db[t].delete}
|
|
2551
|
+
end
|
|
2552
|
+
|
|
2553
|
+
specify 'insert and retrieve row types' do
|
|
2554
|
+
@ds.insert(:id=>1, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345']))
|
|
2555
|
+
@ds.count.should == 1
|
|
2556
|
+
if @native
|
|
2557
|
+
# Single row valued type
|
|
2558
|
+
rs = @ds.all
|
|
2559
|
+
v = rs.first[:address]
|
|
2560
|
+
v.should_not be_a_kind_of(Hash)
|
|
2561
|
+
v.to_hash.should be_a_kind_of(Hash)
|
|
2562
|
+
v.to_hash.should == {:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}
|
|
2563
|
+
@ds.delete
|
|
2564
|
+
@ds.insert(rs.first)
|
|
2565
|
+
@ds.all.should == rs
|
|
2566
|
+
|
|
2567
|
+
# Nested row value type
|
|
2568
|
+
p = @ds.get(:person)
|
|
2569
|
+
p[:id].should == 1
|
|
2570
|
+
p[:address].should == v
|
|
2571
|
+
end
|
|
2572
|
+
end
|
|
2573
|
+
|
|
2574
|
+
specify 'insert and retrieve arrays of row types' do
|
|
2575
|
+
@ds = @db[:company]
|
|
2576
|
+
@ds.insert(:id=>1, :employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])])]))
|
|
2577
|
+
@ds.count.should == 1
|
|
2578
|
+
if @native
|
|
2579
|
+
v = @ds.get(:company)
|
|
2580
|
+
v.should_not be_a_kind_of(Hash)
|
|
2581
|
+
v.to_hash.should be_a_kind_of(Hash)
|
|
2582
|
+
v[:id].should == 1
|
|
2583
|
+
employees = v[:employees]
|
|
2584
|
+
employees.should_not be_a_kind_of(Array)
|
|
2585
|
+
employees.to_a.should be_a_kind_of(Array)
|
|
2586
|
+
employees.should == [{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}]
|
|
2587
|
+
@ds.delete
|
|
2588
|
+
@ds.insert(v[:id], v[:employees])
|
|
2589
|
+
@ds.get(:company).should == v
|
|
2590
|
+
end
|
|
2591
|
+
end
|
|
2592
|
+
|
|
2593
|
+
specify 'use row types in bound variables' do
|
|
2594
|
+
@ds.call(:insert, {:address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])}, {:address=>:$address, :id=>1})
|
|
2595
|
+
@ds.get(:address).should == {:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}
|
|
2596
|
+
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345']))[:id].should == 1
|
|
2597
|
+
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12356'])).should == nil
|
|
2598
|
+
|
|
2599
|
+
@ds.delete
|
|
2600
|
+
@ds.call(:insert, {:address=>Sequel.pg_row([nil, nil, nil])}, {:address=>:$address, :id=>1})
|
|
2601
|
+
@ds.get(:address).should == {:street=>nil, :city=>nil, :zip=>nil}
|
|
2602
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2603
|
+
|
|
2604
|
+
specify 'use arrays of row types in bound variables' do
|
|
2605
|
+
@ds = @db[:company]
|
|
2606
|
+
@ds.call(:insert, {:employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])])])}, {:employees=>:$employees, :id=>1})
|
|
2607
|
+
@ds.get(:company).should == {:id=>1, :employees=>[{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}]}
|
|
2608
|
+
@ds.filter(:employees=>Sequel.cast(:$employees, 'person[]')).call(:first, :employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])])]))[:id].should == 1
|
|
2609
|
+
@ds.filter(:employees=>Sequel.cast(:$employees, 'person[]')).call(:first, :employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12356'])])])).should == nil
|
|
2610
|
+
|
|
2611
|
+
|
|
2612
|
+
@ds.delete
|
|
2613
|
+
@ds.call(:insert, {:employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row([nil, nil, nil])])])}, {:employees=>:$employees, :id=>1})
|
|
2614
|
+
@ds.get(:employees).should == [{:address=>{:city=>nil, :zip=>nil, :street=>nil}, :id=>1}]
|
|
2615
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2616
|
+
|
|
2617
|
+
specify 'operations/functions with pg_row_ops' do
|
|
2618
|
+
@ds.insert(:id=>1, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345']))
|
|
2619
|
+
@ds.get(Sequel.pg_row(:address)[:street]).should == '123 Sesame St'
|
|
2620
|
+
@ds.get(Sequel.pg_row(:address)[:city]).should == 'Somewhere'
|
|
2621
|
+
@ds.get(Sequel.pg_row(:address)[:zip]).should == '12345'
|
|
2622
|
+
|
|
2623
|
+
@ds = @db[:company]
|
|
2624
|
+
@ds.insert(:id=>1, :employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])])]))
|
|
2625
|
+
@ds.get(Sequel.pg_row(:company)[:id]).should == 1
|
|
2626
|
+
if @native
|
|
2627
|
+
@ds.get(Sequel.pg_row(:company)[:employees]).should == [{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}]
|
|
2628
|
+
@ds.get(Sequel.pg_row(:company)[:employees][1]).should == {:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}
|
|
2629
|
+
@ds.get(Sequel.pg_row(:company)[:employees][1][:address]).should == {:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}
|
|
2630
|
+
end
|
|
2631
|
+
@ds.get(Sequel.pg_row(:company)[:employees][1][:id]).should == 1
|
|
2632
|
+
@ds.get(Sequel.pg_row(:company)[:employees][1][:address][:street]).should == '123 Sesame St'
|
|
2633
|
+
@ds.get(Sequel.pg_row(:company)[:employees][1][:address][:city]).should == 'Somewhere'
|
|
2634
|
+
@ds.get(Sequel.pg_row(:company)[:employees][1][:address][:zip]).should == '12345'
|
|
2635
|
+
end
|
|
2636
|
+
|
|
2637
|
+
context "#splat and #*" do
|
|
2638
|
+
before(:all) do
|
|
2639
|
+
@db.create_table!(:a){Integer :a}
|
|
2640
|
+
@db.create_table!(:b){a :b; Integer :a}
|
|
2641
|
+
@db.register_row_type(:a)
|
|
2642
|
+
@db.register_row_type(:b)
|
|
2643
|
+
@db[:b].insert(:a=>1, :b=>@db.row_type(:a, [2]))
|
|
2644
|
+
end
|
|
2645
|
+
after(:all) do
|
|
2646
|
+
@db.drop_table?(:b, :a)
|
|
2647
|
+
end
|
|
2648
|
+
|
|
2649
|
+
specify "splat should reference the table type" do
|
|
2650
|
+
@db[:b].select(:a).first.should == {:a=>1}
|
|
2651
|
+
@db[:b].select(:b__a).first.should == {:a=>1}
|
|
2652
|
+
@db[:b].select(Sequel.pg_row(:b)[:a]).first.should == {:a=>2}
|
|
2653
|
+
@db[:b].select(Sequel.pg_row(:b).splat[:a]).first.should == {:a=>1}
|
|
2654
|
+
|
|
2655
|
+
if @native
|
|
2656
|
+
@db[:b].select(:b).first.should == {:b=>{:a=>2}}
|
|
2657
|
+
@db[:b].select(Sequel.pg_row(:b).splat).first.should == {:a=>1, :b=>{:a=>2}}
|
|
2658
|
+
@db[:b].select(Sequel.pg_row(:b).splat(:b)).first.should == {:b=>{:a=>1, :b=>{:a=>2}}}
|
|
2659
|
+
end
|
|
2660
|
+
end
|
|
2661
|
+
|
|
2662
|
+
specify "* should expand the table type into separate columns" do
|
|
2663
|
+
ds = @db[:b].select(Sequel.pg_row(:b).splat(:b)).from_self(:alias=>:t)
|
|
2664
|
+
if @native
|
|
2665
|
+
ds.first.should == {:b=>{:a=>1, :b=>{:a=>2}}}
|
|
2666
|
+
ds.select(Sequel.pg_row(:b).*).first.should == {:a=>1, :b=>{:a=>2}}
|
|
2667
|
+
ds.select(Sequel.pg_row(:b)[:b]).first.should == {:b=>{:a=>2}}
|
|
2668
|
+
ds.select(Sequel.pg_row(:t__b).*).first.should == {:a=>1, :b=>{:a=>2}}
|
|
2669
|
+
ds.select(Sequel.pg_row(:t__b)[:b]).first.should == {:b=>{:a=>2}}
|
|
2670
|
+
end
|
|
2671
|
+
ds.select(Sequel.pg_row(:b)[:a]).first.should == {:a=>1}
|
|
2672
|
+
ds.select(Sequel.pg_row(:t__b)[:a]).first.should == {:a=>1}
|
|
2673
|
+
end
|
|
2674
|
+
end
|
|
2675
|
+
|
|
2676
|
+
context "with models" do
|
|
2677
|
+
before(:all) do
|
|
2678
|
+
class Address < Sequel::Model(:address)
|
|
2679
|
+
plugin :pg_row
|
|
2680
|
+
end
|
|
2681
|
+
class Person < Sequel::Model(:person)
|
|
2682
|
+
plugin :pg_row
|
|
2683
|
+
end
|
|
2684
|
+
class Company < Sequel::Model(:company)
|
|
2685
|
+
plugin :pg_row
|
|
2686
|
+
end
|
|
2687
|
+
@a = Address.new(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345')
|
|
2688
|
+
@es = Sequel.pg_array([Person.new(:id=>1, :address=>@a)])
|
|
2689
|
+
end
|
|
2690
|
+
after(:all) do
|
|
2691
|
+
Object.send(:remove_const, :Address) rescue nil
|
|
2692
|
+
Object.send(:remove_const, :Person) rescue nil
|
|
2693
|
+
Object.send(:remove_const, :Company) rescue nil
|
|
2694
|
+
end
|
|
2695
|
+
|
|
2696
|
+
specify 'insert and retrieve row types as model objects' do
|
|
2697
|
+
@ds.insert(:id=>1, :address=>@a)
|
|
2698
|
+
@ds.count.should == 1
|
|
2699
|
+
if @native
|
|
2700
|
+
# Single row valued type
|
|
2701
|
+
rs = @ds.all
|
|
2702
|
+
v = rs.first[:address]
|
|
2703
|
+
v.should be_a_kind_of(Address)
|
|
2704
|
+
v.should == @a
|
|
2705
|
+
@ds.delete
|
|
2706
|
+
@ds.insert(rs.first)
|
|
2707
|
+
@ds.all.should == rs
|
|
2708
|
+
|
|
2709
|
+
# Nested row value type
|
|
2710
|
+
p = @ds.get(:person)
|
|
2711
|
+
p.should be_a_kind_of(Person)
|
|
2712
|
+
p.id.should == 1
|
|
2713
|
+
p.address.should be_a_kind_of(Address)
|
|
2714
|
+
p.address.should == @a
|
|
2715
|
+
end
|
|
2716
|
+
end
|
|
2717
|
+
|
|
2718
|
+
specify 'insert and retrieve arrays of row types as model objects' do
|
|
2719
|
+
@ds = @db[:company]
|
|
2720
|
+
@ds.insert(:id=>1, :employees=>@es)
|
|
2721
|
+
@ds.count.should == 1
|
|
2722
|
+
if @native
|
|
2723
|
+
v = @ds.get(:company)
|
|
2724
|
+
v.should be_a_kind_of(Company)
|
|
2725
|
+
v.id.should == 1
|
|
2726
|
+
employees = v[:employees]
|
|
2727
|
+
employees.should_not be_a_kind_of(Array)
|
|
2728
|
+
employees.to_a.should be_a_kind_of(Array)
|
|
2729
|
+
employees.should == @es
|
|
2730
|
+
@ds.delete
|
|
2731
|
+
@ds.insert(v.id, v.employees)
|
|
2732
|
+
@ds.get(:company).should == v
|
|
2733
|
+
end
|
|
2734
|
+
end
|
|
2735
|
+
|
|
2736
|
+
specify 'use model objects in bound variables' do
|
|
2737
|
+
@ds.call(:insert, {:address=>@a}, {:address=>:$address, :id=>1})
|
|
2738
|
+
@ds.get(:address).should == @a
|
|
2739
|
+
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>@a)[:id].should == 1
|
|
2740
|
+
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>Address.new(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12356')).should == nil
|
|
2741
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2742
|
+
|
|
2743
|
+
specify 'use arrays of model objects in bound variables' do
|
|
2744
|
+
@ds = @db[:company]
|
|
2745
|
+
@ds.call(:insert, {:employees=>@es}, {:employees=>:$employees, :id=>1})
|
|
2746
|
+
@ds.get(:company).should == Company.new(:id=>1, :employees=>@es)
|
|
2747
|
+
@ds.filter(:employees=>Sequel.cast(:$employees, 'person[]')).call(:first, :employees=>@es)[:id].should == 1
|
|
2748
|
+
@ds.filter(:employees=>Sequel.cast(:$employees, 'person[]')).call(:first, :employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12356'])])])).should == nil
|
|
2749
|
+
end if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG
|
|
2750
|
+
|
|
2751
|
+
specify 'model typecasting' do
|
|
2752
|
+
Person.plugin :pg_typecast_on_load, :address unless @native
|
|
2753
|
+
a = Address.new(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345')
|
|
2754
|
+
o = Person.create(:id=>1, :address=>['123 Sesame St', 'Somewhere', '12345'])
|
|
2755
|
+
o.address.should == a
|
|
2756
|
+
o = Person.create(:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'})
|
|
2757
|
+
o.address.should == a
|
|
2758
|
+
o = Person.create(:id=>1, :address=>a)
|
|
2759
|
+
o.address.should == a
|
|
2760
|
+
|
|
2761
|
+
Company.plugin :pg_typecast_on_load, :employees unless @native
|
|
2762
|
+
e = Person.new(:id=>1, :address=>a)
|
|
2763
|
+
unless @db.adapter_scheme == :jdbc
|
|
2764
|
+
o = Company.create(:id=>1, :employees=>[{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}])
|
|
2765
|
+
o.employees.should == [e]
|
|
2766
|
+
o = Company.create(:id=>1, :employees=>[e])
|
|
2767
|
+
o.employees.should == [e]
|
|
2768
|
+
end
|
|
2769
|
+
end
|
|
2770
|
+
end
|
|
1009
2771
|
end
|