sequel 5.20.0 → 5.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +398 -1922
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -7
- data/doc/advanced_associations.rdoc +4 -4
- data/doc/association_basics.rdoc +80 -16
- data/doc/cheat_sheet.rdoc +6 -5
- data/doc/code_order.rdoc +10 -12
- data/doc/dataset_filtering.rdoc +17 -2
- data/doc/fork_safety.rdoc +84 -0
- data/doc/migration.rdoc +11 -5
- data/doc/model_dataset_method_design.rdoc +1 -1
- data/doc/model_plugins.rdoc +1 -1
- data/doc/opening_databases.rdoc +10 -2
- data/doc/postgresql.rdoc +82 -3
- data/doc/querying.rdoc +4 -4
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/release_notes/5.22.0.txt +48 -0
- data/doc/release_notes/5.23.0.txt +56 -0
- data/doc/release_notes/5.24.0.txt +56 -0
- data/doc/release_notes/5.25.0.txt +32 -0
- data/doc/release_notes/5.26.0.txt +35 -0
- data/doc/release_notes/5.27.0.txt +21 -0
- data/doc/release_notes/5.28.0.txt +16 -0
- data/doc/release_notes/5.29.0.txt +22 -0
- data/doc/release_notes/5.30.0.txt +20 -0
- data/doc/release_notes/5.31.0.txt +148 -0
- data/doc/release_notes/5.32.0.txt +46 -0
- data/doc/release_notes/5.33.0.txt +24 -0
- data/doc/release_notes/5.34.0.txt +40 -0
- data/doc/release_notes/5.35.0.txt +56 -0
- data/doc/release_notes/5.36.0.txt +60 -0
- data/doc/release_notes/5.37.0.txt +30 -0
- data/doc/release_notes/5.38.0.txt +28 -0
- data/doc/release_notes/5.39.0.txt +19 -0
- data/doc/release_notes/5.40.0.txt +40 -0
- data/doc/release_notes/5.41.0.txt +25 -0
- data/doc/release_notes/5.42.0.txt +136 -0
- data/doc/release_notes/5.43.0.txt +98 -0
- data/doc/release_notes/5.44.0.txt +32 -0
- data/doc/release_notes/5.45.0.txt +34 -0
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/sharding.rdoc +2 -0
- data/doc/sql.rdoc +13 -1
- data/doc/testing.rdoc +20 -7
- data/doc/transactions.rdoc +0 -8
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +43 -35
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +6 -6
- data/lib/sequel/adapters/jdbc/postgresql.rb +11 -17
- data/lib/sequel/adapters/jdbc/sqlite.rb +29 -0
- data/lib/sequel/adapters/jdbc.rb +24 -6
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +2 -3
- data/lib/sequel/adapters/odbc.rb +8 -6
- data/lib/sequel/adapters/oracle.rb +5 -4
- data/lib/sequel/adapters/postgres.rb +15 -9
- data/lib/sequel/adapters/shared/access.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +66 -21
- data/lib/sequel/adapters/shared/mysql.rb +27 -10
- data/lib/sequel/adapters/shared/oracle.rb +29 -23
- data/lib/sequel/adapters/shared/postgres.rb +271 -32
- data/lib/sequel/adapters/shared/sqlanywhere.rb +9 -9
- data/lib/sequel/adapters/shared/sqlite.rb +161 -19
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +15 -2
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +4 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +4 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +12 -12
- data/lib/sequel/connection_pool/single.rb +1 -1
- data/lib/sequel/connection_pool/threaded.rb +2 -2
- data/lib/sequel/core.rb +333 -319
- data/lib/sequel/database/connecting.rb +3 -4
- data/lib/sequel/database/logging.rb +7 -1
- data/lib/sequel/database/misc.rb +31 -12
- data/lib/sequel/database/query.rb +3 -1
- data/lib/sequel/database/schema_generator.rb +53 -51
- data/lib/sequel/database/schema_methods.rb +38 -23
- data/lib/sequel/database/transactions.rb +17 -18
- data/lib/sequel/dataset/actions.rb +14 -9
- data/lib/sequel/dataset/features.rb +16 -0
- data/lib/sequel/dataset/misc.rb +2 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -7
- data/lib/sequel/dataset/prepared_statements.rb +2 -0
- data/lib/sequel/dataset/query.rb +26 -9
- data/lib/sequel/dataset/sql.rb +76 -25
- data/lib/sequel/dataset.rb +4 -2
- data/lib/sequel/deprecated.rb +3 -1
- data/lib/sequel/exceptions.rb +2 -0
- data/lib/sequel/extensions/_pretty_table.rb +1 -2
- data/lib/sequel/extensions/any_not_empty.rb +45 -0
- data/lib/sequel/extensions/async_thread_pool.rb +438 -0
- data/lib/sequel/extensions/blank.rb +8 -0
- data/lib/sequel/extensions/columns_introspection.rb +1 -2
- data/lib/sequel/extensions/connection_expiration.rb +2 -2
- data/lib/sequel/extensions/connection_validator.rb +2 -2
- data/lib/sequel/extensions/core_refinements.rb +2 -0
- data/lib/sequel/extensions/date_arithmetic.rb +36 -24
- data/lib/sequel/extensions/duplicate_columns_handler.rb +3 -1
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/exclude_or_null.rb +68 -0
- data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
- data/lib/sequel/extensions/index_caching.rb +9 -7
- data/lib/sequel/extensions/inflector.rb +9 -1
- data/lib/sequel/extensions/integer64.rb +2 -0
- data/lib/sequel/extensions/migration.rb +11 -3
- data/lib/sequel/extensions/named_timezones.rb +56 -8
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +5 -0
- data/lib/sequel/extensions/pg_array_ops.rb +14 -6
- data/lib/sequel/extensions/pg_enum.rb +11 -3
- data/lib/sequel/extensions/pg_extended_date_support.rb +2 -2
- data/lib/sequel/extensions/pg_hstore.rb +6 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +54 -2
- data/lib/sequel/extensions/pg_inet.rb +15 -5
- data/lib/sequel/extensions/pg_interval.rb +36 -8
- data/lib/sequel/extensions/pg_json.rb +387 -123
- data/lib/sequel/extensions/pg_json_ops.rb +238 -0
- data/lib/sequel/extensions/pg_loose_count.rb +3 -1
- data/lib/sequel/extensions/pg_range.rb +17 -9
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +4 -2
- data/lib/sequel/extensions/pg_row_ops.rb +24 -0
- data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +24 -7
- data/lib/sequel/extensions/server_block.rb +18 -7
- data/lib/sequel/extensions/sql_comments.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
- data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +9 -3
- data/lib/sequel/model/associations.rb +356 -117
- data/lib/sequel/model/base.rb +107 -68
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model/plugins.rb +9 -3
- data/lib/sequel/model.rb +3 -1
- data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
- data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
- data/lib/sequel/plugins/association_pks.rb +60 -18
- data/lib/sequel/plugins/association_proxies.rb +8 -2
- data/lib/sequel/plugins/async_thread_pool.rb +39 -0
- data/lib/sequel/plugins/auto_validations.rb +39 -5
- data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
- data/lib/sequel/plugins/blacklist_security.rb +1 -2
- data/lib/sequel/plugins/boolean_subsets.rb +4 -1
- data/lib/sequel/plugins/caching.rb +3 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +33 -28
- data/lib/sequel/plugins/column_encryption.rb +728 -0
- data/lib/sequel/plugins/composition.rb +7 -2
- data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
- data/lib/sequel/plugins/constraint_validations.rb +2 -1
- data/lib/sequel/plugins/csv_serializer.rb +28 -9
- data/lib/sequel/plugins/dataset_associations.rb +4 -1
- data/lib/sequel/plugins/dirty.rb +60 -22
- data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
- data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/json_serializer.rb +57 -35
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +108 -9
- data/lib/sequel/plugins/nested_attributes.rb +15 -3
- data/lib/sequel/plugins/pg_array_associations.rb +58 -41
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +91 -30
- data/lib/sequel/plugins/prepared_statements.rb +15 -12
- data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
- data/lib/sequel/plugins/rcte_tree.rb +43 -35
- data/lib/sequel/plugins/serialization.rb +8 -3
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +11 -5
- data/lib/sequel/plugins/single_table_inheritance.rb +22 -15
- data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
- data/lib/sequel/plugins/static_cache.rb +9 -4
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/string_stripper.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +2 -0
- data/lib/sequel/plugins/throw_failures.rb +1 -1
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/tree.rb +9 -4
- data/lib/sequel/plugins/typecast_on_load.rb +3 -2
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validation_class_methods.rb +5 -1
- data/lib/sequel/plugins/validation_helpers.rb +18 -11
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +20 -5
- data/lib/sequel/timezones.rb +63 -17
- data/lib/sequel/version.rb +1 -1
- metadata +113 -381
- data/Rakefile +0 -151
- data/doc/release_notes/4.0.0.txt +0 -262
- data/doc/release_notes/4.1.0.txt +0 -85
- data/doc/release_notes/4.10.0.txt +0 -226
- data/doc/release_notes/4.11.0.txt +0 -147
- data/doc/release_notes/4.12.0.txt +0 -105
- data/doc/release_notes/4.13.0.txt +0 -169
- data/doc/release_notes/4.14.0.txt +0 -68
- data/doc/release_notes/4.15.0.txt +0 -56
- data/doc/release_notes/4.16.0.txt +0 -36
- data/doc/release_notes/4.17.0.txt +0 -38
- data/doc/release_notes/4.18.0.txt +0 -36
- data/doc/release_notes/4.19.0.txt +0 -45
- data/doc/release_notes/4.2.0.txt +0 -129
- data/doc/release_notes/4.20.0.txt +0 -79
- data/doc/release_notes/4.21.0.txt +0 -94
- data/doc/release_notes/4.22.0.txt +0 -72
- data/doc/release_notes/4.23.0.txt +0 -65
- data/doc/release_notes/4.24.0.txt +0 -99
- data/doc/release_notes/4.25.0.txt +0 -181
- data/doc/release_notes/4.26.0.txt +0 -44
- data/doc/release_notes/4.27.0.txt +0 -78
- data/doc/release_notes/4.28.0.txt +0 -57
- data/doc/release_notes/4.29.0.txt +0 -41
- data/doc/release_notes/4.3.0.txt +0 -40
- data/doc/release_notes/4.30.0.txt +0 -37
- data/doc/release_notes/4.31.0.txt +0 -57
- data/doc/release_notes/4.32.0.txt +0 -132
- data/doc/release_notes/4.33.0.txt +0 -88
- data/doc/release_notes/4.34.0.txt +0 -86
- data/doc/release_notes/4.35.0.txt +0 -130
- data/doc/release_notes/4.36.0.txt +0 -116
- data/doc/release_notes/4.37.0.txt +0 -50
- data/doc/release_notes/4.38.0.txt +0 -67
- data/doc/release_notes/4.39.0.txt +0 -127
- data/doc/release_notes/4.4.0.txt +0 -92
- data/doc/release_notes/4.40.0.txt +0 -179
- data/doc/release_notes/4.41.0.txt +0 -77
- data/doc/release_notes/4.42.0.txt +0 -221
- data/doc/release_notes/4.43.0.txt +0 -87
- data/doc/release_notes/4.44.0.txt +0 -125
- data/doc/release_notes/4.45.0.txt +0 -370
- data/doc/release_notes/4.46.0.txt +0 -404
- data/doc/release_notes/4.47.0.txt +0 -56
- data/doc/release_notes/4.48.0.txt +0 -293
- data/doc/release_notes/4.49.0.txt +0 -222
- data/doc/release_notes/4.5.0.txt +0 -34
- data/doc/release_notes/4.6.0.txt +0 -30
- data/doc/release_notes/4.7.0.txt +0 -103
- data/doc/release_notes/4.8.0.txt +0 -175
- data/doc/release_notes/4.9.0.txt +0 -190
- data/spec/adapter_spec.rb +0 -4
- data/spec/adapters/db2_spec.rb +0 -170
- data/spec/adapters/mssql_spec.rb +0 -804
- data/spec/adapters/mysql_spec.rb +0 -1065
- data/spec/adapters/oracle_spec.rb +0 -371
- data/spec/adapters/postgres_spec.rb +0 -4125
- data/spec/adapters/spec_helper.rb +0 -44
- data/spec/adapters/sqlanywhere_spec.rb +0 -97
- data/spec/adapters/sqlite_spec.rb +0 -652
- data/spec/bin_spec.rb +0 -278
- data/spec/core/connection_pool_spec.rb +0 -1250
- data/spec/core/database_spec.rb +0 -2865
- data/spec/core/dataset_spec.rb +0 -5515
- data/spec/core/deprecated_spec.rb +0 -70
- data/spec/core/expression_filters_spec.rb +0 -1455
- data/spec/core/mock_adapter_spec.rb +0 -722
- data/spec/core/object_graph_spec.rb +0 -336
- data/spec/core/placeholder_literalizer_spec.rb +0 -166
- data/spec/core/schema_generator_spec.rb +0 -214
- data/spec/core/schema_spec.rb +0 -1826
- data/spec/core/spec_helper.rb +0 -24
- data/spec/core/version_spec.rb +0 -14
- data/spec/core_extensions_spec.rb +0 -763
- data/spec/core_model_spec.rb +0 -2
- data/spec/core_spec.rb +0 -1
- data/spec/deprecation_helper.rb +0 -30
- data/spec/extensions/accessed_columns_spec.rb +0 -51
- data/spec/extensions/active_model_spec.rb +0 -99
- data/spec/extensions/after_initialize_spec.rb +0 -28
- data/spec/extensions/arbitrary_servers_spec.rb +0 -109
- data/spec/extensions/association_dependencies_spec.rb +0 -125
- data/spec/extensions/association_pks_spec.rb +0 -423
- data/spec/extensions/association_proxies_spec.rb +0 -100
- data/spec/extensions/auto_literal_strings_spec.rb +0 -205
- data/spec/extensions/auto_validations_spec.rb +0 -229
- data/spec/extensions/blacklist_security_spec.rb +0 -95
- data/spec/extensions/blank_spec.rb +0 -69
- data/spec/extensions/boolean_readers_spec.rb +0 -93
- data/spec/extensions/boolean_subsets_spec.rb +0 -47
- data/spec/extensions/caching_spec.rb +0 -273
- data/spec/extensions/caller_logging_spec.rb +0 -52
- data/spec/extensions/class_table_inheritance_spec.rb +0 -750
- data/spec/extensions/column_conflicts_spec.rb +0 -75
- data/spec/extensions/column_select_spec.rb +0 -129
- data/spec/extensions/columns_introspection_spec.rb +0 -90
- data/spec/extensions/columns_updated_spec.rb +0 -35
- data/spec/extensions/composition_spec.rb +0 -248
- data/spec/extensions/connection_expiration_spec.rb +0 -151
- data/spec/extensions/connection_validator_spec.rb +0 -144
- data/spec/extensions/constant_sql_override_spec.rb +0 -24
- data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
- data/spec/extensions/constraint_validations_spec.rb +0 -439
- data/spec/extensions/core_refinements_spec.rb +0 -528
- data/spec/extensions/csv_serializer_spec.rb +0 -183
- data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
- data/spec/extensions/dataset_associations_spec.rb +0 -365
- data/spec/extensions/dataset_source_alias_spec.rb +0 -51
- data/spec/extensions/date_arithmetic_spec.rb +0 -181
- data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
- data/spec/extensions/def_dataset_method_spec.rb +0 -100
- data/spec/extensions/defaults_setter_spec.rb +0 -150
- data/spec/extensions/delay_add_association_spec.rb +0 -73
- data/spec/extensions/dirty_spec.rb +0 -189
- data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
- data/spec/extensions/eager_each_spec.rb +0 -62
- data/spec/extensions/eager_graph_eager_spec.rb +0 -100
- data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
- data/spec/extensions/error_splitter_spec.rb +0 -18
- data/spec/extensions/error_sql_spec.rb +0 -20
- data/spec/extensions/escaped_like_spec.rb +0 -40
- data/spec/extensions/eval_inspect_spec.rb +0 -81
- data/spec/extensions/finder_spec.rb +0 -260
- data/spec/extensions/force_encoding_spec.rb +0 -126
- data/spec/extensions/freeze_datasets_spec.rb +0 -31
- data/spec/extensions/graph_each_spec.rb +0 -113
- data/spec/extensions/hook_class_methods_spec.rb +0 -402
- data/spec/extensions/identifier_mangling_spec.rb +0 -201
- data/spec/extensions/implicit_subquery_spec.rb +0 -58
- data/spec/extensions/index_caching_spec.rb +0 -66
- data/spec/extensions/inflector_spec.rb +0 -183
- data/spec/extensions/input_transformer_spec.rb +0 -69
- data/spec/extensions/insert_returning_select_spec.rb +0 -72
- data/spec/extensions/instance_filters_spec.rb +0 -79
- data/spec/extensions/instance_hooks_spec.rb +0 -246
- data/spec/extensions/integer64_spec.rb +0 -22
- data/spec/extensions/inverted_subsets_spec.rb +0 -33
- data/spec/extensions/json_serializer_spec.rb +0 -336
- data/spec/extensions/lazy_attributes_spec.rb +0 -183
- data/spec/extensions/list_spec.rb +0 -291
- data/spec/extensions/looser_typecasting_spec.rb +0 -43
- data/spec/extensions/many_through_many_spec.rb +0 -2177
- data/spec/extensions/migration_spec.rb +0 -864
- data/spec/extensions/modification_detection_spec.rb +0 -93
- data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -92
- data/spec/extensions/named_timezones_spec.rb +0 -111
- data/spec/extensions/nested_attributes_spec.rb +0 -767
- data/spec/extensions/null_dataset_spec.rb +0 -85
- data/spec/extensions/optimistic_locking_spec.rb +0 -127
- data/spec/extensions/pagination_spec.rb +0 -116
- data/spec/extensions/pg_array_associations_spec.rb +0 -802
- data/spec/extensions/pg_array_ops_spec.rb +0 -144
- data/spec/extensions/pg_array_spec.rb +0 -398
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -172
- data/spec/extensions/pg_enum_spec.rb +0 -118
- data/spec/extensions/pg_extended_date_support_spec.rb +0 -126
- data/spec/extensions/pg_hstore_ops_spec.rb +0 -238
- data/spec/extensions/pg_hstore_spec.rb +0 -219
- data/spec/extensions/pg_inet_ops_spec.rb +0 -102
- data/spec/extensions/pg_inet_spec.rb +0 -72
- data/spec/extensions/pg_interval_spec.rb +0 -103
- data/spec/extensions/pg_json_ops_spec.rb +0 -289
- data/spec/extensions/pg_json_spec.rb +0 -262
- data/spec/extensions/pg_loose_count_spec.rb +0 -23
- data/spec/extensions/pg_range_ops_spec.rb +0 -60
- data/spec/extensions/pg_range_spec.rb +0 -519
- data/spec/extensions/pg_row_ops_spec.rb +0 -61
- data/spec/extensions/pg_row_plugin_spec.rb +0 -60
- data/spec/extensions/pg_row_spec.rb +0 -363
- data/spec/extensions/pg_static_cache_updater_spec.rb +0 -93
- data/spec/extensions/pg_timestamptz_spec.rb +0 -17
- data/spec/extensions/prepared_statements_safe_spec.rb +0 -66
- data/spec/extensions/prepared_statements_spec.rb +0 -177
- data/spec/extensions/pretty_table_spec.rb +0 -123
- data/spec/extensions/query_spec.rb +0 -94
- data/spec/extensions/rcte_tree_spec.rb +0 -381
- data/spec/extensions/round_timestamps_spec.rb +0 -39
- data/spec/extensions/s_spec.rb +0 -60
- data/spec/extensions/schema_caching_spec.rb +0 -64
- data/spec/extensions/schema_dumper_spec.rb +0 -870
- data/spec/extensions/select_remove_spec.rb +0 -38
- data/spec/extensions/sequel_4_dataset_methods_spec.rb +0 -121
- data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
- data/spec/extensions/serialization_spec.rb +0 -365
- data/spec/extensions/server_block_spec.rb +0 -97
- data/spec/extensions/server_logging_spec.rb +0 -45
- data/spec/extensions/sharding_spec.rb +0 -189
- data/spec/extensions/shared_caching_spec.rb +0 -151
- data/spec/extensions/single_table_inheritance_spec.rb +0 -347
- data/spec/extensions/singular_table_names_spec.rb +0 -22
- data/spec/extensions/skip_create_refresh_spec.rb +0 -18
- data/spec/extensions/spec_helper.rb +0 -63
- data/spec/extensions/split_array_nil_spec.rb +0 -24
- data/spec/extensions/split_values_spec.rb +0 -57
- data/spec/extensions/sql_comments_spec.rb +0 -33
- data/spec/extensions/sql_expr_spec.rb +0 -59
- data/spec/extensions/static_cache_spec.rb +0 -471
- data/spec/extensions/string_agg_spec.rb +0 -90
- data/spec/extensions/string_date_time_spec.rb +0 -95
- data/spec/extensions/string_stripper_spec.rb +0 -68
- data/spec/extensions/subclasses_spec.rb +0 -79
- data/spec/extensions/subset_conditions_spec.rb +0 -38
- data/spec/extensions/symbol_aref_refinement_spec.rb +0 -28
- data/spec/extensions/symbol_as_refinement_spec.rb +0 -21
- data/spec/extensions/synchronize_sql_spec.rb +0 -124
- data/spec/extensions/table_select_spec.rb +0 -83
- data/spec/extensions/tactical_eager_loading_spec.rb +0 -402
- data/spec/extensions/thread_local_timezones_spec.rb +0 -67
- data/spec/extensions/throw_failures_spec.rb +0 -74
- data/spec/extensions/timestamps_spec.rb +0 -209
- data/spec/extensions/to_dot_spec.rb +0 -153
- data/spec/extensions/touch_spec.rb +0 -226
- data/spec/extensions/tree_spec.rb +0 -334
- data/spec/extensions/typecast_on_load_spec.rb +0 -86
- data/spec/extensions/unlimited_update_spec.rb +0 -21
- data/spec/extensions/update_or_create_spec.rb +0 -83
- data/spec/extensions/update_primary_key_spec.rb +0 -105
- data/spec/extensions/update_refresh_spec.rb +0 -59
- data/spec/extensions/uuid_spec.rb +0 -101
- data/spec/extensions/validate_associated_spec.rb +0 -52
- data/spec/extensions/validation_class_methods_spec.rb +0 -1040
- data/spec/extensions/validation_contexts_spec.rb +0 -31
- data/spec/extensions/validation_helpers_spec.rb +0 -525
- data/spec/extensions/whitelist_security_spec.rb +0 -157
- data/spec/extensions/xml_serializer_spec.rb +0 -213
- data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
- data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
- data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
- data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
- data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/double_migration/001_create_sessions.rb +0 -9
- data/spec/files/double_migration/002_create_nodes.rb +0 -19
- data/spec/files/double_migration/003_3_create_users.rb +0 -4
- data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
- data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
- data/spec/files/empty_migration/001_create_sessions.rb +0 -9
- data/spec/files/empty_migration/002_create_nodes.rb +0 -0
- data/spec/files/empty_migration/003_3_create_users.rb +0 -4
- data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
- data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
- data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
- data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
- data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/reversible_migrations/001_reversible.rb +0 -5
- data/spec/files/reversible_migrations/002_reversible.rb +0 -5
- data/spec/files/reversible_migrations/003_reversible.rb +0 -5
- data/spec/files/reversible_migrations/004_reversible.rb +0 -5
- data/spec/files/reversible_migrations/005_reversible.rb +0 -10
- data/spec/files/reversible_migrations/006_reversible.rb +0 -10
- data/spec/files/reversible_migrations/007_reversible.rb +0 -10
- data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
- data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
- data/spec/guards_helper.rb +0 -59
- data/spec/integration/associations_test.rb +0 -2597
- data/spec/integration/database_test.rb +0 -113
- data/spec/integration/dataset_test.rb +0 -1981
- data/spec/integration/eager_loader_test.rb +0 -687
- data/spec/integration/migrator_test.rb +0 -262
- data/spec/integration/model_test.rb +0 -203
- data/spec/integration/plugin_test.rb +0 -2396
- data/spec/integration/prepared_statement_test.rb +0 -405
- data/spec/integration/schema_test.rb +0 -889
- data/spec/integration/spec_helper.rb +0 -65
- data/spec/integration/timezone_test.rb +0 -86
- data/spec/integration/transaction_test.rb +0 -603
- data/spec/integration/type_test.rb +0 -127
- data/spec/model/association_reflection_spec.rb +0 -803
- data/spec/model/associations_spec.rb +0 -4738
- data/spec/model/base_spec.rb +0 -875
- data/spec/model/class_dataset_methods_spec.rb +0 -146
- data/spec/model/dataset_methods_spec.rb +0 -198
- data/spec/model/eager_loading_spec.rb +0 -2377
- data/spec/model/hooks_spec.rb +0 -370
- data/spec/model/inflector_spec.rb +0 -26
- data/spec/model/model_spec.rb +0 -956
- data/spec/model/plugins_spec.rb +0 -429
- data/spec/model/record_spec.rb +0 -2118
- data/spec/model/spec_helper.rb +0 -46
- data/spec/model/validations_spec.rb +0 -220
- data/spec/model_no_assoc_spec.rb +0 -1
- data/spec/model_spec.rb +0 -1
- data/spec/plugin_spec.rb +0 -1
- data/spec/sequel_coverage.rb +0 -15
- data/spec/sequel_warning.rb +0 -4
- data/spec/spec_config.rb +0 -12
|
@@ -1,4125 +0,0 @@
|
|
|
1
|
-
SEQUEL_ADAPTER_TEST = :postgres
|
|
2
|
-
|
|
3
|
-
require_relative 'spec_helper'
|
|
4
|
-
|
|
5
|
-
uses_pg = Sequel::Postgres::USES_PG if DB.adapter_scheme == :postgres
|
|
6
|
-
uses_pg_or_jdbc = uses_pg || DB.adapter_scheme == :jdbc
|
|
7
|
-
|
|
8
|
-
DB.extension :pg_array, :pg_range, :pg_row, :pg_inet, :pg_json, :pg_enum
|
|
9
|
-
begin
|
|
10
|
-
DB.extension :pg_interval
|
|
11
|
-
rescue LoadError
|
|
12
|
-
end
|
|
13
|
-
DB.extension :pg_hstore if DB.type_supported?('hstore')
|
|
14
|
-
|
|
15
|
-
describe "PostgreSQL", '#create_table' do
|
|
16
|
-
before do
|
|
17
|
-
@db = DB
|
|
18
|
-
@db.test_connection
|
|
19
|
-
end
|
|
20
|
-
after do
|
|
21
|
-
@db.drop_table?(:tmp_dolls, :unlogged_dolls)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it "should create a temporary table" do
|
|
25
|
-
@db.create_table(:tmp_dolls, :temp => true){text :name}
|
|
26
|
-
@db.table_exists?(:tmp_dolls).must_equal true
|
|
27
|
-
@db.disconnect
|
|
28
|
-
@db.table_exists?(:tmp_dolls).must_equal false
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it "temporary table should support :on_commit option" do
|
|
32
|
-
@db.drop_table?(:some_table)
|
|
33
|
-
@db.transaction do
|
|
34
|
-
@db.create_table(:some_table, :temp => true, :on_commit => :drop){text :name}
|
|
35
|
-
end
|
|
36
|
-
@db.table_exists?(:some_table).must_equal false
|
|
37
|
-
|
|
38
|
-
@db.transaction do
|
|
39
|
-
@db.create_table(:some_table, :temp => true, :on_commit => :delete_rows){text :name}
|
|
40
|
-
@db[:some_table].insert('a')
|
|
41
|
-
end
|
|
42
|
-
@db.table_exists?(:some_table).must_equal true
|
|
43
|
-
@db[:some_table].empty?.must_equal true
|
|
44
|
-
|
|
45
|
-
@db.drop_table(:some_table)
|
|
46
|
-
@db.transaction do
|
|
47
|
-
@db.create_table(:some_table, :temp => true, :on_commit => :preserve_rows){text :name}
|
|
48
|
-
@db[:some_table].insert('a')
|
|
49
|
-
end
|
|
50
|
-
@db.table_exists?(:some_table).must_equal true
|
|
51
|
-
@db[:some_table].count.must_equal 1
|
|
52
|
-
@db.drop_table(:some_table)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it "temporary table should accept :on_commit with :as option" do
|
|
56
|
-
@db.drop_table?(:some_table)
|
|
57
|
-
@db.transaction do
|
|
58
|
-
@db.create_table(:some_table, :temp => true, :on_commit => :drop, :as => 'select 1')
|
|
59
|
-
end
|
|
60
|
-
@db.table_exists?(:some_table).must_equal false
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it ":on_commit should raise error if not used on a temporary table" do
|
|
64
|
-
proc{@db.create_table(:some_table, :on_commit => :drop)}.must_raise(Sequel::Error)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it ":on_commit should raise error if given unsupported value" do
|
|
68
|
-
proc{@db.create_table(:some_table, :temp => true, :on_commit => :unsupported){text :name}}.must_raise(Sequel::Error)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it "should create an unlogged table" do
|
|
72
|
-
@db.create_table(:unlogged_dolls, :unlogged => true){text :name}
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "should create a table inheriting from another table" do
|
|
76
|
-
@db.create_table(:unlogged_dolls){text :name}
|
|
77
|
-
@db.create_table(:tmp_dolls, :inherits=>:unlogged_dolls){}
|
|
78
|
-
@db[:tmp_dolls].insert('a')
|
|
79
|
-
@db[:unlogged_dolls].all.must_equal [{:name=>'a'}]
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it "should create a table inheriting from multiple tables" do
|
|
83
|
-
begin
|
|
84
|
-
@db.create_table(:unlogged_dolls){text :name}
|
|
85
|
-
@db.create_table(:tmp_dolls){text :bar}
|
|
86
|
-
@db.create_table!(:items, :inherits=>[:unlogged_dolls, :tmp_dolls]){text :foo}
|
|
87
|
-
@db[:items].insert(:name=>'a', :bar=>'b', :foo=>'c')
|
|
88
|
-
@db[:unlogged_dolls].all.must_equal [{:name=>'a'}]
|
|
89
|
-
@db[:tmp_dolls].all.must_equal [{:bar=>'b'}]
|
|
90
|
-
@db[:items].all.must_equal [{:name=>'a', :bar=>'b', :foo=>'c'}]
|
|
91
|
-
ensure
|
|
92
|
-
@db.drop_table?(:items)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it "should have #check_constraints method for getting check constraints" do
|
|
97
|
-
@db.create_table(:tmp_dolls) do
|
|
98
|
-
Integer :i
|
|
99
|
-
Integer :j
|
|
100
|
-
constraint(:ic, Sequel[:i] > 2)
|
|
101
|
-
constraint(:jc, Sequel[:j] > 2)
|
|
102
|
-
constraint(:ijc, Sequel[:i] - Sequel[:j] > 2)
|
|
103
|
-
end
|
|
104
|
-
@db.check_constraints(:tmp_dolls).must_equal(:ic=>{:definition=>"CHECK ((i > 2))", :columns=>[:i]}, :jc=>{:definition=>"CHECK ((j > 2))", :columns=>[:j]}, :ijc=>{:definition=>"CHECK (((i - j) > 2))", :columns=>[:i, :j]})
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
it "should have #check_constraints return check constraints where columns are unknown" do
|
|
108
|
-
begin
|
|
109
|
-
@db.create_table(:tmp_dolls) do
|
|
110
|
-
Integer :i
|
|
111
|
-
Integer :j
|
|
112
|
-
end
|
|
113
|
-
@db.run "CREATE OR REPLACE FUNCTION valid_tmp_dolls(t1 tmp_dolls) RETURNS boolean AS 'SELECT false' LANGUAGE SQL;"
|
|
114
|
-
@db.alter_table(:tmp_dolls) do
|
|
115
|
-
add_constraint(:valid_tmp_dolls, Sequel.function(:valid_tmp_dolls, :tmp_dolls))
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
@db.check_constraints(:tmp_dolls).must_equal(:valid_tmp_dolls=>{:definition=>"CHECK (valid_tmp_dolls(tmp_dolls.*))", :columns=>[]})
|
|
119
|
-
ensure
|
|
120
|
-
@db.run "ALTER TABLE tmp_dolls DROP CONSTRAINT IF EXISTS valid_tmp_dolls"
|
|
121
|
-
@db.run "DROP FUNCTION IF EXISTS valid_tmp_dolls(tmp_dolls)"
|
|
122
|
-
end
|
|
123
|
-
end if DB.server_version >= 90000
|
|
124
|
-
|
|
125
|
-
it "should not allow to pass both :temp and :unlogged" do
|
|
126
|
-
proc do
|
|
127
|
-
@db.create_table(:temp_unlogged_dolls, :temp => true, :unlogged => true){text :name}
|
|
128
|
-
end.must_raise(Sequel::Error, "can't provide both :temp and :unlogged to create_table")
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
it "should support :if_exists option to drop_column" do
|
|
132
|
-
@db.create_table(:tmp_dolls){Integer :a; Integer :b}
|
|
133
|
-
2.times do
|
|
134
|
-
@db.drop_column :tmp_dolls, :b, :if_exists=>true
|
|
135
|
-
@db[:tmp_dolls].columns.must_equal [:a]
|
|
136
|
-
end
|
|
137
|
-
end if DB.server_version >= 90000
|
|
138
|
-
|
|
139
|
-
it "should support primary_key with :type=>:serial or :type=>:bigserial" do
|
|
140
|
-
[:serial, :bigserial, 'serial', 'bigserial'].each do |type|
|
|
141
|
-
@db.create_table!(:tmp_dolls){primary_key :id, :type=>type}
|
|
142
|
-
@db[:tmp_dolls].insert
|
|
143
|
-
@db[:tmp_dolls].get(:id).must_equal 1
|
|
144
|
-
end
|
|
145
|
-
end if DB.server_version >= 100002
|
|
146
|
-
|
|
147
|
-
it "should support primary_key with :serial=>true" do
|
|
148
|
-
@db.create_table!(:tmp_dolls){primary_key :id, :serial=>true}
|
|
149
|
-
@db[:tmp_dolls].insert
|
|
150
|
-
@db[:tmp_dolls].get(:id).must_equal 1
|
|
151
|
-
end if DB.server_version >= 100002
|
|
152
|
-
|
|
153
|
-
it "should support creating identity columns on non-primary key tables" do
|
|
154
|
-
@db.create_table(:tmp_dolls){Integer :a, :identity=>true}
|
|
155
|
-
2.times do
|
|
156
|
-
@db[:tmp_dolls].insert
|
|
157
|
-
end
|
|
158
|
-
@db[:tmp_dolls].select_order_map(:a).must_equal [1, 2]
|
|
159
|
-
@db[:tmp_dolls].insert(:a=>2)
|
|
160
|
-
@db[:tmp_dolls].select_order_map(:a).must_equal [1, 2, 2]
|
|
161
|
-
@db[:tmp_dolls].insert(:a=>4)
|
|
162
|
-
@db[:tmp_dolls].select_order_map(:a).must_equal [1, 2, 2, 4]
|
|
163
|
-
@db[:tmp_dolls].overriding_user_value.insert(:a=>5)
|
|
164
|
-
@db[:tmp_dolls].select_order_map(:a).must_equal [1, 2, 2, 3, 4]
|
|
165
|
-
end if DB.server_version >= 100002
|
|
166
|
-
|
|
167
|
-
it "should support creating identity columns generated always" do
|
|
168
|
-
@db.create_table(:tmp_dolls){primary_key :id, :identity=>:always}
|
|
169
|
-
2.times do
|
|
170
|
-
@db[:tmp_dolls].insert
|
|
171
|
-
end
|
|
172
|
-
@db[:tmp_dolls].select_order_map(:id).must_equal [1, 2]
|
|
173
|
-
proc{@db[:tmp_dolls].insert(:id=>2)}.must_raise Sequel::DatabaseError
|
|
174
|
-
@db[:tmp_dolls].overriding_system_value.insert(:id=>4)
|
|
175
|
-
@db[:tmp_dolls].select_order_map(:id).must_equal [1, 2, 4]
|
|
176
|
-
@db[:tmp_dolls].insert
|
|
177
|
-
@db[:tmp_dolls].select_order_map(:id).must_equal [1, 2, 3, 4]
|
|
178
|
-
end if DB.server_version >= 100002
|
|
179
|
-
|
|
180
|
-
it "should support converting serial columns to identity columns" do
|
|
181
|
-
@db.create_table(:tmp_dolls){primary_key :id, :identity=>false, :serial=>true}
|
|
182
|
-
sch = @db.schema(:tmp_dolls)[0][1]
|
|
183
|
-
sch[:default].must_match(/nextval/)
|
|
184
|
-
sch[:auto_increment].must_equal true
|
|
185
|
-
|
|
186
|
-
2.times do
|
|
187
|
-
@db[:tmp_dolls].insert
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
@db.convert_serial_to_identity(:tmp_dolls)
|
|
191
|
-
sch = @db.schema(:tmp_dolls)[0][1]
|
|
192
|
-
sch[:default].must_be_nil
|
|
193
|
-
sch[:auto_increment].must_equal true
|
|
194
|
-
|
|
195
|
-
@db[:tmp_dolls].insert
|
|
196
|
-
@db[:tmp_dolls].insert(5)
|
|
197
|
-
@db[:tmp_dolls].select_order_map(:id).must_equal [1, 2, 3, 5]
|
|
198
|
-
|
|
199
|
-
# Make sure it doesn't break if already converted
|
|
200
|
-
@db.convert_serial_to_identity(:tmp_dolls)
|
|
201
|
-
end if DB.server_version >= 100002 && DB.get{current_setting('is_superuser')} == 'on'
|
|
202
|
-
|
|
203
|
-
it "should support converting serial columns to identity columns when using the :column option" do
|
|
204
|
-
@db.create_table(:tmp_dolls){Integer :i, :primary_key=>true; serial :id}
|
|
205
|
-
sch = @db.schema(:tmp_dolls)[1][1]
|
|
206
|
-
sch[:default].must_match(/nextval/)
|
|
207
|
-
|
|
208
|
-
2.times do |i|
|
|
209
|
-
@db[:tmp_dolls].insert(:i=>-i)
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
# Automatic conversion should not work
|
|
213
|
-
proc{@db.convert_serial_to_identity(:tmp_dolls)}.must_raise Sequel::Error
|
|
214
|
-
|
|
215
|
-
# Conversion of type without related sequence should not work
|
|
216
|
-
proc{@db.convert_serial_to_identity(:tmp_dolls, :column=>:i)}.must_raise Sequel::Error
|
|
217
|
-
|
|
218
|
-
@db.convert_serial_to_identity(:tmp_dolls, :column=>:id)
|
|
219
|
-
sch = @db.schema(:tmp_dolls)[1][1]
|
|
220
|
-
sch[:default].must_be_nil
|
|
221
|
-
|
|
222
|
-
@db[:tmp_dolls].insert(:i=>200)
|
|
223
|
-
@db[:tmp_dolls].insert(:i=>300, :id=>5)
|
|
224
|
-
@db[:tmp_dolls].select_order_map(:id).must_equal [1, 2, 3, 5]
|
|
225
|
-
|
|
226
|
-
# Make sure it doesn't break if already converted
|
|
227
|
-
@db.convert_serial_to_identity(:tmp_dolls, :column=>:id)
|
|
228
|
-
end if DB.server_version >= 100002 && DB.get{current_setting('is_superuser')} == 'on'
|
|
229
|
-
|
|
230
|
-
it "should support pg_loose_count extension" do
|
|
231
|
-
@db.extension :pg_loose_count
|
|
232
|
-
@db.create_table(:tmp_dolls){text :name}
|
|
233
|
-
@db.loose_count(:tmp_dolls).must_be_kind_of(Integer)
|
|
234
|
-
@db.loose_count(:tmp_dolls).must_equal 0
|
|
235
|
-
@db.loose_count(Sequel[:public][:tmp_dolls]).must_equal 0
|
|
236
|
-
@db[:tmp_dolls].insert('a')
|
|
237
|
-
@db << 'VACUUM ANALYZE tmp_dolls'
|
|
238
|
-
@db.loose_count(:tmp_dolls).must_equal 1
|
|
239
|
-
@db.loose_count(Sequel[:public][:tmp_dolls]).must_equal 1
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
describe "PostgreSQL views" do
|
|
244
|
-
before do
|
|
245
|
-
@db = DB
|
|
246
|
-
@db.drop_table?(:items, :cascade=>true)
|
|
247
|
-
@db.create_table(:items){Integer :number}
|
|
248
|
-
@db[:items].insert(10)
|
|
249
|
-
@db[:items].insert(20)
|
|
250
|
-
end
|
|
251
|
-
after do
|
|
252
|
-
@opts ||={}
|
|
253
|
-
@db.drop_view(:items_view, @opts.merge(:if_exists=>true, :cascade=>true)) rescue nil
|
|
254
|
-
@db.drop_table?(:items)
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
it "should support temporary views" do
|
|
258
|
-
@db.create_view(:items_view, @db[:items].where(:number=>10), :temp=>true)
|
|
259
|
-
@db[:items_view].map(:number).must_equal [10]
|
|
260
|
-
@db.create_or_replace_view(:items_view, @db[:items].where(:number=>20), :temp=>true)
|
|
261
|
-
@db[:items_view].map(:number).must_equal [20]
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
it "should support recursive views" do
|
|
265
|
-
@db.create_view(:items_view, @db[:items].where(:number=>10).union(@db[:items, :items_view].where(Sequel.-(:number, 5)=>:n).select(:number), :all=>true, :from_self=>false), :recursive=>[:n])
|
|
266
|
-
@db[:items_view].select_order_map(:n).must_equal [10]
|
|
267
|
-
@db[:items].insert(15)
|
|
268
|
-
@db[:items_view].select_order_map(:n).must_equal [10, 15, 20]
|
|
269
|
-
end if DB.server_version >= 90300
|
|
270
|
-
|
|
271
|
-
it "should support materialized views" do
|
|
272
|
-
@opts = {:materialized=>true}
|
|
273
|
-
@db.create_view(:items_view, @db[:items].where{number >= 10}, @opts)
|
|
274
|
-
@db[:items_view].select_order_map(:number).must_equal [10, 20]
|
|
275
|
-
@db[:items].insert(15)
|
|
276
|
-
@db[:items_view].select_order_map(:number).must_equal [10, 20]
|
|
277
|
-
@db.refresh_view(:items_view)
|
|
278
|
-
@db[:items_view].select_order_map(:number).must_equal [10, 15, 20]
|
|
279
|
-
@db.views.wont_include :items_view
|
|
280
|
-
@db.views(@opts).must_include :items_view
|
|
281
|
-
end if DB.server_version >= 90300
|
|
282
|
-
|
|
283
|
-
it "should support refreshing materialized views concurrently" do
|
|
284
|
-
@opts = {:materialized=>true}
|
|
285
|
-
@db.create_view(:items_view, @db[:items].where{number >= 10}, @opts)
|
|
286
|
-
@db.refresh_view(:items_view)
|
|
287
|
-
proc{@db.refresh_view(:items_view, :concurrently=>true)}.must_raise(Sequel::DatabaseError)
|
|
288
|
-
@db.add_index :items_view, :number, :unique=>true
|
|
289
|
-
@db.refresh_view(:items_view, :concurrently=>true)
|
|
290
|
-
end if DB.server_version >= 90400
|
|
291
|
-
|
|
292
|
-
it "should support specifying tablespaces for materialized views" do
|
|
293
|
-
@opts = {:materialized=>true}
|
|
294
|
-
@db.create_view(:items_view, @db[:items].where{number >= 10}, :materialized=>true, :tablespace=>:pg_default)
|
|
295
|
-
end if DB.server_version >= 90300
|
|
296
|
-
|
|
297
|
-
it "should support :if_exists=>true for not raising an error if the view does not exist" do
|
|
298
|
-
@db.drop_view(:items_view, :if_exists=>true)
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
describe "PostgreSQL", 'INSERT ON CONFLICT' do
|
|
303
|
-
before(:all) do
|
|
304
|
-
@db = DB
|
|
305
|
-
@db.create_table!(:ic_test){Integer :a; Integer :b; Integer :c; TrueClass :c_is_unique, :default=>false; unique :a, :name=>:ic_test_a_uidx; unique [:b, :c], :name=>:ic_test_b_c_uidx; index [:c], :where=>:c_is_unique, :unique=>true}
|
|
306
|
-
@ds = @db[:ic_test]
|
|
307
|
-
end
|
|
308
|
-
before do
|
|
309
|
-
@ds.delete
|
|
310
|
-
end
|
|
311
|
-
after(:all) do
|
|
312
|
-
@db.drop_table?(:ic_test)
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
it "Dataset#insert_ignore and insert_conflict should ignore uniqueness violations" do
|
|
316
|
-
@ds.insert(1, 2, 3)
|
|
317
|
-
@ds.insert(10, 11, 3, true)
|
|
318
|
-
proc{@ds.insert(1, 3, 4)}.must_raise Sequel::UniqueConstraintViolation
|
|
319
|
-
proc{@ds.insert(11, 12, 3, true)}.must_raise Sequel::UniqueConstraintViolation
|
|
320
|
-
@ds.insert_ignore.insert(1, 3, 4).must_be_nil
|
|
321
|
-
@ds.insert_conflict.insert(1, 3, 4).must_be_nil
|
|
322
|
-
@ds.insert_conflict.insert(11, 12, 3, true).must_be_nil
|
|
323
|
-
@ds.insert_conflict(:target=>:a).insert(1, 3, 4).must_be_nil
|
|
324
|
-
@ds.insert_conflict(:target=>:c, :conflict_where=>:c_is_unique).insert(11, 12, 3, true).must_be_nil
|
|
325
|
-
@ds.insert_conflict(:constraint=>:ic_test_a_uidx).insert(1, 3, 4).must_be_nil
|
|
326
|
-
@ds.all.must_equal [{:a=>1, :b=>2, :c=>3, :c_is_unique=>false}, {:a=>10, :b=>11, :c=>3, :c_is_unique=>true}]
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
it "Dataset#insert_ignore and insert_conflict should work with multi_insert/import" do
|
|
330
|
-
@ds.insert(1, 2, 3)
|
|
331
|
-
@ds.insert_ignore.multi_insert([{:a=>1, :b=>3, :c=>4}])
|
|
332
|
-
@ds.insert_ignore.import([:a, :b, :c], [[1, 3, 4]])
|
|
333
|
-
@ds.all.must_equal [{:a=>1, :b=>2, :c=>3, :c_is_unique=>false}]
|
|
334
|
-
@ds.insert_conflict(:target=>:a, :update=>{:b=>3}).import([:a, :b, :c], [[1, 3, 4]])
|
|
335
|
-
@ds.all.must_equal [{:a=>1, :b=>3, :c=>3, :c_is_unique=>false}]
|
|
336
|
-
@ds.insert_conflict(:target=>:a, :update=>{:b=>4}).multi_insert([{:a=>1, :b=>5, :c=>6}])
|
|
337
|
-
@ds.all.must_equal [{:a=>1, :b=>4, :c=>3, :c_is_unique=>false}]
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
it "Dataset#insert_conflict should handle upserts" do
|
|
341
|
-
@ds.insert(1, 2, 3)
|
|
342
|
-
@ds.insert_conflict(:target=>:a, :update=>{:b=>3}).insert(1, 3, 4).must_be_nil
|
|
343
|
-
@ds.all.must_equal [{:a=>1, :b=>3, :c=>3, :c_is_unique=>false}]
|
|
344
|
-
@ds.insert_conflict(:target=>[:b, :c], :update=>{:c=>5}).insert(5, 3, 3).must_be_nil
|
|
345
|
-
@ds.all.must_equal [{:a=>1, :b=>3, :c=>5, :c_is_unique=>false}]
|
|
346
|
-
@ds.insert_conflict(:constraint=>:ic_test_a_uidx, :update=>{:b=>4}).insert(1, 3).must_be_nil
|
|
347
|
-
@ds.all.must_equal [{:a=>1, :b=>4, :c=>5, :c_is_unique=>false}]
|
|
348
|
-
@ds.insert_conflict(:constraint=>:ic_test_a_uidx, :update=>{:b=>5}, :update_where=>{Sequel[:ic_test][:b]=>4}).insert(1, 3, 4).must_be_nil
|
|
349
|
-
@ds.all.must_equal [{:a=>1, :b=>5, :c=>5, :c_is_unique=>false}]
|
|
350
|
-
@ds.insert_conflict(:constraint=>:ic_test_a_uidx, :update=>{:b=>6}, :update_where=>{Sequel[:ic_test][:b]=>4}).insert(1, 3, 4).must_be_nil
|
|
351
|
-
@ds.all.must_equal [{:a=>1, :b=>5, :c=>5, :c_is_unique=>false}]
|
|
352
|
-
end
|
|
353
|
-
end if DB.server_version >= 90500
|
|
354
|
-
|
|
355
|
-
describe "A PostgreSQL database" do
|
|
356
|
-
before(:all) do
|
|
357
|
-
@db = DB
|
|
358
|
-
@db.create_table!(Sequel[:public][:testfk]){primary_key :id; foreign_key :i, Sequel[:public][:testfk]}
|
|
359
|
-
end
|
|
360
|
-
after(:all) do
|
|
361
|
-
@db.drop_table?(Sequel[:public][:testfk])
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
it "should provide the server version" do
|
|
365
|
-
@db.server_version.must_be :>, 70000
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
it "should create a dataset using the VALUES clause via #values" do
|
|
369
|
-
@db.values([[1, 2], [3, 4]]).map([:column1, :column2]).must_equal [[1, 2], [3, 4]]
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
it "should support ordering in aggregate functions" do
|
|
373
|
-
@db.from(@db.values([['1'], ['2']]).as(:t, [:a])).get{string_agg(:a, '-').order(Sequel.desc(:a)).as(:c)}.must_equal '2-1'
|
|
374
|
-
end if DB.server_version >= 90000
|
|
375
|
-
|
|
376
|
-
it "should support ordering and limiting with #values" do
|
|
377
|
-
@db.values([[1, 2], [3, 4]]).reverse(:column2, :column1).limit(1).map([:column1, :column2]).must_equal [[3, 4]]
|
|
378
|
-
@db.values([[1, 2], [3, 4]]).reverse(:column2, :column1).offset(1).map([:column1, :column2]).must_equal [[1, 2]]
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
it "should support subqueries with #values" do
|
|
382
|
-
@db.values([[1, 2]]).from_self.cross_join(@db.values([[3, 4]]).as(:x, [:c1, :c2])).map([:column1, :column2, :c1, :c2]).must_equal [[1, 2, 3, 4]]
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
it "should respect the :read_only option per-savepoint" do
|
|
386
|
-
proc{@db.transaction{@db.transaction(:savepoint=>true, :read_only=>true){@db[Sequel[:public][:testfk]].insert}}}.must_raise(Sequel::DatabaseError)
|
|
387
|
-
proc{@db.transaction(:auto_savepoint=>true, :read_only=>true){@db.transaction(:read_only=>false){@db[Sequel[:public][:testfk]].insert}}}.must_raise(Sequel::DatabaseError)
|
|
388
|
-
@db[Sequel[:public][:testfk]].delete
|
|
389
|
-
@db.transaction{@db[Sequel[:public][:testfk]].insert; @db.transaction(:savepoint=>true, :read_only=>true){@db[Sequel[:public][:testfk]].all;}}
|
|
390
|
-
@db.transaction{@db.transaction(:savepoint=>true, :read_only=>true){}; @db[Sequel[:public][:testfk]].insert}
|
|
391
|
-
@db.transaction{@db[Sequel[:public][:testfk]].all; @db.transaction(:savepoint=>true, :read_only=>true){@db[Sequel[:public][:testfk]].all;}}
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
it "should support disable_insert_returning" do
|
|
395
|
-
ds = @db[Sequel[:public][:testfk]].disable_insert_returning
|
|
396
|
-
ds.delete
|
|
397
|
-
ds.insert.must_be_nil
|
|
398
|
-
id = ds.max(:id)
|
|
399
|
-
ds.select_order_map([:id, :i]).must_equal [[id, nil]]
|
|
400
|
-
ds.insert(:i=>id).must_be_nil
|
|
401
|
-
ds.select_order_map([:id, :i]).must_equal [[id, nil], [id+1, id]]
|
|
402
|
-
ds.insert_select(:i=>ds.max(:id)).must_be_nil
|
|
403
|
-
ds.select_order_map([:id, :i]).must_equal [[id, nil], [id+1, id]]
|
|
404
|
-
c = Class.new(Sequel::Model(ds))
|
|
405
|
-
c.class_eval do
|
|
406
|
-
def before_create
|
|
407
|
-
self.id = model.max(:id)+1
|
|
408
|
-
super
|
|
409
|
-
end
|
|
410
|
-
end
|
|
411
|
-
c.create(:i=>id+1).must_equal c.load(:id=>id+2, :i=>id+1)
|
|
412
|
-
ds.select_order_map([:id, :i]).must_equal [[id, nil], [id+1, id], [id+2, id+1]]
|
|
413
|
-
ds.delete
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
it "should support functions with and without quoting" do
|
|
417
|
-
ds = @db[Sequel[:public][:testfk]]
|
|
418
|
-
ds.delete
|
|
419
|
-
ds.insert
|
|
420
|
-
ds.get{sum(1)}.must_equal 1
|
|
421
|
-
ds.get{Sequel.function('pg_catalog.sum', 1)}.must_equal 1
|
|
422
|
-
ds.get{sum.function(1)}.must_equal 1
|
|
423
|
-
ds.get{pg_catalog[:sum].function(1)}.must_equal 1
|
|
424
|
-
ds.delete
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
it "should support a :qualify option to tables and views" do
|
|
428
|
-
@db.tables(:qualify=>true).must_include(Sequel.qualify('public', 'testfk'))
|
|
429
|
-
begin
|
|
430
|
-
@db.create_view(:testfkv, @db[:testfk])
|
|
431
|
-
@db.views(:qualify=>true).must_include(Sequel.qualify('public', 'testfkv'))
|
|
432
|
-
ensure
|
|
433
|
-
@db.drop_view(:testfkv)
|
|
434
|
-
end
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
it "should handle double underscores in tables when using the qualify option" do
|
|
438
|
-
@db.create_table!(Sequel.qualify(:public, 'test__fk')){Integer :a}
|
|
439
|
-
@db.tables(:qualify=>true).must_include(Sequel.qualify('public', 'test__fk'))
|
|
440
|
-
@db.drop_table(Sequel.qualify(:public, 'test__fk'))
|
|
441
|
-
end
|
|
442
|
-
|
|
443
|
-
it "should not typecast the int2vector type incorrectly" do
|
|
444
|
-
@db.get(Sequel.cast('10 20', :int2vector)).wont_equal 10
|
|
445
|
-
end
|
|
446
|
-
|
|
447
|
-
it "should not typecast the money type incorrectly" do
|
|
448
|
-
@db.get(Sequel.cast('10.01', :money)).wont_equal 0
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
it "should correctly parse the schema" do
|
|
452
|
-
[[[:id, 23], [:i, 23]], [[:id, 20], [:i, 20]]].must_include @db.schema(Sequel[:public][:testfk], :reload=>true).map{|c,s| [c, s[:oid]]}
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
it "should parse foreign keys for tables in a schema" do
|
|
456
|
-
@db.foreign_key_list(Sequel[:public][:testfk]).must_equal [{:on_delete=>:no_action, :on_update=>:no_action, :columns=>[:i], :key=>[:id], :deferrable=>false, :table=>Sequel.qualify(:public, :testfk), :name=>:testfk_i_fkey}]
|
|
457
|
-
@db.foreign_key_list(Sequel[:public][:testfk], :schema=>false).must_equal [{:on_delete=>:no_action, :on_update=>:no_action, :columns=>[:i], :key=>[:id], :deferrable=>false, :table=>:testfk, :name=>:testfk_i_fkey, :schema=>:public}]
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
it "should return uuid fields as strings" do
|
|
461
|
-
@db.get(Sequel.cast('550e8400-e29b-41d4-a716-446655440000', :uuid)).must_equal '550e8400-e29b-41d4-a716-446655440000'
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
it "should handle inserts with placeholder literal string tables" do
|
|
465
|
-
ds = @db.from(Sequel.lit('?', :testfk))
|
|
466
|
-
ds.delete
|
|
467
|
-
ds.insert(:id=>1)
|
|
468
|
-
ds.select_map(:id).must_equal [1]
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
it "should have notice receiver receive notices" do
|
|
472
|
-
a = nil
|
|
473
|
-
Sequel.connect(DB.opts.merge(:notice_receiver=>proc{|r| a = r.result_error_message})){|db| db.do("BEGIN\nRAISE WARNING 'foo';\nEND;")}
|
|
474
|
-
a.must_equal "WARNING: foo\n"
|
|
475
|
-
end if uses_pg && DB.server_version >= 90000
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
describe "A PostgreSQL database " do
|
|
479
|
-
after do
|
|
480
|
-
DB.drop_table?(:b, :a)
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
it "should handle non-ASCII column aliases" do
|
|
484
|
-
s = String.new("\u00E4").force_encoding(DB.get('a').encoding)
|
|
485
|
-
k, v = DB.select(Sequel.as(s, s)).first.shift
|
|
486
|
-
k.to_s.must_equal v
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
it "should parse foreign keys referencing current table using :reverse option" do
|
|
490
|
-
DB.create_table!(:a) do
|
|
491
|
-
primary_key :id
|
|
492
|
-
Integer :i
|
|
493
|
-
Integer :j
|
|
494
|
-
foreign_key :a_id, :a, :foreign_key_constraint_name=>:a_a
|
|
495
|
-
unique [:i, :j]
|
|
496
|
-
end
|
|
497
|
-
DB.create_table!(:b) do
|
|
498
|
-
foreign_key :a_id, :a, :foreign_key_constraint_name=>:a_a
|
|
499
|
-
Integer :c
|
|
500
|
-
Integer :d
|
|
501
|
-
foreign_key [:c, :d], :a, :key=>[:j, :i], :name=>:a_c_d
|
|
502
|
-
end
|
|
503
|
-
DB.foreign_key_list(:a, :reverse=>true).must_equal [
|
|
504
|
-
{:name=>:a_a, :columns=>[:a_id], :key=>[:id], :on_update=>:no_action, :on_delete=>:no_action, :deferrable=>false, :table=>:a, :schema=>:public},
|
|
505
|
-
{:name=>:a_a, :columns=>[:a_id], :key=>[:id], :on_update=>:no_action, :on_delete=>:no_action, :deferrable=>false, :table=>:b, :schema=>:public},
|
|
506
|
-
{:name=>:a_c_d, :columns=>[:c, :d], :key=>[:j, :i], :on_update=>:no_action, :on_delete=>:no_action, :deferrable=>false, :table=>:b, :schema=>:public}]
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
|
|
510
|
-
describe "A PostgreSQL database with domain types" do
|
|
511
|
-
before(:all) do
|
|
512
|
-
@db = DB
|
|
513
|
-
@db << "DROP DOMAIN IF EXISTS positive_number CASCADE"
|
|
514
|
-
@db << "CREATE DOMAIN positive_number AS numeric(10,2) CHECK (VALUE > 0)"
|
|
515
|
-
@db.create_table!(:testfk){positive_number :id, :primary_key=>true}
|
|
516
|
-
end
|
|
517
|
-
after(:all) do
|
|
518
|
-
@db.drop_table?(:testfk)
|
|
519
|
-
@db << "DROP DOMAIN positive_number"
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
it "should correctly parse the schema" do
|
|
523
|
-
sch = @db.schema(:testfk, :reload=>true)
|
|
524
|
-
sch.first.last.delete(:domain_oid).must_be_kind_of(Integer)
|
|
525
|
-
sch.first.last[:db_domain_type].must_equal 'positive_number'
|
|
526
|
-
end
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
describe "A PostgreSQL dataset" do
|
|
530
|
-
before(:all) do
|
|
531
|
-
@db = DB
|
|
532
|
-
@d = @db[:test]
|
|
533
|
-
@db.create_table! :test do
|
|
534
|
-
text :name
|
|
535
|
-
integer :value, :index => true
|
|
536
|
-
end
|
|
537
|
-
end
|
|
538
|
-
before do
|
|
539
|
-
@d.delete
|
|
540
|
-
end
|
|
541
|
-
after do
|
|
542
|
-
@db.drop_table?(:atest)
|
|
543
|
-
end
|
|
544
|
-
after(:all) do
|
|
545
|
-
@db.drop_table?(:test)
|
|
546
|
-
end
|
|
547
|
-
|
|
548
|
-
it "should support regexps" do
|
|
549
|
-
@d.insert(:name => 'abc', :value => 1)
|
|
550
|
-
@d.insert(:name => 'bcd', :value => 2)
|
|
551
|
-
@d.filter(:name => /bc/).count.must_equal 2
|
|
552
|
-
@d.filter(:name => /^bc/).count.must_equal 1
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
it "should support NULLS FIRST and NULLS LAST" do
|
|
556
|
-
@d.insert(:name => 'abc')
|
|
557
|
-
@d.insert(:name => 'bcd')
|
|
558
|
-
@d.insert(:name => 'bcd', :value => 2)
|
|
559
|
-
@d.order(Sequel.asc(:value, :nulls=>:first), :name).select_map(:name).must_equal %w[abc bcd bcd]
|
|
560
|
-
@d.order(Sequel.asc(:value, :nulls=>:last), :name).select_map(:name).must_equal %w[bcd abc bcd]
|
|
561
|
-
@d.order(Sequel.asc(:value, :nulls=>:first), :name).reverse.select_map(:name).must_equal %w[bcd bcd abc]
|
|
562
|
-
end
|
|
563
|
-
|
|
564
|
-
it "should support selecting from LATERAL functions" do
|
|
565
|
-
@d.from{[generate_series(1,3,1).as(:a), pow(:a, 2).lateral.as(:b)]}.select_map([:a, :b])== [[1, 1], [2, 4], [3, 9]]
|
|
566
|
-
end if DB.server_version >= 90300
|
|
567
|
-
|
|
568
|
-
it "should support ordered-set and hypothetical-set aggregate functions" do
|
|
569
|
-
@d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{mode.function.within_group(:a)}.must_equal 1
|
|
570
|
-
end if DB.server_version >= 90400
|
|
571
|
-
|
|
572
|
-
it "should support filtered aggregate functions" do
|
|
573
|
-
@d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{count(:a).filter(:a=>1)}.must_equal 2
|
|
574
|
-
end if DB.server_version >= 90400
|
|
575
|
-
|
|
576
|
-
it "should support functions with ordinality" do
|
|
577
|
-
@d.from{generate_series(1,10,3).with_ordinality}.select_map([:generate_series, :ordinality]).must_equal [[1, 1], [4, 2], [7, 3], [10, 4]]
|
|
578
|
-
end if DB.server_version >= 90400
|
|
579
|
-
|
|
580
|
-
it "#lock should lock tables and yield if a block is given" do
|
|
581
|
-
@d.lock('EXCLUSIVE'){@d.insert(:name=>'a')}
|
|
582
|
-
end
|
|
583
|
-
|
|
584
|
-
it "should support exclusion constraints when creating or altering tables" do
|
|
585
|
-
@db.create_table!(:atest){Integer :t; exclude [[Sequel.desc(:t, :nulls=>:last), '=']], :using=>:btree, :where=>proc{t > 0}}
|
|
586
|
-
@db[:atest].insert(1)
|
|
587
|
-
@db[:atest].insert(2)
|
|
588
|
-
proc{@db[:atest].insert(2)}.must_raise(Sequel::Postgres::ExclusionConstraintViolation)
|
|
589
|
-
|
|
590
|
-
@db.create_table!(:atest){Integer :t}
|
|
591
|
-
@db.alter_table(:atest){add_exclusion_constraint [[:t, '=']], :using=>:btree, :name=>'atest_ex'}
|
|
592
|
-
@db[:atest].insert(1)
|
|
593
|
-
@db[:atest].insert(2)
|
|
594
|
-
proc{@db[:atest].insert(2)}.must_raise(Sequel::Postgres::ExclusionConstraintViolation)
|
|
595
|
-
@db.alter_table(:atest){drop_constraint 'atest_ex'}
|
|
596
|
-
end if DB.server_version >= 90000
|
|
597
|
-
|
|
598
|
-
it "should support deferrable exclusion constraints" do
|
|
599
|
-
@db.create_table!(:atest){Integer :t; exclude [[Sequel.desc(:t, :nulls=>:last), '=']], :using=>:btree, :where=>proc{t > 0}, :deferrable => true}
|
|
600
|
-
proc do
|
|
601
|
-
@db.transaction do
|
|
602
|
-
@db[:atest].insert(2)
|
|
603
|
-
@db[:atest].insert(2)
|
|
604
|
-
end
|
|
605
|
-
end.must_raise(Sequel::Postgres::ExclusionConstraintViolation)
|
|
606
|
-
end if DB.server_version >= 90000
|
|
607
|
-
|
|
608
|
-
it "should support Database#error_info for getting info hash on the given error" do
|
|
609
|
-
@db.create_table!(:atest){Integer :t; Integer :t2, :null=>false, :default=>1; constraint :f, :t=>0}
|
|
610
|
-
begin
|
|
611
|
-
@db[:atest].insert(1)
|
|
612
|
-
rescue => e
|
|
613
|
-
end
|
|
614
|
-
e.wont_equal nil
|
|
615
|
-
info = @db.error_info(e)
|
|
616
|
-
info[:schema].must_equal 'public'
|
|
617
|
-
info[:table].must_equal 'atest'
|
|
618
|
-
info[:constraint].must_equal 'f'
|
|
619
|
-
info[:column].must_be_nil
|
|
620
|
-
info[:type].must_be_nil
|
|
621
|
-
|
|
622
|
-
begin
|
|
623
|
-
@db[:atest].insert(0, nil)
|
|
624
|
-
rescue => e
|
|
625
|
-
end
|
|
626
|
-
e.wont_equal nil
|
|
627
|
-
info = @db.error_info(e.wrapped_exception)
|
|
628
|
-
info[:schema].must_equal 'public'
|
|
629
|
-
info[:table].must_equal 'atest'
|
|
630
|
-
info[:constraint].must_be_nil
|
|
631
|
-
info[:column].must_equal 't2'
|
|
632
|
-
info[:type].must_be_nil
|
|
633
|
-
end if DB.server_version >= 90300 && uses_pg && Object.const_defined?(:PG) && ::PG.const_defined?(:Constants) && ::PG::Constants.const_defined?(:PG_DIAG_SCHEMA_NAME)
|
|
634
|
-
|
|
635
|
-
it "should support Database#do for executing anonymous code blocks" do
|
|
636
|
-
@db.drop_table?(:btest)
|
|
637
|
-
@db.do "BEGIN EXECUTE 'CREATE TABLE btest (a INTEGER)'; EXECUTE 'INSERT INTO btest VALUES (1)'; END"
|
|
638
|
-
@db[:btest].select_map(:a).must_equal [1]
|
|
639
|
-
|
|
640
|
-
@db.do "BEGIN EXECUTE 'DROP TABLE btest; CREATE TABLE atest (a INTEGER)'; EXECUTE 'INSERT INTO atest VALUES (1)'; END", :language=>:plpgsql
|
|
641
|
-
@db[:atest].select_map(:a).must_equal [1]
|
|
642
|
-
end if DB.server_version >= 90000
|
|
643
|
-
|
|
644
|
-
it "should support adding foreign key constarints that are not yet valid, and validating them later" do
|
|
645
|
-
@db.create_table!(:atest){primary_key :id; Integer :fk}
|
|
646
|
-
@db[:atest].insert(1, 5)
|
|
647
|
-
@db.alter_table(:atest){add_foreign_key [:fk], :atest, :not_valid=>true, :name=>:atest_fk}
|
|
648
|
-
@db[:atest].insert(2, 1)
|
|
649
|
-
proc{@db[:atest].insert(3, 4)}.must_raise(Sequel::ForeignKeyConstraintViolation)
|
|
650
|
-
|
|
651
|
-
proc{@db.alter_table(:atest){validate_constraint :atest_fk}}.must_raise(Sequel::ForeignKeyConstraintViolation)
|
|
652
|
-
@db[:atest].where(:id=>1).update(:fk=>2)
|
|
653
|
-
@db.alter_table(:atest){validate_constraint :atest_fk}
|
|
654
|
-
@db.alter_table(:atest){validate_constraint :atest_fk}
|
|
655
|
-
end if DB.server_version >= 90200
|
|
656
|
-
|
|
657
|
-
it "should support adding check constarints that are not yet valid, and validating them later" do
|
|
658
|
-
@db.create_table!(:atest){Integer :a}
|
|
659
|
-
@db[:atest].insert(5)
|
|
660
|
-
@db.alter_table(:atest){add_constraint({:name=>:atest_check, :not_valid=>true}){a >= 10}}
|
|
661
|
-
@db[:atest].insert(10)
|
|
662
|
-
proc{@db[:atest].insert(6)}.must_raise(Sequel::CheckConstraintViolation)
|
|
663
|
-
|
|
664
|
-
proc{@db.alter_table(:atest){validate_constraint :atest_check}}.must_raise(Sequel::CheckConstraintViolation, Sequel::DatabaseError)
|
|
665
|
-
@db[:atest].where{a < 10}.update(:a=>Sequel.+(:a, 10))
|
|
666
|
-
@db.alter_table(:atest){validate_constraint :atest_check}
|
|
667
|
-
@db.alter_table(:atest){validate_constraint :atest_check}
|
|
668
|
-
end if DB.server_version >= 90200
|
|
669
|
-
|
|
670
|
-
it "should support :using when altering a column's type" do
|
|
671
|
-
@db.create_table!(:atest){Integer :t}
|
|
672
|
-
@db[:atest].insert(1262404000)
|
|
673
|
-
@db.alter_table(:atest){set_column_type :t, Time, :using=>Sequel.cast('epoch', Time) + Sequel.cast('1 second', :interval) * :t}
|
|
674
|
-
@db[:atest].get(Sequel.extract(:year, :t)).must_equal 2010
|
|
675
|
-
end
|
|
676
|
-
|
|
677
|
-
it "should support :using with a string when altering a column's type" do
|
|
678
|
-
@db.create_table!(:atest){Integer :t}
|
|
679
|
-
@db[:atest].insert(1262304000)
|
|
680
|
-
@db.alter_table(:atest){set_column_type :t, Time, :using=>"'epoch'::timestamp + '1 second'::interval * t"}
|
|
681
|
-
@db[:atest].get(Sequel.extract(:year, :t)).must_equal 2010
|
|
682
|
-
end
|
|
683
|
-
|
|
684
|
-
it "should have #transaction support various types of synchronous options" do
|
|
685
|
-
@db.transaction(:synchronous=>:on){}
|
|
686
|
-
@db.transaction(:synchronous=>true){}
|
|
687
|
-
@db.transaction(:synchronous=>:off){}
|
|
688
|
-
@db.transaction(:synchronous=>false){}
|
|
689
|
-
|
|
690
|
-
@db.transaction(:synchronous=>nil){}
|
|
691
|
-
if @db.server_version >= 90100
|
|
692
|
-
@db.transaction(:synchronous=>:local){}
|
|
693
|
-
|
|
694
|
-
if @db.server_version >= 90200
|
|
695
|
-
@db.transaction(:synchronous=>:remote_write){}
|
|
696
|
-
end
|
|
697
|
-
end
|
|
698
|
-
end
|
|
699
|
-
|
|
700
|
-
it "should have #transaction support read only transactions" do
|
|
701
|
-
@db.transaction(:read_only=>true){}
|
|
702
|
-
@db.transaction(:read_only=>false){}
|
|
703
|
-
@db.transaction(:isolation=>:serializable, :read_only=>true){}
|
|
704
|
-
@db.transaction(:isolation=>:serializable, :read_only=>false){}
|
|
705
|
-
end
|
|
706
|
-
|
|
707
|
-
it "should have #transaction support deferrable transactions" do
|
|
708
|
-
@db.transaction(:deferrable=>true){}
|
|
709
|
-
@db.transaction(:deferrable=>false){}
|
|
710
|
-
@db.transaction(:deferrable=>true, :read_only=>true){}
|
|
711
|
-
@db.transaction(:deferrable=>false, :read_only=>false){}
|
|
712
|
-
@db.transaction(:isolation=>:serializable, :deferrable=>true, :read_only=>true){}
|
|
713
|
-
@db.transaction(:isolation=>:serializable, :deferrable=>false, :read_only=>false){}
|
|
714
|
-
end if DB.server_version >= 90100
|
|
715
|
-
|
|
716
|
-
it "should support parsing partial indexes with :include_partial option" do
|
|
717
|
-
@db.add_index :test, [:name, :value], :where=>(Sequel[:value] > 10), :name=>:tnv_partial
|
|
718
|
-
@db.indexes(:test)[:tnv_partial].must_be_nil
|
|
719
|
-
@db.indexes(:test, :include_partial=>true)[:tnv_partial].must_equal(:columns=>[:name, :value], :unique=>false, :deferrable=>nil)
|
|
720
|
-
end
|
|
721
|
-
|
|
722
|
-
it "should support creating indexes concurrently" do
|
|
723
|
-
@db.add_index :test, [:name, :value], :concurrently=>true, :name=>'tnv0'
|
|
724
|
-
end
|
|
725
|
-
|
|
726
|
-
it "should support dropping indexes only if they already exist" do
|
|
727
|
-
proc{@db.drop_index :test, [:name, :value], :name=>'tnv1'}.must_raise Sequel::DatabaseError
|
|
728
|
-
@db.drop_index :test, [:name, :value], :if_exists=>true, :name=>'tnv1'
|
|
729
|
-
@db.add_index :test, [:name, :value], :name=>'tnv1'
|
|
730
|
-
@db.drop_index :test, [:name, :value], :if_exists=>true, :name=>'tnv1'
|
|
731
|
-
end
|
|
732
|
-
|
|
733
|
-
it "should support CASCADE when dropping indexes" do
|
|
734
|
-
@db.add_index :test, [:name, :value], :name=>'tnv2', :unique=>true
|
|
735
|
-
@db.create_table(:atest){text :name; integer :value; foreign_key [:name, :value], :test, :key=>[:name, :value]}
|
|
736
|
-
@db.foreign_key_list(:atest).length.must_equal 1
|
|
737
|
-
@db.drop_index :test, [:name, :value], :cascade=>true, :name=>'tnv2'
|
|
738
|
-
@db.foreign_key_list(:atest).length.must_equal 0
|
|
739
|
-
end
|
|
740
|
-
|
|
741
|
-
it "should support dropping indexes concurrently" do
|
|
742
|
-
@db.add_index :test, [:name, :value], :name=>'tnv2'
|
|
743
|
-
@db.drop_index :test, [:name, :value], :concurrently=>true, :name=>'tnv2'
|
|
744
|
-
end if DB.server_version >= 90200
|
|
745
|
-
|
|
746
|
-
it "should support creating indexes only if they do not exist" do
|
|
747
|
-
@db.add_index :test, [:name, :value], :name=>'tnv3'
|
|
748
|
-
proc{@db.add_index :test, [:name, :value], :name=>'tnv3'}.must_raise Sequel::DatabaseError
|
|
749
|
-
@db.add_index :test, [:name, :value], :if_not_exists=>true, :name=>'tnv3'
|
|
750
|
-
end if DB.server_version >= 90500
|
|
751
|
-
|
|
752
|
-
it "should support including columns in indexes" do
|
|
753
|
-
@db.create_table(:atest){Integer :a; Integer :b; Integer :c}
|
|
754
|
-
@db.add_index :atest, :a, :include=>[:b, :c]
|
|
755
|
-
@db.add_index :atest, :b, :include=>:a
|
|
756
|
-
end if DB.server_version >= 110000
|
|
757
|
-
|
|
758
|
-
it "should support specifying tablespaces for tables" do
|
|
759
|
-
@db.create_table(:atest, :tablespace=>:pg_default){Integer :a}
|
|
760
|
-
end
|
|
761
|
-
|
|
762
|
-
it "should support specifying tablespaces for indexes" do
|
|
763
|
-
@db.create_table(:atest){Integer :a}
|
|
764
|
-
@db.add_index :atest, :a, :tablespace=>:pg_default
|
|
765
|
-
end
|
|
766
|
-
|
|
767
|
-
it "#lock should lock table if inside a transaction" do
|
|
768
|
-
@db.transaction{@d.lock('EXCLUSIVE'); @d.insert(:name=>'a')}
|
|
769
|
-
end
|
|
770
|
-
|
|
771
|
-
it "#lock should return nil" do
|
|
772
|
-
@d.lock('EXCLUSIVE'){@d.insert(:name=>'a')}.must_be_nil
|
|
773
|
-
@db.transaction{@d.lock('EXCLUSIVE').must_be_nil; @d.insert(:name=>'a')}
|
|
774
|
-
end
|
|
775
|
-
|
|
776
|
-
it "should raise an error if attempting to update a joined dataset with a single FROM table" do
|
|
777
|
-
proc{@db[:test].join(:test, [:name]).update(:name=>'a')}.must_raise(Sequel::Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs')
|
|
778
|
-
end
|
|
779
|
-
|
|
780
|
-
it "should truncate with options" do
|
|
781
|
-
@d.insert( :name => 'abc', :value => 1)
|
|
782
|
-
@d.count.must_equal 1
|
|
783
|
-
@d.truncate(:cascade => true)
|
|
784
|
-
@d.count.must_equal 0
|
|
785
|
-
if @d.db.server_version > 80400
|
|
786
|
-
@d.insert( :name => 'abc', :value => 1)
|
|
787
|
-
@d.truncate(:cascade => true, :only=>true, :restart=>true)
|
|
788
|
-
@d.count.must_equal 0
|
|
789
|
-
end
|
|
790
|
-
end
|
|
791
|
-
|
|
792
|
-
it "should truncate multiple tables at once" do
|
|
793
|
-
tables = [:test, :test]
|
|
794
|
-
tables.each{|t| @d.from(t).insert}
|
|
795
|
-
@d.from(:test, :test).truncate
|
|
796
|
-
tables.each{|t| @d.from(t).count.must_equal 0}
|
|
797
|
-
end
|
|
798
|
-
end
|
|
799
|
-
|
|
800
|
-
describe "Dataset#distinct" do
|
|
801
|
-
before do
|
|
802
|
-
@db = DB
|
|
803
|
-
@db.create_table!(:a) do
|
|
804
|
-
Integer :a
|
|
805
|
-
Integer :b
|
|
806
|
-
end
|
|
807
|
-
@ds = @db[:a]
|
|
808
|
-
end
|
|
809
|
-
after do
|
|
810
|
-
@db.drop_table?(:a)
|
|
811
|
-
end
|
|
812
|
-
|
|
813
|
-
it "#distinct with arguments should return results distinct on those arguments" do
|
|
814
|
-
@ds.insert(20, 10)
|
|
815
|
-
@ds.insert(30, 10)
|
|
816
|
-
@ds.order(:b, :a).distinct.map(:a).must_equal [20, 30]
|
|
817
|
-
@ds.order(:b, Sequel.desc(:a)).distinct.map(:a).must_equal [30, 20]
|
|
818
|
-
@ds.order(:b, :a).distinct(:b).map(:a).must_equal [20]
|
|
819
|
-
@ds.order(:b, Sequel.desc(:a)).distinct(:b).map(:a).must_equal [30]
|
|
820
|
-
end
|
|
821
|
-
end
|
|
822
|
-
|
|
823
|
-
if DB.pool.respond_to?(:max_size) and DB.pool.max_size > 1
|
|
824
|
-
describe "Dataset#for_update support" do
|
|
825
|
-
before do
|
|
826
|
-
@db = DB.create_table!(:items) do
|
|
827
|
-
primary_key :id
|
|
828
|
-
Integer :number
|
|
829
|
-
String :name
|
|
830
|
-
end
|
|
831
|
-
@ds = DB[:items]
|
|
832
|
-
end
|
|
833
|
-
after do
|
|
834
|
-
DB.drop_table?(:items)
|
|
835
|
-
DB.disconnect
|
|
836
|
-
end
|
|
837
|
-
|
|
838
|
-
it "should handle FOR UPDATE" do
|
|
839
|
-
@ds.insert(:number=>20)
|
|
840
|
-
c, t = nil, nil
|
|
841
|
-
q = Queue.new
|
|
842
|
-
DB.transaction do
|
|
843
|
-
@ds.for_update.first(:id=>1)
|
|
844
|
-
t = Thread.new do
|
|
845
|
-
DB.transaction do
|
|
846
|
-
q.push nil
|
|
847
|
-
@ds.filter(:id=>1).update(:name=>'Jim')
|
|
848
|
-
c = @ds.first(:id=>1)
|
|
849
|
-
q.push nil
|
|
850
|
-
end
|
|
851
|
-
end
|
|
852
|
-
q.pop
|
|
853
|
-
@ds.filter(:id=>1).update(:number=>30)
|
|
854
|
-
end
|
|
855
|
-
q.pop
|
|
856
|
-
t.join
|
|
857
|
-
c.must_equal(:id=>1, :number=>30, :name=>'Jim')
|
|
858
|
-
end
|
|
859
|
-
|
|
860
|
-
it "should handle FOR SHARE" do
|
|
861
|
-
@ds.insert(:number=>20)
|
|
862
|
-
c, t = nil
|
|
863
|
-
q = Queue.new
|
|
864
|
-
DB.transaction do
|
|
865
|
-
@ds.for_share.first(:id=>1)
|
|
866
|
-
t = Thread.new do
|
|
867
|
-
DB.transaction do
|
|
868
|
-
c = @ds.for_share.filter(:id=>1).first
|
|
869
|
-
q.push nil
|
|
870
|
-
end
|
|
871
|
-
end
|
|
872
|
-
q.pop
|
|
873
|
-
@ds.filter(:id=>1).update(:name=>'Jim')
|
|
874
|
-
c.must_equal(:id=>1, :number=>20, :name=>nil)
|
|
875
|
-
end
|
|
876
|
-
t.join
|
|
877
|
-
end
|
|
878
|
-
end
|
|
879
|
-
end
|
|
880
|
-
|
|
881
|
-
describe "A PostgreSQL dataset with a timestamp field" do
|
|
882
|
-
before(:all) do
|
|
883
|
-
@db = DB
|
|
884
|
-
@db.create_table! :test3 do
|
|
885
|
-
Date :date
|
|
886
|
-
DateTime :time
|
|
887
|
-
end
|
|
888
|
-
@d = @db[:test3]
|
|
889
|
-
@db.extension :pg_extended_date_support
|
|
890
|
-
end
|
|
891
|
-
before do
|
|
892
|
-
@d.delete
|
|
893
|
-
end
|
|
894
|
-
after do
|
|
895
|
-
@db.convert_infinite_timestamps = false
|
|
896
|
-
Sequel.datetime_class = Time
|
|
897
|
-
Sequel::SQLTime.date = nil
|
|
898
|
-
Sequel.application_timezone = nil
|
|
899
|
-
end
|
|
900
|
-
after(:all) do
|
|
901
|
-
@db.drop_table?(:test3)
|
|
902
|
-
end
|
|
903
|
-
|
|
904
|
-
it "should store milliseconds in time fields for Time objects" do
|
|
905
|
-
t = Time.now
|
|
906
|
-
@d.insert(:time=>t)
|
|
907
|
-
t2 = @d.get(:time)
|
|
908
|
-
@d.literal(t2).must_equal @d.literal(t)
|
|
909
|
-
t2.strftime('%Y-%m-%d %H:%M:%S').must_equal t.strftime('%Y-%m-%d %H:%M:%S')
|
|
910
|
-
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).must_equal t.usec
|
|
911
|
-
end
|
|
912
|
-
|
|
913
|
-
it "should store milliseconds in time fields for DateTime objects" do
|
|
914
|
-
t = DateTime.now
|
|
915
|
-
@d.insert(:time=>t)
|
|
916
|
-
t2 = @d.get(:time)
|
|
917
|
-
@d.literal(t2).must_equal @d.literal(t)
|
|
918
|
-
t2.strftime('%Y-%m-%d %H:%M:%S').must_equal t.strftime('%Y-%m-%d %H:%M:%S')
|
|
919
|
-
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).must_equal t.strftime('%N').to_i/1000
|
|
920
|
-
end
|
|
921
|
-
|
|
922
|
-
it "should respect SQLTime.date setting for time columns" do
|
|
923
|
-
Sequel::SQLTime.date = Time.local(2000, 1, 2)
|
|
924
|
-
d = Sequel::SQLTime.create(10, 11, 12)
|
|
925
|
-
@db.get(Sequel.cast(d, :time)).must_equal d
|
|
926
|
-
@db.get(Sequel.cast(d, :timetz)).must_equal d
|
|
927
|
-
end
|
|
928
|
-
|
|
929
|
-
it "should respect Sequel.application_timezone for time columns" do
|
|
930
|
-
d = Sequel::SQLTime.create(10, 11, 12)
|
|
931
|
-
Sequel.application_timezone = :local
|
|
932
|
-
@db.get(Sequel.cast(d, :time)).utc_offset.must_equal Time.now.utc_offset
|
|
933
|
-
@db.get(Sequel.cast(d, :timetz)).utc_offset.must_equal Time.now.utc_offset
|
|
934
|
-
Sequel.application_timezone = :utc
|
|
935
|
-
@db.get(Sequel.cast(d, :time)).utc_offset.must_equal 0
|
|
936
|
-
@db.get(Sequel.cast(d, :timetz)).utc_offset.must_equal 0
|
|
937
|
-
end
|
|
938
|
-
|
|
939
|
-
it "should handle parsing dates and timestamps in with 1, 2, and 3 digit years" do
|
|
940
|
-
[1, 10, 100, -2, -20, -200].each do |year|
|
|
941
|
-
d = Date.new(year, 2, 3)
|
|
942
|
-
@db.get(Sequel.cast(d, Date)).must_equal d
|
|
943
|
-
d = Time.local(year, 2, 3, 10, 11, 12)
|
|
944
|
-
@db.get(Sequel.cast(d, Time)).must_equal d
|
|
945
|
-
begin
|
|
946
|
-
Sequel.datetime_class = DateTime
|
|
947
|
-
d = DateTime.new(year, 2, 3, 10, 11, 12)
|
|
948
|
-
@db.get(Sequel.cast(d, Time)).must_equal d
|
|
949
|
-
ensure
|
|
950
|
-
Sequel.datetime_class = Time
|
|
951
|
-
end
|
|
952
|
-
end
|
|
953
|
-
end
|
|
954
|
-
|
|
955
|
-
it "should handle parsing dates and timestamps in the distant future" do
|
|
956
|
-
d = Date.new(5874896, 2, 3)
|
|
957
|
-
@db.get(Sequel.cast(d, Date)).must_equal d
|
|
958
|
-
d = Time.local(294275, 2, 3, 10, 11, 12)
|
|
959
|
-
@db.get(Sequel.cast(d, Time)).must_equal d
|
|
960
|
-
Sequel.datetime_class = DateTime
|
|
961
|
-
d = DateTime.new(294275, 2, 3, 10, 11, 12)
|
|
962
|
-
@db.get(Sequel.cast(d, Time)).must_equal d
|
|
963
|
-
end
|
|
964
|
-
|
|
965
|
-
it "should handle BC times and dates" do
|
|
966
|
-
d = Date.new(-1234, 2, 3)
|
|
967
|
-
@db.get(Sequel.cast(d, Date)).must_equal d
|
|
968
|
-
Sequel.default_timezone = :utc
|
|
969
|
-
t = Time.at(-100000000000).utc + 0.5
|
|
970
|
-
@db.get(Sequel.cast(t, Time)).must_equal t
|
|
971
|
-
@db.get(Sequel.cast(t, :timestamptz)).must_equal t
|
|
972
|
-
Sequel.datetime_class = DateTime
|
|
973
|
-
dt = DateTime.new(-1234, 2, 3, 10, 20, Rational(30, 20))
|
|
974
|
-
@db.get(Sequel.cast(dt, DateTime)).must_equal dt
|
|
975
|
-
@db.get(Sequel.cast(dt, :timestamptz)).must_equal dt
|
|
976
|
-
Sequel.datetime_class = Time
|
|
977
|
-
Sequel.default_timezone = nil
|
|
978
|
-
end
|
|
979
|
-
|
|
980
|
-
it "should handle infinite timestamps if convert_infinite_timestamps is set" do
|
|
981
|
-
@d.insert(:time=>Sequel.cast('infinity', DateTime))
|
|
982
|
-
@db.convert_infinite_timestamps = :nil
|
|
983
|
-
@db[:test3].get(:time).must_be_nil
|
|
984
|
-
@db.convert_infinite_timestamps = :string
|
|
985
|
-
@db[:test3].get(:time).must_equal 'infinity'
|
|
986
|
-
@db.convert_infinite_timestamps = :float
|
|
987
|
-
@db[:test3].get(:time).must_equal 1.0/0.0
|
|
988
|
-
@db.convert_infinite_timestamps = 'nil'
|
|
989
|
-
@db[:test3].get(:time).must_be_nil
|
|
990
|
-
@db.convert_infinite_timestamps = 'string'
|
|
991
|
-
@db[:test3].get(:time).must_equal 'infinity'
|
|
992
|
-
@db.convert_infinite_timestamps = 'date'
|
|
993
|
-
@db[:test3].get(:time).must_equal Date::Infinity.new
|
|
994
|
-
@db.convert_infinite_timestamps = 'float'
|
|
995
|
-
@db[:test3].get(:time).must_equal 1.0/0.0
|
|
996
|
-
@db.convert_infinite_timestamps = 't'
|
|
997
|
-
@db[:test3].get(:time).must_equal 1.0/0.0
|
|
998
|
-
@db.convert_infinite_timestamps = true
|
|
999
|
-
@db[:test3].get(:time).must_equal 1.0/0.0
|
|
1000
|
-
@db.convert_infinite_timestamps = 'f'
|
|
1001
|
-
proc{@db[:test3].get(:time)}.must_raise ArgumentError, Sequel::InvalidValue
|
|
1002
|
-
@db.convert_infinite_timestamps = nil
|
|
1003
|
-
proc{@db[:test3].get(:time)}.must_raise ArgumentError, Sequel::InvalidValue
|
|
1004
|
-
@db.convert_infinite_timestamps = false
|
|
1005
|
-
proc{@db[:test3].get(:time)}.must_raise ArgumentError, Sequel::InvalidValue
|
|
1006
|
-
|
|
1007
|
-
@d.update(:time=>Sequel.cast('-infinity', DateTime))
|
|
1008
|
-
@db.convert_infinite_timestamps = :nil
|
|
1009
|
-
@db[:test3].get(:time).must_be_nil
|
|
1010
|
-
@db.convert_infinite_timestamps = :string
|
|
1011
|
-
@db[:test3].get(:time).must_equal '-infinity'
|
|
1012
|
-
@db.convert_infinite_timestamps = :date
|
|
1013
|
-
@db[:test3].get(:time).must_equal(-Date::Infinity.new)
|
|
1014
|
-
@db.convert_infinite_timestamps = :float
|
|
1015
|
-
@db[:test3].get(:time).must_equal(-1.0/0.0)
|
|
1016
|
-
end
|
|
1017
|
-
|
|
1018
|
-
it "should handle infinite dates if convert_infinite_timestamps is set" do
|
|
1019
|
-
@d.insert(:time=>Sequel.cast('infinity', DateTime))
|
|
1020
|
-
@db.convert_infinite_timestamps = :nil
|
|
1021
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_be_nil
|
|
1022
|
-
@db.convert_infinite_timestamps = :string
|
|
1023
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal 'infinity'
|
|
1024
|
-
@db.convert_infinite_timestamps = :float
|
|
1025
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal 1.0/0.0
|
|
1026
|
-
@db.convert_infinite_timestamps = 'nil'
|
|
1027
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_be_nil
|
|
1028
|
-
@db.convert_infinite_timestamps = 'string'
|
|
1029
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal 'infinity'
|
|
1030
|
-
@db.convert_infinite_timestamps = 'float'
|
|
1031
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal 1.0/0.0
|
|
1032
|
-
@db.convert_infinite_timestamps = 't'
|
|
1033
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal 1.0/0.0
|
|
1034
|
-
@db.convert_infinite_timestamps = true
|
|
1035
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal 1.0/0.0
|
|
1036
|
-
@db.convert_infinite_timestamps = 'f'
|
|
1037
|
-
proc{@db[:test3].get(Sequel.cast(:time, Date))}.must_raise ArgumentError, Sequel::InvalidValue
|
|
1038
|
-
@db.convert_infinite_timestamps = nil
|
|
1039
|
-
proc{@db[:test3].get(Sequel.cast(:time, Date))}.must_raise ArgumentError, Sequel::InvalidValue
|
|
1040
|
-
@db.convert_infinite_timestamps = false
|
|
1041
|
-
proc{@db[:test3].get(Sequel.cast(:time, Date))}.must_raise ArgumentError, Sequel::InvalidValue
|
|
1042
|
-
|
|
1043
|
-
@d.update(:time=>Sequel.cast('-infinity', DateTime))
|
|
1044
|
-
@db.convert_infinite_timestamps = :nil
|
|
1045
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_be_nil
|
|
1046
|
-
@db.convert_infinite_timestamps = :string
|
|
1047
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal '-infinity'
|
|
1048
|
-
@db.convert_infinite_timestamps = :float
|
|
1049
|
-
@db[:test3].get(Sequel.cast(:time, Date)).must_equal(-1.0/0.0)
|
|
1050
|
-
end
|
|
1051
|
-
|
|
1052
|
-
it "should handle conversions from infinite strings/floats in models" do
|
|
1053
|
-
c = Class.new(Sequel::Model(:test3))
|
|
1054
|
-
@db.convert_infinite_timestamps = :float
|
|
1055
|
-
c.new(:time=>'infinity').time.must_equal 'infinity'
|
|
1056
|
-
c.new(:time=>'-infinity').time.must_equal '-infinity'
|
|
1057
|
-
c.new(:time=>1.0/0.0).time.must_equal 1.0/0.0
|
|
1058
|
-
c.new(:time=>-1.0/0.0).time.must_equal(-1.0/0.0)
|
|
1059
|
-
end
|
|
1060
|
-
|
|
1061
|
-
it "should handle infinite dates if convert_infinite_timestamps is set" do
|
|
1062
|
-
@d.insert(:date=>Sequel.cast('infinity', Date))
|
|
1063
|
-
@db.convert_infinite_timestamps = :nil
|
|
1064
|
-
@db[:test3].get(:date).must_be_nil
|
|
1065
|
-
@db.convert_infinite_timestamps = :string
|
|
1066
|
-
@db[:test3].get(:date).must_equal 'infinity'
|
|
1067
|
-
@db.convert_infinite_timestamps = :float
|
|
1068
|
-
@db[:test3].get(:date).must_equal 1.0/0.0
|
|
1069
|
-
|
|
1070
|
-
@d.update(:date=>Sequel.cast('-infinity', :timestamp))
|
|
1071
|
-
@db.convert_infinite_timestamps = :nil
|
|
1072
|
-
@db[:test3].get(:date).must_be_nil
|
|
1073
|
-
@db.convert_infinite_timestamps = :string
|
|
1074
|
-
@db[:test3].get(:date).must_equal '-infinity'
|
|
1075
|
-
@db.convert_infinite_timestamps = :float
|
|
1076
|
-
@db[:test3].get(:date).must_equal(-1.0/0.0)
|
|
1077
|
-
end
|
|
1078
|
-
|
|
1079
|
-
it "should handle conversions from infinite strings/floats in models" do
|
|
1080
|
-
c = Class.new(Sequel::Model(:test3))
|
|
1081
|
-
@db.convert_infinite_timestamps = :float
|
|
1082
|
-
c.new(:date=>'infinity').date.must_equal 'infinity'
|
|
1083
|
-
c.new(:date=>'-infinity').date.must_equal '-infinity'
|
|
1084
|
-
c.new(:date=>1.0/0.0).date.must_equal 1.0/0.0
|
|
1085
|
-
c.new(:date=>-1.0/0.0).date.must_equal(-1.0/0.0)
|
|
1086
|
-
end
|
|
1087
|
-
|
|
1088
|
-
it "explain and analyze should not raise errors" do
|
|
1089
|
-
@d = DB[:test3]
|
|
1090
|
-
@d.explain
|
|
1091
|
-
@d.analyze
|
|
1092
|
-
end
|
|
1093
|
-
|
|
1094
|
-
it "#locks should be a dataset returning database locks " do
|
|
1095
|
-
@db.locks.must_be_kind_of(Sequel::Dataset)
|
|
1096
|
-
@db.locks.all.must_be_kind_of(Array)
|
|
1097
|
-
end
|
|
1098
|
-
end
|
|
1099
|
-
|
|
1100
|
-
describe "A PostgreSQL database" do
|
|
1101
|
-
before do
|
|
1102
|
-
@db = DB
|
|
1103
|
-
@db.create_table! :test2 do
|
|
1104
|
-
text :name
|
|
1105
|
-
integer :value
|
|
1106
|
-
end
|
|
1107
|
-
end
|
|
1108
|
-
after do
|
|
1109
|
-
@db.drop_table?(:test2)
|
|
1110
|
-
end
|
|
1111
|
-
|
|
1112
|
-
it "should support column operations" do
|
|
1113
|
-
@db.create_table!(:test2){text :name; integer :value}
|
|
1114
|
-
@db[:test2].insert({})
|
|
1115
|
-
@db[:test2].columns.must_equal [:name, :value]
|
|
1116
|
-
|
|
1117
|
-
@db.add_column :test2, :xyz, :text, :default => '000'
|
|
1118
|
-
@db[:test2].columns.must_equal [:name, :value, :xyz]
|
|
1119
|
-
@db[:test2].insert(:name => 'mmm', :value => 111)
|
|
1120
|
-
@db[:test2].first[:xyz].must_equal '000'
|
|
1121
|
-
|
|
1122
|
-
@db[:test2].columns.must_equal [:name, :value, :xyz]
|
|
1123
|
-
@db.drop_column :test2, :xyz
|
|
1124
|
-
|
|
1125
|
-
@db[:test2].columns.must_equal [:name, :value]
|
|
1126
|
-
|
|
1127
|
-
@db[:test2].delete
|
|
1128
|
-
@db.add_column :test2, :xyz, :text, :default => '000'
|
|
1129
|
-
@db[:test2].insert(:name => 'mmm', :value => 111, :xyz => 'qqqq')
|
|
1130
|
-
|
|
1131
|
-
@db[:test2].columns.must_equal [:name, :value, :xyz]
|
|
1132
|
-
@db.rename_column :test2, :xyz, :zyx
|
|
1133
|
-
@db[:test2].columns.must_equal [:name, :value, :zyx]
|
|
1134
|
-
@db[:test2].first[:zyx].must_equal 'qqqq'
|
|
1135
|
-
|
|
1136
|
-
@db.add_column :test2, :xyz, :float
|
|
1137
|
-
@db[:test2].delete
|
|
1138
|
-
@db[:test2].insert(:name => 'mmm', :value => 111, :xyz => 56.78)
|
|
1139
|
-
@db.set_column_type :test2, :xyz, :integer
|
|
1140
|
-
|
|
1141
|
-
@db[:test2].first[:xyz].must_equal 57
|
|
1142
|
-
end
|
|
1143
|
-
end
|
|
1144
|
-
|
|
1145
|
-
describe "A PostgreSQL database" do
|
|
1146
|
-
before do
|
|
1147
|
-
@db = DB
|
|
1148
|
-
@db.drop_table?(:posts)
|
|
1149
|
-
end
|
|
1150
|
-
after do
|
|
1151
|
-
@db.drop_table?(:posts)
|
|
1152
|
-
end
|
|
1153
|
-
|
|
1154
|
-
it "should support resetting the primary key sequence" do
|
|
1155
|
-
@db.create_table(:posts){primary_key :a}
|
|
1156
|
-
@db[:posts].insert(:a=>20).must_equal 20
|
|
1157
|
-
@db[:posts].insert.must_equal 1
|
|
1158
|
-
@db[:posts].insert.must_equal 2
|
|
1159
|
-
@db[:posts].insert(:a=>10).must_equal 10
|
|
1160
|
-
@db.reset_primary_key_sequence(:posts).must_equal 21
|
|
1161
|
-
@db[:posts].insert.must_equal 21
|
|
1162
|
-
@db[:posts].order(:a).map(:a).must_equal [1, 2, 10, 20, 21]
|
|
1163
|
-
end
|
|
1164
|
-
|
|
1165
|
-
it "should support specifying Integer/Bignum types in primary keys and have them be auto incrementing" do
|
|
1166
|
-
@db.create_table(:posts){primary_key :a, :type=>Integer}
|
|
1167
|
-
@db[:posts].insert.must_equal 1
|
|
1168
|
-
@db[:posts].insert.must_equal 2
|
|
1169
|
-
@db.create_table!(:posts){primary_key :a, :type=>:Bignum}
|
|
1170
|
-
@db[:posts].insert.must_equal 1
|
|
1171
|
-
@db[:posts].insert.must_equal 2
|
|
1172
|
-
end
|
|
1173
|
-
|
|
1174
|
-
it "should not raise an error if attempting to resetting the primary key sequence for a table without a primary key" do
|
|
1175
|
-
@db.create_table(:posts){Integer :a}
|
|
1176
|
-
@db.reset_primary_key_sequence(:posts).must_be_nil
|
|
1177
|
-
end
|
|
1178
|
-
|
|
1179
|
-
it "should support opclass specification" do
|
|
1180
|
-
@db.create_table(:posts){text :title; text :body; integer :user_id; index(:user_id, :opclass => :int4_ops, :type => :btree)}
|
|
1181
|
-
proc{@db.create_table(:posts){text :title; text :body; integer :user_id; index(:user_id, :opclass => :bogus_opclass, :type => :btree)}}.must_raise Sequel::DatabaseError
|
|
1182
|
-
end
|
|
1183
|
-
|
|
1184
|
-
it "should support fulltext indexes and searching" do
|
|
1185
|
-
@db.create_table(:posts){text :title; text :body; full_text_index [:title, :body]; full_text_index :title, :language => 'french', :index_type=>:gist}
|
|
1186
|
-
|
|
1187
|
-
@db[:posts].insert(:title=>'ruby rails', :body=>'yowsa')
|
|
1188
|
-
@db[:posts].insert(:title=>'sequel', :body=>'ruby')
|
|
1189
|
-
@db[:posts].insert(:title=>'ruby scooby', :body=>'x')
|
|
1190
|
-
|
|
1191
|
-
@db[:posts].full_text_search(:title, 'rails').all.must_equal [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
1192
|
-
@db[:posts].full_text_search(:title, 'rails', :headline=>true).all.must_equal [{:title=>'ruby rails', :body=>'yowsa', :headline=>'ruby <b>rails</b>'}]
|
|
1193
|
-
@db[:posts].full_text_search([:title, :body], ['yowsa', 'rails']).all.must_equal [:title=>'ruby rails', :body=>'yowsa']
|
|
1194
|
-
@db[:posts].full_text_search(:title, 'scooby', :language => 'french').all.must_equal [{:title=>'ruby scooby', :body=>'x'}]
|
|
1195
|
-
|
|
1196
|
-
@db[:posts].full_text_search(:title, :$n).call(:select, :n=>'rails').must_equal [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
1197
|
-
@db[:posts].full_text_search(:title, :$n).prepare(:select, :fts_select).call(:n=>'rails').must_equal [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
1198
|
-
|
|
1199
|
-
@db[:posts].insert(:title=>'jruby rubinius ruby maglev mri iron')
|
|
1200
|
-
@db[:posts].insert(:title=>'ruby jruby maglev mri rubinius iron')
|
|
1201
|
-
@db[:posts].full_text_search(:title, 'rubinius ruby', :phrase=>true).select_order_map(:title).must_equal ['jruby rubinius ruby maglev mri iron']
|
|
1202
|
-
@db[:posts].full_text_search(:title, 'jruby maglev', :phrase=>true).select_order_map(:title).must_equal ['ruby jruby maglev mri rubinius iron']
|
|
1203
|
-
@db[:posts].full_text_search(:title, 'rubinius ruby', :plain=>true).select_order_map(:title).must_equal ['jruby rubinius ruby maglev mri iron', 'ruby jruby maglev mri rubinius iron']
|
|
1204
|
-
@db[:posts].full_text_search(:title, 'jruby maglev', :plain=>true).select_order_map(:title).must_equal ['jruby rubinius ruby maglev mri iron', 'ruby jruby maglev mri rubinius iron']
|
|
1205
|
-
|
|
1206
|
-
if DB.server_version >= 90600
|
|
1207
|
-
@db[:posts].full_text_search(:title, 'rubinius ruby', :to_tsquery=>:phrase).select_order_map(:title).must_equal ['jruby rubinius ruby maglev mri iron']
|
|
1208
|
-
@db[:posts].full_text_search(:title, 'jruby maglev', :to_tsquery=>:phrase).select_order_map(:title).must_equal ['ruby jruby maglev mri rubinius iron']
|
|
1209
|
-
end
|
|
1210
|
-
|
|
1211
|
-
@db[:posts].full_text_search(Sequel.function(:to_tsvector, 'simple', :title), 'rails', :tsvector=>true).all.must_equal [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
1212
|
-
@db[:posts].full_text_search(:title, Sequel.function(:to_tsquery, 'simple', 'rails'), :tsquery=>true).all.must_equal [{:title=>'ruby rails', :body=>'yowsa'}]
|
|
1213
|
-
proc{@db[:posts].full_text_search(Sequel.function(:to_tsvector, 'simple', :title), 'rubinius ruby', :tsvector=>true, :phrase=>true)}.must_raise(Sequel::Error)
|
|
1214
|
-
proc{@db[:posts].full_text_search(:title, Sequel.function(:to_tsquery, 'simple', 'rails'), :tsquery=>true, :phrase=>true)}.must_raise(Sequel::Error)
|
|
1215
|
-
|
|
1216
|
-
@db[:posts].delete
|
|
1217
|
-
t1 = "bork " * 1000 + "ruby sequel"
|
|
1218
|
-
t2 = "ruby sequel " * 1000
|
|
1219
|
-
@db[:posts].insert(:title=>t1)
|
|
1220
|
-
@db[:posts].insert(:title=>t2)
|
|
1221
|
-
@db[:posts].full_text_search(:title, 'ruby & sequel', :rank=>true).select_map(:title).must_equal [t2, t1]
|
|
1222
|
-
end if DB.server_version >= 80300
|
|
1223
|
-
|
|
1224
|
-
it "should support spatial indexes" do
|
|
1225
|
-
@db.create_table(:posts){box :geom; spatial_index [:geom]}
|
|
1226
|
-
end
|
|
1227
|
-
|
|
1228
|
-
it "should support indexes with index type" do
|
|
1229
|
-
@db.create_table(:posts){point :p; index :p, :type => 'gist'}
|
|
1230
|
-
end
|
|
1231
|
-
|
|
1232
|
-
it "should support unique indexes with index type" do
|
|
1233
|
-
@db.create_table(:posts){varchar :title, :size => 5; index :title, :type => 'btree', :unique => true, :name=>:post_index_foo}
|
|
1234
|
-
@db.indexes(:posts).length.must_equal 1
|
|
1235
|
-
@db.indexes(:posts)[:post_index_foo][:unique].must_equal true
|
|
1236
|
-
end
|
|
1237
|
-
|
|
1238
|
-
it "should support partial indexes" do
|
|
1239
|
-
@db.create_table(:posts){varchar :title, :size => 5; index :title, :where => {:title => '5'}}
|
|
1240
|
-
end
|
|
1241
|
-
|
|
1242
|
-
it "should support identifiers for table names when creating indexes" do
|
|
1243
|
-
@db.create_table(Sequel::SQL::Identifier.new(:posts)){varchar :title, :size => 5; index :title}
|
|
1244
|
-
@db.indexes(:posts).length.must_equal 1
|
|
1245
|
-
end
|
|
1246
|
-
|
|
1247
|
-
it "should support renaming tables" do
|
|
1248
|
-
@db.create_table!(:posts1){primary_key :a}
|
|
1249
|
-
@db.rename_table(:posts1, :posts)
|
|
1250
|
-
end
|
|
1251
|
-
|
|
1252
|
-
it "should adding a primary key only if it does not already exists" do
|
|
1253
|
-
@db.create_table(:posts){Integer :a}
|
|
1254
|
-
@db.alter_table(:posts){add_column :b, Integer}
|
|
1255
|
-
@db.alter_table(:posts){add_column :b, Integer, :if_not_exists=>true}
|
|
1256
|
-
proc{@db.alter_table(:posts){add_column :b, Integer}}.must_raise Sequel::DatabaseError
|
|
1257
|
-
end if DB.server_version >= 90600
|
|
1258
|
-
end
|
|
1259
|
-
|
|
1260
|
-
describe "Sequel::Postgres::Database" do
|
|
1261
|
-
before do
|
|
1262
|
-
@db = DB
|
|
1263
|
-
@db.create_table!(:posts){Integer :a}
|
|
1264
|
-
end
|
|
1265
|
-
after do
|
|
1266
|
-
@db.run("DROP PROCEDURE test_procedure_posts(int, int)")
|
|
1267
|
-
@db.drop_table?(:posts)
|
|
1268
|
-
end
|
|
1269
|
-
|
|
1270
|
-
it "#call_procedure should call a procedure that returns a row" do
|
|
1271
|
-
@db.run <<SQL
|
|
1272
|
-
CREATE OR REPLACE PROCEDURE test_procedure_posts(inout a int, inout b int)
|
|
1273
|
-
LANGUAGE SQL
|
|
1274
|
-
AS $$
|
|
1275
|
-
INSERT INTO posts VALUES (a) RETURNING *;
|
|
1276
|
-
INSERT INTO posts VALUES (a * 2) RETURNING *;
|
|
1277
|
-
SELECT max(posts.a), min(posts.a) FROM posts;
|
|
1278
|
-
$$;
|
|
1279
|
-
SQL
|
|
1280
|
-
@db.call_procedure(:test_procedure_posts, 1, nil).must_equal(:a=>2, :b=>1)
|
|
1281
|
-
@db.call_procedure(:test_procedure_posts, 3, nil).must_equal(:a=>6, :b=>1)
|
|
1282
|
-
end
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
it "#call_procedure should call a procedure that doesn't return a row" do
|
|
1286
|
-
@db.run <<SQL
|
|
1287
|
-
CREATE OR REPLACE PROCEDURE test_procedure_posts(int, int)
|
|
1288
|
-
LANGUAGE SQL
|
|
1289
|
-
AS $$
|
|
1290
|
-
INSERT INTO posts VALUES ($1) RETURNING *;
|
|
1291
|
-
INSERT INTO posts VALUES ($1 * 2) RETURNING *;
|
|
1292
|
-
$$;
|
|
1293
|
-
SQL
|
|
1294
|
-
@db.call_procedure(:test_procedure_posts, 1, nil).must_be_nil
|
|
1295
|
-
@db.call_procedure(:test_procedure_posts, 3, nil).must_be_nil
|
|
1296
|
-
end
|
|
1297
|
-
end if DB.adapter_scheme == :postgres && DB.server_version >= 110000
|
|
1298
|
-
|
|
1299
|
-
describe "Postgres::Dataset#import" do
|
|
1300
|
-
before do
|
|
1301
|
-
@db = DB
|
|
1302
|
-
@db.create_table!(:test){primary_key :x; Integer :y}
|
|
1303
|
-
@ds = @db[:test]
|
|
1304
|
-
end
|
|
1305
|
-
after do
|
|
1306
|
-
@db.drop_table?(:test)
|
|
1307
|
-
end
|
|
1308
|
-
|
|
1309
|
-
it "#import should a single insert statement" do
|
|
1310
|
-
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
1311
|
-
@ds.all.must_equal [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
1312
|
-
end
|
|
1313
|
-
|
|
1314
|
-
it "#import should work correctly when returning primary keys" do
|
|
1315
|
-
@ds.import([:x, :y], [[1, 2], [3, 4]], :return=>:primary_key).must_equal [1, 3]
|
|
1316
|
-
@ds.all.must_equal [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
1317
|
-
end
|
|
1318
|
-
|
|
1319
|
-
it "#import should work correctly when returning primary keys with :slice option" do
|
|
1320
|
-
@ds.import([:x, :y], [[1, 2], [3, 4]], :return=>:primary_key, :slice=>1).must_equal [1, 3]
|
|
1321
|
-
@ds.all.must_equal [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
1322
|
-
end
|
|
1323
|
-
|
|
1324
|
-
it "#import should work correctly with an arbitrary returning value" do
|
|
1325
|
-
@ds.returning(:y, :x).import([:x, :y], [[1, 2], [3, 4]]).must_equal [{:y=>2, :x=>1}, {:y=>4, :x=>3}]
|
|
1326
|
-
@ds.all.must_equal [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
|
|
1327
|
-
end
|
|
1328
|
-
end
|
|
1329
|
-
|
|
1330
|
-
describe "Postgres::Dataset#insert" do
|
|
1331
|
-
before do
|
|
1332
|
-
@db = DB
|
|
1333
|
-
@db.create_table!(:test5){primary_key :xid; Integer :value}
|
|
1334
|
-
@ds = @db[:test5]
|
|
1335
|
-
end
|
|
1336
|
-
after do
|
|
1337
|
-
@db.drop_table?(:test5)
|
|
1338
|
-
end
|
|
1339
|
-
|
|
1340
|
-
it "should work with static SQL" do
|
|
1341
|
-
@ds.with_sql('INSERT INTO test5 (value) VALUES (10)').insert.must_be_nil
|
|
1342
|
-
@db['INSERT INTO test5 (value) VALUES (20)'].insert.must_be_nil
|
|
1343
|
-
@ds.all.must_equal [{:xid=>1, :value=>10}, {:xid=>2, :value=>20}]
|
|
1344
|
-
end
|
|
1345
|
-
|
|
1346
|
-
it "should insert correctly if using a column array and a value array" do
|
|
1347
|
-
@ds.insert([:value], [10]).must_equal 1
|
|
1348
|
-
@ds.all.must_equal [{:xid=>1, :value=>10}]
|
|
1349
|
-
end
|
|
1350
|
-
|
|
1351
|
-
it "should have insert return primary key value" do
|
|
1352
|
-
@ds.insert(:value=>10).must_equal 1
|
|
1353
|
-
end
|
|
1354
|
-
|
|
1355
|
-
it "should have insert_select insert the record and return the inserted record" do
|
|
1356
|
-
h = @ds.insert_select(:value=>10)
|
|
1357
|
-
h[:value].must_equal 10
|
|
1358
|
-
@ds.first(:xid=>h[:xid])[:value].must_equal 10
|
|
1359
|
-
end
|
|
1360
|
-
|
|
1361
|
-
it "should have insert_select respect existing returning clause" do
|
|
1362
|
-
h = @ds.returning(Sequel[:value].as(:v), Sequel[:xid].as(:x)).insert_select(:value=>10)
|
|
1363
|
-
h[:v].must_equal 10
|
|
1364
|
-
@ds.first(:xid=>h[:x])[:value].must_equal 10
|
|
1365
|
-
end
|
|
1366
|
-
|
|
1367
|
-
it "should have prepared insert_select respect existing returning clause" do
|
|
1368
|
-
h = @ds.returning(Sequel[:value].as(:v), Sequel[:xid].as(:x)).prepare(:insert_select, :insert_select, :value=>10).call
|
|
1369
|
-
h[:v].must_equal 10
|
|
1370
|
-
@ds.first(:xid=>h[:x])[:value].must_equal 10
|
|
1371
|
-
end
|
|
1372
|
-
|
|
1373
|
-
it "should correctly return the inserted record's primary key value" do
|
|
1374
|
-
value1 = 10
|
|
1375
|
-
id1 = @ds.insert(:value=>value1)
|
|
1376
|
-
@ds.first(:xid=>id1)[:value].must_equal value1
|
|
1377
|
-
value2 = 20
|
|
1378
|
-
id2 = @ds.insert(:value=>value2)
|
|
1379
|
-
@ds.first(:xid=>id2)[:value].must_equal value2
|
|
1380
|
-
end
|
|
1381
|
-
|
|
1382
|
-
it "should return nil if the table has no primary key" do
|
|
1383
|
-
@db.create_table!(:test5){String :name; Integer :value}
|
|
1384
|
-
@ds.delete
|
|
1385
|
-
@ds.insert(:name=>'a').must_be_nil
|
|
1386
|
-
end
|
|
1387
|
-
end
|
|
1388
|
-
|
|
1389
|
-
describe "Postgres::Database schema qualified tables" do
|
|
1390
|
-
before do
|
|
1391
|
-
@db = DB
|
|
1392
|
-
@db << "CREATE SCHEMA schema_test"
|
|
1393
|
-
@db.instance_variable_set(:@primary_keys, {})
|
|
1394
|
-
@db.instance_variable_set(:@primary_key_sequences, {})
|
|
1395
|
-
end
|
|
1396
|
-
after do
|
|
1397
|
-
@db << "DROP SCHEMA schema_test CASCADE"
|
|
1398
|
-
end
|
|
1399
|
-
|
|
1400
|
-
it "should be able to create, drop, select and insert into tables in a given schema" do
|
|
1401
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){primary_key :i}
|
|
1402
|
-
@db[Sequel[:schema_test][:schema_test]].first.must_be_nil
|
|
1403
|
-
@db[Sequel[:schema_test][:schema_test]].insert(:i=>1).must_equal 1
|
|
1404
|
-
@db[Sequel[:schema_test][:schema_test]].first.must_equal(:i=>1)
|
|
1405
|
-
@db.from(Sequel.lit('schema_test.schema_test')).first.must_equal(:i=>1)
|
|
1406
|
-
@db.drop_table(Sequel[:schema_test][:schema_test])
|
|
1407
|
-
@db.create_table(Sequel.qualify(:schema_test, :schema_test)){integer :i}
|
|
1408
|
-
@db[Sequel[:schema_test][:schema_test]].first.must_be_nil
|
|
1409
|
-
@db.from(Sequel.lit('schema_test.schema_test')).first.must_be_nil
|
|
1410
|
-
@db.drop_table(Sequel.qualify(:schema_test, :schema_test))
|
|
1411
|
-
end
|
|
1412
|
-
|
|
1413
|
-
it "#tables should not include tables in a default non-public schema" do
|
|
1414
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){integer :i}
|
|
1415
|
-
@db.tables(:schema=>:schema_test).must_include(:schema_test)
|
|
1416
|
-
@db.tables.wont_include(:pg_am)
|
|
1417
|
-
@db.tables.wont_include(:domain_udt_usage)
|
|
1418
|
-
end
|
|
1419
|
-
|
|
1420
|
-
it "#tables should return tables in the schema provided by the :schema argument" do
|
|
1421
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){integer :i}
|
|
1422
|
-
@db.tables(:schema=>:schema_test).must_equal [:schema_test]
|
|
1423
|
-
end
|
|
1424
|
-
|
|
1425
|
-
it "#schema should not include columns from tables in a default non-public schema" do
|
|
1426
|
-
@db.create_table(Sequel[:schema_test][:domains]){integer :i}
|
|
1427
|
-
sch = @db.schema(Sequel[:schema_test][:domains])
|
|
1428
|
-
cs = sch.map{|x| x.first}
|
|
1429
|
-
cs.first.must_equal :i
|
|
1430
|
-
cs.wont_include(:data_type)
|
|
1431
|
-
end
|
|
1432
|
-
|
|
1433
|
-
it "#schema should only include columns from the table in the given :schema argument" do
|
|
1434
|
-
@db.create_table!(:domains){integer :d}
|
|
1435
|
-
@db.create_table(Sequel[:schema_test][:domains]){integer :i}
|
|
1436
|
-
sch = @db.schema(:domains, :schema=>:schema_test)
|
|
1437
|
-
cs = sch.map{|x| x.first}
|
|
1438
|
-
cs.first.must_equal :i
|
|
1439
|
-
cs.wont_include(:d)
|
|
1440
|
-
@db.drop_table(:domains)
|
|
1441
|
-
end
|
|
1442
|
-
|
|
1443
|
-
it "#schema should not include columns in tables from other domains by default" do
|
|
1444
|
-
@db.create_table!(Sequel[:public][:domains]){integer :d}
|
|
1445
|
-
@db.create_table(Sequel[:schema_test][:domains]){integer :i}
|
|
1446
|
-
begin
|
|
1447
|
-
@db.schema(:domains).map{|x| x.first}.must_equal [:d]
|
|
1448
|
-
@db.schema(Sequel[:schema_test][:domains]).map{|x| x.first}.must_equal [:i]
|
|
1449
|
-
ensure
|
|
1450
|
-
@db.drop_table?(Sequel[:public][:domains])
|
|
1451
|
-
end
|
|
1452
|
-
end
|
|
1453
|
-
|
|
1454
|
-
it "#table_exists? should see if the table is in a given schema" do
|
|
1455
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){integer :i}
|
|
1456
|
-
@db.table_exists?(Sequel[:schema_test][:schema_test]).must_equal true
|
|
1457
|
-
end
|
|
1458
|
-
|
|
1459
|
-
it "should be able to add and drop indexes in a schema" do
|
|
1460
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){Integer :i, :index=>true}
|
|
1461
|
-
@db.indexes(Sequel[:schema_test][:schema_test]).keys.must_equal [:schema_test_schema_test_i_index]
|
|
1462
|
-
@db.drop_index Sequel[:schema_test][:schema_test], :i
|
|
1463
|
-
@db.indexes(Sequel[:schema_test][:schema_test]).keys.must_equal []
|
|
1464
|
-
end
|
|
1465
|
-
|
|
1466
|
-
it "should be able to get primary keys for tables in a given schema" do
|
|
1467
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){primary_key :i}
|
|
1468
|
-
@db.primary_key(Sequel[:schema_test][:schema_test]).must_equal 'i'
|
|
1469
|
-
end
|
|
1470
|
-
|
|
1471
|
-
it "should be able to get serial sequences for tables in a given schema" do
|
|
1472
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){primary_key :i}
|
|
1473
|
-
@db.primary_key_sequence(Sequel[:schema_test][:schema_test]).must_equal '"schema_test"."schema_test_i_seq"'
|
|
1474
|
-
end
|
|
1475
|
-
|
|
1476
|
-
it "should be able to get serial sequences for tables that have spaces in the name in a given schema" do
|
|
1477
|
-
@db.create_table(Sequel[:schema_test][:"schema test"]){primary_key :i}
|
|
1478
|
-
@db.primary_key_sequence(Sequel[:schema_test][:"schema test"]).must_equal '"schema_test"."schema test_i_seq"'
|
|
1479
|
-
end
|
|
1480
|
-
|
|
1481
|
-
it "should be able to get custom sequences for tables in a given schema" do
|
|
1482
|
-
@db << "CREATE SEQUENCE schema_test.kseq"
|
|
1483
|
-
@db.create_table(Sequel[:schema_test][:schema_test]){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.kseq'::regclass)")}
|
|
1484
|
-
@db.primary_key_sequence(Sequel[:schema_test][:schema_test]).must_equal '"schema_test".kseq'
|
|
1485
|
-
end
|
|
1486
|
-
|
|
1487
|
-
it "should be able to get custom sequences for tables that have spaces in the name in a given schema" do
|
|
1488
|
-
@db << "CREATE SEQUENCE schema_test.\"ks eq\""
|
|
1489
|
-
@db.create_table(Sequel[:schema_test][:"schema test"]){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.\"ks eq\"'::regclass)")}
|
|
1490
|
-
@db.primary_key_sequence(Sequel[:schema_test][:"schema test"]).must_equal '"schema_test"."ks eq"'
|
|
1491
|
-
end
|
|
1492
|
-
|
|
1493
|
-
it "should handle schema introspection cases with tables with same name in multiple schemas" do
|
|
1494
|
-
begin
|
|
1495
|
-
@db.create_table(Sequel[:schema_test][:schema_test]) do
|
|
1496
|
-
primary_key :id
|
|
1497
|
-
foreign_key :i, Sequel[:schema_test][:schema_test], :index=>{:name=>:schema_test_sti}
|
|
1498
|
-
end
|
|
1499
|
-
@db.create_table!(Sequel[:public][:schema_test]) do
|
|
1500
|
-
primary_key :id
|
|
1501
|
-
foreign_key :j, Sequel[:public][:schema_test], :index=>{:name=>:public_test_sti}
|
|
1502
|
-
end
|
|
1503
|
-
|
|
1504
|
-
h = @db.schema(:schema_test)
|
|
1505
|
-
h.length.must_equal 2
|
|
1506
|
-
h.last.first.must_equal :j
|
|
1507
|
-
|
|
1508
|
-
@db.indexes(:schema_test).must_equal(:public_test_sti=>{:unique=>false, :columns=>[:j], :deferrable=>nil})
|
|
1509
|
-
@db.foreign_key_list(:schema_test).must_equal [{:on_update=>:no_action, :columns=>[:j], :deferrable=>false, :key=>[:id], :table=>:schema_test, :on_delete=>:no_action, :name=>:schema_test_j_fkey, :schema=>:public}]
|
|
1510
|
-
ensure
|
|
1511
|
-
@db.drop_table?(Sequel[:public][:schema_test])
|
|
1512
|
-
end
|
|
1513
|
-
end
|
|
1514
|
-
end
|
|
1515
|
-
|
|
1516
|
-
describe "Postgres::Database schema qualified tables and eager graphing" do
|
|
1517
|
-
before(:all) do
|
|
1518
|
-
@db = DB
|
|
1519
|
-
@db.run "DROP SCHEMA s CASCADE" rescue nil
|
|
1520
|
-
@db.run "CREATE SCHEMA s"
|
|
1521
|
-
|
|
1522
|
-
@db.create_table(Sequel[:s][:bands]){primary_key :id; String :name}
|
|
1523
|
-
@db.create_table(Sequel[:s][:albums]){primary_key :id; String :name; foreign_key :band_id, Sequel[:s][:bands]}
|
|
1524
|
-
@db.create_table(Sequel[:s][:tracks]){primary_key :id; String :name; foreign_key :album_id, Sequel[:s][:albums]}
|
|
1525
|
-
@db.create_table(Sequel[:s][:members]){primary_key :id; String :name; foreign_key :band_id, Sequel[:s][:bands]}
|
|
1526
|
-
|
|
1527
|
-
@Band = Class.new(Sequel::Model(Sequel[:s][:bands]))
|
|
1528
|
-
@Album = Class.new(Sequel::Model(Sequel[:s][:albums]))
|
|
1529
|
-
@Track = Class.new(Sequel::Model(Sequel[:s][:tracks]))
|
|
1530
|
-
@Member = Class.new(Sequel::Model(Sequel[:s][:members]))
|
|
1531
|
-
def @Band.name; :Band; end
|
|
1532
|
-
def @Album.name; :Album; end
|
|
1533
|
-
def @Track.name; :Track; end
|
|
1534
|
-
def @Member.name; :Member; end
|
|
1535
|
-
|
|
1536
|
-
@Band.one_to_many :albums, :class=>@Album, :order=>:name
|
|
1537
|
-
@Band.one_to_many :members, :class=>@Member, :order=>:name
|
|
1538
|
-
@Album.many_to_one :band, :class=>@Band, :order=>:name
|
|
1539
|
-
@Album.one_to_many :tracks, :class=>@Track, :order=>:name
|
|
1540
|
-
@Track.many_to_one :album, :class=>@Album, :order=>:name
|
|
1541
|
-
@Member.many_to_one :band, :class=>@Band, :order=>:name
|
|
1542
|
-
|
|
1543
|
-
@Member.many_to_many :members, :class=>@Member, :join_table=>Sequel[:s][:bands], :right_key=>:id, :left_key=>:id, :left_primary_key=>:band_id, :right_primary_key=>:band_id, :order=>:name
|
|
1544
|
-
@Band.many_to_many :tracks, :class=>@Track, :join_table=>Sequel[:s][:albums], :right_key=>:id, :right_primary_key=>:album_id, :order=>:name
|
|
1545
|
-
|
|
1546
|
-
@b1 = @Band.create(:name=>"BM")
|
|
1547
|
-
@b2 = @Band.create(:name=>"J")
|
|
1548
|
-
@a1 = @Album.create(:name=>"BM1", :band=>@b1)
|
|
1549
|
-
@a2 = @Album.create(:name=>"BM2", :band=>@b1)
|
|
1550
|
-
@a3 = @Album.create(:name=>"GH", :band=>@b2)
|
|
1551
|
-
@a4 = @Album.create(:name=>"GHL", :band=>@b2)
|
|
1552
|
-
@t1 = @Track.create(:name=>"BM1-1", :album=>@a1)
|
|
1553
|
-
@t2 = @Track.create(:name=>"BM1-2", :album=>@a1)
|
|
1554
|
-
@t3 = @Track.create(:name=>"BM2-1", :album=>@a2)
|
|
1555
|
-
@t4 = @Track.create(:name=>"BM2-2", :album=>@a2)
|
|
1556
|
-
@m1 = @Member.create(:name=>"NU", :band=>@b1)
|
|
1557
|
-
@m2 = @Member.create(:name=>"TS", :band=>@b1)
|
|
1558
|
-
@m3 = @Member.create(:name=>"NS", :band=>@b2)
|
|
1559
|
-
@m4 = @Member.create(:name=>"JC", :band=>@b2)
|
|
1560
|
-
end
|
|
1561
|
-
after(:all) do
|
|
1562
|
-
@db.run "DROP SCHEMA s CASCADE"
|
|
1563
|
-
end
|
|
1564
|
-
|
|
1565
|
-
it "should return all eager graphs correctly" do
|
|
1566
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:albums).all
|
|
1567
|
-
bands.must_equal [@b1, @b2]
|
|
1568
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1569
|
-
|
|
1570
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:albums=>:tracks).all
|
|
1571
|
-
bands.must_equal [@b1, @b2]
|
|
1572
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1573
|
-
bands.map{|x| x.albums.map{|y| y.tracks}}.must_equal [[[@t1, @t2], [@t3, @t4]], [[], []]]
|
|
1574
|
-
|
|
1575
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph({:albums=>:tracks}, :members).all
|
|
1576
|
-
bands.must_equal [@b1, @b2]
|
|
1577
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1578
|
-
bands.map{|x| x.albums.map{|y| y.tracks}}.must_equal [[[@t1, @t2], [@t3, @t4]], [[], []]]
|
|
1579
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1580
|
-
end
|
|
1581
|
-
|
|
1582
|
-
it "should have eager graphs work with previous joins" do
|
|
1583
|
-
bands = @Band.order(Sequel[:bands][:name]).select_all(Sequel[:s][:bands]).join(Sequel[:s][:members], :band_id=>:id).from_self(:alias=>:bands0).eager_graph(:albums=>:tracks).all
|
|
1584
|
-
bands.must_equal [@b1, @b2]
|
|
1585
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1586
|
-
bands.map{|x| x.albums.map{|y| y.tracks}}.must_equal [[[@t1, @t2], [@t3, @t4]], [[], []]]
|
|
1587
|
-
end
|
|
1588
|
-
|
|
1589
|
-
it "should have eager graphs work with joins with the same tables" do
|
|
1590
|
-
bands = @Band.order(Sequel[:bands][:name]).select_all(Sequel[:s][:bands]).join(Sequel[:s][:members], :band_id=>:id).eager_graph({:albums=>:tracks}, :members).all
|
|
1591
|
-
bands.must_equal [@b1, @b2]
|
|
1592
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1593
|
-
bands.map{|x| x.albums.map{|y| y.tracks}}.must_equal [[[@t1, @t2], [@t3, @t4]], [[], []]]
|
|
1594
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1595
|
-
end
|
|
1596
|
-
|
|
1597
|
-
it "should have eager graphs work with self referential associations" do
|
|
1598
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:tracks=>{:album=>:band}).all
|
|
1599
|
-
bands.must_equal [@b1, @b2]
|
|
1600
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1601
|
-
bands.map{|x| x.tracks.map{|y| y.album}}.must_equal [[@a1, @a1, @a2, @a2], []]
|
|
1602
|
-
bands.map{|x| x.tracks.map{|y| y.album.band}}.must_equal [[@b1, @b1, @b1, @b1], []]
|
|
1603
|
-
|
|
1604
|
-
members = @Member.order(Sequel[:members][:name]).eager_graph(:members).all
|
|
1605
|
-
members.must_equal [@m4, @m3, @m1, @m2]
|
|
1606
|
-
members.map{|x| x.members}.must_equal [[@m4, @m3], [@m4, @m3], [@m1, @m2], [@m1, @m2]]
|
|
1607
|
-
|
|
1608
|
-
members = @Member.order(Sequel[:members][:name]).eager_graph(:band, :members=>:band).all
|
|
1609
|
-
members.must_equal [@m4, @m3, @m1, @m2]
|
|
1610
|
-
members.map{|x| x.band}.must_equal [@b2, @b2, @b1, @b1]
|
|
1611
|
-
members.map{|x| x.members}.must_equal [[@m4, @m3], [@m4, @m3], [@m1, @m2], [@m1, @m2]]
|
|
1612
|
-
members.map{|x| x.members.map{|y| y.band}}.must_equal [[@b2, @b2], [@b2, @b2], [@b1, @b1], [@b1, @b1]]
|
|
1613
|
-
end
|
|
1614
|
-
|
|
1615
|
-
it "should have eager graphs work with a from_self dataset" do
|
|
1616
|
-
bands = @Band.order(Sequel[:bands][:name]).from_self.eager_graph(:tracks=>{:album=>:band}).all
|
|
1617
|
-
bands.must_equal [@b1, @b2]
|
|
1618
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1619
|
-
bands.map{|x| x.tracks.map{|y| y.album}}.must_equal [[@a1, @a1, @a2, @a2], []]
|
|
1620
|
-
bands.map{|x| x.tracks.map{|y| y.album.band}}.must_equal [[@b1, @b1, @b1, @b1], []]
|
|
1621
|
-
end
|
|
1622
|
-
|
|
1623
|
-
it "should have eager graphs work with different types of aliased from tables" do
|
|
1624
|
-
bands = @Band.order(Sequel[:tracks][:name]).from(Sequel[:s][:bands].as(:tracks)).eager_graph(:tracks).all
|
|
1625
|
-
bands.must_equal [@b1, @b2]
|
|
1626
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1627
|
-
|
|
1628
|
-
bands = @Band.order(Sequel[:tracks][:name]).from(Sequel.expr(Sequel[:s][:bands]).as(:tracks)).eager_graph(:tracks).all
|
|
1629
|
-
bands.must_equal [@b1, @b2]
|
|
1630
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1631
|
-
|
|
1632
|
-
bands = @Band.order(Sequel[:tracks][:name]).from(Sequel.expr(Sequel[:s][:bands]).as(Sequel.identifier(:tracks))).eager_graph(:tracks).all
|
|
1633
|
-
bands.must_equal [@b1, @b2]
|
|
1634
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1635
|
-
|
|
1636
|
-
bands = @Band.order(Sequel[:tracks][:name]).from(Sequel.expr(Sequel[:s][:bands]).as('tracks')).eager_graph(:tracks).all
|
|
1637
|
-
bands.must_equal [@b1, @b2]
|
|
1638
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1639
|
-
end
|
|
1640
|
-
|
|
1641
|
-
it "should have eager graphs work with join tables with aliases" do
|
|
1642
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:members).join(Sequel[:s][:albums].as(:tracks), :band_id=>Sequel.qualify(Sequel[:s][:bands], :id)).eager_graph(:albums=>:tracks).all
|
|
1643
|
-
bands.must_equal [@b1, @b2]
|
|
1644
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1645
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1646
|
-
|
|
1647
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:members).join(Sequel.as(Sequel[:s][:albums], :tracks), :band_id=>Sequel.qualify(Sequel[:s][:bands], :id)).eager_graph(:albums=>:tracks).all
|
|
1648
|
-
bands.must_equal [@b1, @b2]
|
|
1649
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1650
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1651
|
-
|
|
1652
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:members).join(Sequel.as(Sequel[:s][:albums], 'tracks'), :band_id=>Sequel.qualify(Sequel[:s][:bands], :id)).eager_graph(:albums=>:tracks).all
|
|
1653
|
-
bands.must_equal [@b1, @b2]
|
|
1654
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1655
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1656
|
-
|
|
1657
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:members).join(Sequel.as(Sequel[:s][:albums], Sequel.identifier(:tracks)), :band_id=>Sequel.qualify(Sequel[:s][:bands], :id)).eager_graph(:albums=>:tracks).all
|
|
1658
|
-
bands.must_equal [@b1, @b2]
|
|
1659
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1660
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1661
|
-
|
|
1662
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:members).join(Sequel[:s][:albums], {:band_id=>Sequel.qualify(Sequel[:s][:bands], :id)}, :table_alias=>:tracks).eager_graph(:albums=>:tracks).all
|
|
1663
|
-
bands.must_equal [@b1, @b2]
|
|
1664
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1665
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1666
|
-
|
|
1667
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:members).join(Sequel[:s][:albums], {:band_id=>Sequel.qualify(Sequel[:s][:bands], :id)}, :table_alias=>'tracks').eager_graph(:albums=>:tracks).all
|
|
1668
|
-
bands.must_equal [@b1, @b2]
|
|
1669
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1670
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1671
|
-
|
|
1672
|
-
bands = @Band.order(Sequel[:bands][:name]).eager_graph(:members).join(Sequel[:s][:albums], {:band_id=>Sequel.qualify(Sequel[:s][:bands], :id)}, :table_alias=>Sequel.identifier(:tracks)).eager_graph(:albums=>:tracks).all
|
|
1673
|
-
bands.must_equal [@b1, @b2]
|
|
1674
|
-
bands.map{|x| x.albums}.must_equal [[@a1, @a2], [@a3, @a4]]
|
|
1675
|
-
bands.map{|x| x.members}.must_equal [[@m1, @m2], [@m4, @m3]]
|
|
1676
|
-
end
|
|
1677
|
-
|
|
1678
|
-
it "should have eager graphs work with different types of qualified from tables" do
|
|
1679
|
-
bands = @Band.order(Sequel[:bands][:name]).from(Sequel.qualify(:s, :bands)).eager_graph(:tracks).all
|
|
1680
|
-
bands.must_equal [@b1, @b2]
|
|
1681
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1682
|
-
|
|
1683
|
-
bands = @Band.order(Sequel[:bands][:name]).from(Sequel.identifier(:bands).qualify(:s)).eager_graph(:tracks).all
|
|
1684
|
-
bands.must_equal [@b1, @b2]
|
|
1685
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1686
|
-
|
|
1687
|
-
bands = @Band.order(Sequel[:bands][:name]).from(Sequel::SQL::QualifiedIdentifier.new(:s, 'bands')).eager_graph(:tracks).all
|
|
1688
|
-
bands.must_equal [@b1, @b2]
|
|
1689
|
-
bands.map{|x| x.tracks}.must_equal [[@t1, @t2, @t3, @t4], []]
|
|
1690
|
-
end
|
|
1691
|
-
|
|
1692
|
-
end
|
|
1693
|
-
|
|
1694
|
-
if DB.server_version >= 80300
|
|
1695
|
-
describe "PostgreSQL tsearch2" do
|
|
1696
|
-
before(:all) do
|
|
1697
|
-
DB.create_table! :test6 do
|
|
1698
|
-
text :title
|
|
1699
|
-
text :body
|
|
1700
|
-
full_text_index [:title, :body]
|
|
1701
|
-
end
|
|
1702
|
-
@ds = DB[:test6]
|
|
1703
|
-
end
|
|
1704
|
-
after do
|
|
1705
|
-
DB[:test6].delete
|
|
1706
|
-
end
|
|
1707
|
-
after(:all) do
|
|
1708
|
-
DB.drop_table?(:test6)
|
|
1709
|
-
end
|
|
1710
|
-
|
|
1711
|
-
it "should search by indexed column" do
|
|
1712
|
-
record = {:title => "oopsla conference", :body => "test"}
|
|
1713
|
-
@ds.insert(record)
|
|
1714
|
-
@ds.full_text_search(:title, "oopsla").all.must_equal [record]
|
|
1715
|
-
end
|
|
1716
|
-
|
|
1717
|
-
it "should join multiple coumns with spaces to search by last words in row" do
|
|
1718
|
-
record = {:title => "multiple words", :body => "are easy to search"}
|
|
1719
|
-
@ds.insert(record)
|
|
1720
|
-
@ds.full_text_search([:title, :body], "words").all.must_equal [record]
|
|
1721
|
-
end
|
|
1722
|
-
|
|
1723
|
-
it "should return rows with a NULL in one column if a match in another column" do
|
|
1724
|
-
record = {:title => "multiple words", :body =>nil}
|
|
1725
|
-
@ds.insert(record)
|
|
1726
|
-
@ds.full_text_search([:title, :body], "words").all.must_equal [record]
|
|
1727
|
-
end
|
|
1728
|
-
end
|
|
1729
|
-
end
|
|
1730
|
-
|
|
1731
|
-
describe "Postgres::Database functions, languages, schemas, and triggers" do
|
|
1732
|
-
before do
|
|
1733
|
-
@d = DB
|
|
1734
|
-
end
|
|
1735
|
-
after do
|
|
1736
|
-
@d.drop_function('tf', :if_exists=>true, :cascade=>true)
|
|
1737
|
-
@d.drop_function('tf', :if_exists=>true, :cascade=>true, :args=>%w'integer integer')
|
|
1738
|
-
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
|
|
1739
|
-
@d.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
|
|
1740
|
-
@d.drop_table?(:test)
|
|
1741
|
-
end
|
|
1742
|
-
|
|
1743
|
-
it "#create_function and #drop_function should create and drop functions" do
|
|
1744
|
-
proc{@d['SELECT tf()'].all}.must_raise(Sequel::DatabaseError)
|
|
1745
|
-
@d.create_function('tf', 'SELECT 1', :returns=>:integer)
|
|
1746
|
-
@d['SELECT tf()'].all.must_equal [{:tf=>1}]
|
|
1747
|
-
@d.drop_function('tf')
|
|
1748
|
-
proc{@d['SELECT tf()'].all}.must_raise(Sequel::DatabaseError)
|
|
1749
|
-
end
|
|
1750
|
-
|
|
1751
|
-
it "#create_function and #drop_function should support options" do
|
|
1752
|
-
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'}}]
|
|
1753
|
-
@d.create_function(*args)
|
|
1754
|
-
# Make sure replace works
|
|
1755
|
-
@d.create_function(*args)
|
|
1756
|
-
@d['SELECT tf(1, 2)'].all.must_equal [{:tf=>3}]
|
|
1757
|
-
args = ['tf', {:if_exists=>true, :cascade=>true, :args=>[[:integer, :a], :integer]}]
|
|
1758
|
-
@d.drop_function(*args)
|
|
1759
|
-
# Make sure if exists works
|
|
1760
|
-
@d.drop_function(*args)
|
|
1761
|
-
end
|
|
1762
|
-
|
|
1763
|
-
it "#create_language and #drop_language should create and drop languages" do
|
|
1764
|
-
@d.create_language(:plpgsql, :replace=>true) if @d.server_version < 90000
|
|
1765
|
-
proc{@d.create_language(:plpgsql)}.must_raise(Sequel::DatabaseError)
|
|
1766
|
-
@d.drop_language(:plpgsql) if @d.server_version < 90000
|
|
1767
|
-
proc{@d.drop_language(:plpgsql)}.must_raise(Sequel::DatabaseError) if @d.server_version < 90000
|
|
1768
|
-
# Make sure if exists works
|
|
1769
|
-
@d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
|
|
1770
|
-
end
|
|
1771
|
-
|
|
1772
|
-
it "#create_schema and #drop_schema should create and drop schemas" do
|
|
1773
|
-
@d.create_schema(:sequel)
|
|
1774
|
-
@d.create_schema(:sequel, :if_not_exists=>true) if @d.server_version >= 90300
|
|
1775
|
-
@d.create_table(Sequel[:sequel][:test]){Integer :a}
|
|
1776
|
-
@d.drop_schema(:sequel, :if_exists=>true, :cascade=>true)
|
|
1777
|
-
end
|
|
1778
|
-
|
|
1779
|
-
it "#create_trigger and #drop_trigger should create and drop triggers" do
|
|
1780
|
-
@d.create_language(:plpgsql) if @d.server_version < 90000
|
|
1781
|
-
@d.create_function(:tf, 'BEGIN IF NEW.value IS NULL THEN RAISE EXCEPTION \'Blah\'; END IF; RETURN NEW; END;', :language=>:plpgsql, :returns=>:trigger)
|
|
1782
|
-
@d.create_table(:test){String :name; Integer :value}
|
|
1783
|
-
@d.create_trigger(:test, :identity, :tf, :each_row=>true)
|
|
1784
|
-
@d[:test].insert(:name=>'a', :value=>1)
|
|
1785
|
-
@d[:test].filter(:name=>'a').all.must_equal [{:name=>'a', :value=>1}]
|
|
1786
|
-
proc{@d[:test].filter(:name=>'a').update(:value=>nil)}.must_raise(Sequel::DatabaseError)
|
|
1787
|
-
@d[:test].filter(:name=>'a').all.must_equal [{:name=>'a', :value=>1}]
|
|
1788
|
-
@d[:test].filter(:name=>'a').update(:value=>3)
|
|
1789
|
-
@d[:test].filter(:name=>'a').all.must_equal [{:name=>'a', :value=>3}]
|
|
1790
|
-
@d.drop_trigger(:test, :identity)
|
|
1791
|
-
# Make sure if exists works
|
|
1792
|
-
@d.drop_trigger(:test, :identity, :if_exists=>true, :cascade=>true)
|
|
1793
|
-
|
|
1794
|
-
if @d.supports_trigger_conditions?
|
|
1795
|
-
@d.create_trigger(:test, :identity, :tf, :each_row=>true, :events => :update, :when=> {Sequel[:new][:name] => 'b'})
|
|
1796
|
-
@d[:test].filter(:name=>'a').update(:value=>nil)
|
|
1797
|
-
@d[:test].filter(:name=>'a').all.must_equal [{:name=>'a', :value=>nil}]
|
|
1798
|
-
proc{@d[:test].filter(:name=>'a').update(:name=>'b')}.must_raise(Sequel::DatabaseError)
|
|
1799
|
-
@d[:test].filter(:name=>'a').all.must_equal [{:name=>'a', :value=>nil}]
|
|
1800
|
-
@d.drop_trigger(:test, :identity)
|
|
1801
|
-
end
|
|
1802
|
-
end
|
|
1803
|
-
end
|
|
1804
|
-
|
|
1805
|
-
if DB.adapter_scheme == :postgres
|
|
1806
|
-
describe "Postgres::Dataset #use_cursor" do
|
|
1807
|
-
before(:all) do
|
|
1808
|
-
@db = DB
|
|
1809
|
-
@db.create_table!(:test_cursor){Integer :x}
|
|
1810
|
-
@ds = @db[:test_cursor]
|
|
1811
|
-
@db.transaction{1001.times{|i| @ds.insert(i)}}
|
|
1812
|
-
end
|
|
1813
|
-
after(:all) do
|
|
1814
|
-
@db.drop_table?(:test_cursor)
|
|
1815
|
-
end
|
|
1816
|
-
|
|
1817
|
-
it "should return the same results as the non-cursor use" do
|
|
1818
|
-
@ds.all.must_equal @ds.use_cursor.all
|
|
1819
|
-
end
|
|
1820
|
-
|
|
1821
|
-
it "should not swallow errors if closing cursor raises an error" do
|
|
1822
|
-
proc do
|
|
1823
|
-
@db.synchronize do |c|
|
|
1824
|
-
@ds.use_cursor.each do |r|
|
|
1825
|
-
@db.run "CLOSE sequel_cursor"
|
|
1826
|
-
raise ArgumentError
|
|
1827
|
-
end
|
|
1828
|
-
end
|
|
1829
|
-
end.must_raise(ArgumentError)
|
|
1830
|
-
end
|
|
1831
|
-
|
|
1832
|
-
it "should respect the :rows_per_fetch option" do
|
|
1833
|
-
i = 0
|
|
1834
|
-
@ds = @ds.with_extend{define_method(:execute){|*a, &block| i+=1; super(*a, &block);}}
|
|
1835
|
-
@ds.use_cursor.all
|
|
1836
|
-
i.must_equal 2
|
|
1837
|
-
|
|
1838
|
-
i = 0
|
|
1839
|
-
@ds.use_cursor(:rows_per_fetch=>100).all
|
|
1840
|
-
i.must_equal 11
|
|
1841
|
-
end
|
|
1842
|
-
|
|
1843
|
-
it "should respect the :hold=>true option for creating the cursor WITH HOLD and not using a transaction" do
|
|
1844
|
-
@ds.use_cursor.each{@db.in_transaction?.must_equal true}
|
|
1845
|
-
@ds.use_cursor(:hold=>true).each{@db.in_transaction?.must_equal false}
|
|
1846
|
-
end
|
|
1847
|
-
|
|
1848
|
-
it "should support updating individual rows based on a cursor" do
|
|
1849
|
-
@db.transaction(:rollback=>:always) do
|
|
1850
|
-
@ds.use_cursor(:rows_per_fetch=>1).each do |row|
|
|
1851
|
-
@ds.where_current_of.update(:x=>Sequel.*(row[:x], 10))
|
|
1852
|
-
end
|
|
1853
|
-
@ds.select_order_map(:x).must_equal((0..1000).map{|x| x * 10})
|
|
1854
|
-
end
|
|
1855
|
-
@ds.select_order_map(:x).must_equal((0..1000).to_a)
|
|
1856
|
-
end
|
|
1857
|
-
|
|
1858
|
-
it "should respect the :cursor_name option" do
|
|
1859
|
-
one_rows = []
|
|
1860
|
-
two_rows = []
|
|
1861
|
-
@ds.order(:x).use_cursor(:cursor_name => 'cursor_one').each do |one|
|
|
1862
|
-
one_rows << one
|
|
1863
|
-
if one[:x] % 1000 == 500
|
|
1864
|
-
two_rows = []
|
|
1865
|
-
@ds.order(:x).use_cursor(:cursor_name => 'cursor_two').each do |two|
|
|
1866
|
-
two_rows << two
|
|
1867
|
-
end
|
|
1868
|
-
end
|
|
1869
|
-
end
|
|
1870
|
-
one_rows.must_equal two_rows
|
|
1871
|
-
end
|
|
1872
|
-
|
|
1873
|
-
it "should handle returning inside block" do
|
|
1874
|
-
ds = @ds.with_extend do
|
|
1875
|
-
def check_return
|
|
1876
|
-
use_cursor.each{|r| return}
|
|
1877
|
-
end
|
|
1878
|
-
end
|
|
1879
|
-
ds.check_return
|
|
1880
|
-
ds.all.must_equal ds.use_cursor.all
|
|
1881
|
-
end
|
|
1882
|
-
end
|
|
1883
|
-
|
|
1884
|
-
describe "Database#add_named_conversion_proc" do
|
|
1885
|
-
before(:all) do
|
|
1886
|
-
@db = DB
|
|
1887
|
-
@old_cp = @db.conversion_procs[1013]
|
|
1888
|
-
@db.conversion_procs.delete(1013)
|
|
1889
|
-
@db.add_named_conversion_proc(:oidvector, &:reverse)
|
|
1890
|
-
end
|
|
1891
|
-
after(:all) do
|
|
1892
|
-
@db.conversion_procs.delete(30)
|
|
1893
|
-
@db.conversion_procs[1013] = @old_cp
|
|
1894
|
-
@db.drop_table?(:foo)
|
|
1895
|
-
@db.drop_enum(:foo_enum) rescue nil
|
|
1896
|
-
end
|
|
1897
|
-
|
|
1898
|
-
it "should work for scalar types" do
|
|
1899
|
-
@db.create_table!(:foo){oidvector :bar}
|
|
1900
|
-
@db[:foo].insert(Sequel.cast('21', :oidvector))
|
|
1901
|
-
@db[:foo].get(:bar).must_equal '12'
|
|
1902
|
-
end
|
|
1903
|
-
|
|
1904
|
-
it "should work for array types" do
|
|
1905
|
-
@db.create_table!(:foo){column :bar, 'oidvector[]'}
|
|
1906
|
-
@db[:foo].insert(Sequel.pg_array(['21'], :oidvector))
|
|
1907
|
-
@db[:foo].get(:bar).must_equal ['12']
|
|
1908
|
-
end
|
|
1909
|
-
|
|
1910
|
-
it "should work with for enums" do
|
|
1911
|
-
@db.drop_enum(:foo_enum) rescue nil
|
|
1912
|
-
@db.create_enum(:foo_enum, %w(foo bar))
|
|
1913
|
-
@db.add_named_conversion_proc(:foo_enum){|string| string.reverse}
|
|
1914
|
-
@db.create_table!(:foo){foo_enum :bar}
|
|
1915
|
-
@db[:foo].insert(:bar => 'foo')
|
|
1916
|
-
@db[:foo].get(:bar).must_equal 'foo'.reverse
|
|
1917
|
-
end
|
|
1918
|
-
end
|
|
1919
|
-
end
|
|
1920
|
-
|
|
1921
|
-
if uses_pg_or_jdbc && DB.server_version >= 90000
|
|
1922
|
-
describe "Postgres::Database#copy_into" do
|
|
1923
|
-
before(:all) do
|
|
1924
|
-
@db = DB
|
|
1925
|
-
@db.create_table!(:test_copy){Integer :x; Integer :y}
|
|
1926
|
-
@ds = @db[:test_copy].order(:x, :y)
|
|
1927
|
-
end
|
|
1928
|
-
before do
|
|
1929
|
-
@db[:test_copy].delete
|
|
1930
|
-
end
|
|
1931
|
-
after(:all) do
|
|
1932
|
-
@db.drop_table?(:test_copy)
|
|
1933
|
-
end
|
|
1934
|
-
|
|
1935
|
-
it "should work with a :data option containing data in PostgreSQL text format" do
|
|
1936
|
-
@db.copy_into(:test_copy, :data=>"1\t2\n3\t4\n")
|
|
1937
|
-
@ds.select_map([:x, :y]).must_equal [[1, 2], [3, 4]]
|
|
1938
|
-
end
|
|
1939
|
-
|
|
1940
|
-
it "should work with :format=>:csv option and :data option containing data in CSV format" do
|
|
1941
|
-
@db.copy_into(:test_copy, :format=>:csv, :data=>"1,2\n3,4\n")
|
|
1942
|
-
@ds.select_map([:x, :y]).must_equal [[1, 2], [3, 4]]
|
|
1943
|
-
end
|
|
1944
|
-
|
|
1945
|
-
it "should respect given :options" do
|
|
1946
|
-
@db.copy_into(:test_copy, :options=>"FORMAT csv, HEADER TRUE", :data=>"x,y\n1,2\n3,4\n")
|
|
1947
|
-
@ds.select_map([:x, :y]).must_equal [[1, 2], [3, 4]]
|
|
1948
|
-
end
|
|
1949
|
-
|
|
1950
|
-
it "should respect given :options options when :format is used" do
|
|
1951
|
-
@db.copy_into(:test_copy, :options=>"QUOTE '''', DELIMITER '|'", :format=>:csv, :data=>"'1'|'2'\n'3'|'4'\n")
|
|
1952
|
-
@ds.select_map([:x, :y]).must_equal [[1, 2], [3, 4]]
|
|
1953
|
-
end
|
|
1954
|
-
|
|
1955
|
-
it "should accept :columns option to online copy the given columns" do
|
|
1956
|
-
@db.copy_into(:test_copy, :data=>"1\t2\n3\t4\n", :columns=>[:y, :x])
|
|
1957
|
-
@ds.select_map([:x, :y]).must_equal [[2, 1], [4, 3]]
|
|
1958
|
-
end
|
|
1959
|
-
|
|
1960
|
-
it "should accept a block and use returned values for the copy in data stream" do
|
|
1961
|
-
buf = ["1\t2\n", "3\t4\n"]
|
|
1962
|
-
@db.copy_into(:test_copy){buf.shift}
|
|
1963
|
-
@ds.select_map([:x, :y]).must_equal [[1, 2], [3, 4]]
|
|
1964
|
-
end
|
|
1965
|
-
|
|
1966
|
-
it "should work correctly with a block and :format=>:csv" do
|
|
1967
|
-
buf = ["1,2\n", "3,4\n"]
|
|
1968
|
-
@db.copy_into(:test_copy, :format=>:csv){buf.shift}
|
|
1969
|
-
@ds.select_map([:x, :y]).must_equal [[1, 2], [3, 4]]
|
|
1970
|
-
end
|
|
1971
|
-
|
|
1972
|
-
it "should accept an enumerable as the :data option" do
|
|
1973
|
-
@db.copy_into(:test_copy, :data=>["1\t2\n", "3\t4\n"])
|
|
1974
|
-
@ds.select_map([:x, :y]).must_equal [[1, 2], [3, 4]]
|
|
1975
|
-
end
|
|
1976
|
-
|
|
1977
|
-
it "should have an exception, cause a rollback of copied data and still have a usable connection" do
|
|
1978
|
-
2.times do
|
|
1979
|
-
sent = false
|
|
1980
|
-
proc{@db.copy_into(:test_copy){raise ArgumentError if sent; sent = true; "1\t2\n"}}.must_raise(ArgumentError)
|
|
1981
|
-
@ds.select_map([:x, :y]).must_equal []
|
|
1982
|
-
end
|
|
1983
|
-
end
|
|
1984
|
-
|
|
1985
|
-
it "should handle database errors with a rollback of copied data and still have a usable connection" do
|
|
1986
|
-
2.times do
|
|
1987
|
-
proc{@db.copy_into(:test_copy, :data=>["1\t2\n", "3\ta\n"])}.must_raise(Sequel::DatabaseError)
|
|
1988
|
-
@ds.select_map([:x, :y]).must_equal []
|
|
1989
|
-
end
|
|
1990
|
-
end
|
|
1991
|
-
|
|
1992
|
-
it "should raise an Error if both :data and a block are provided" do
|
|
1993
|
-
proc{@db.copy_into(:test_copy, :data=>["1\t2\n", "3\t4\n"]){}}.must_raise(Sequel::Error)
|
|
1994
|
-
end
|
|
1995
|
-
|
|
1996
|
-
it "should raise an Error if neither :data or a block are provided" do
|
|
1997
|
-
proc{@db.copy_into(:test_copy)}.must_raise(Sequel::Error)
|
|
1998
|
-
end
|
|
1999
|
-
end
|
|
2000
|
-
|
|
2001
|
-
describe "Postgres::Database#copy_into using UTF-8 encoding" do
|
|
2002
|
-
before(:all) do
|
|
2003
|
-
@db = DB
|
|
2004
|
-
@db.create_table!(:test_copy){String :t}
|
|
2005
|
-
@ds = @db[:test_copy].order(:t)
|
|
2006
|
-
end
|
|
2007
|
-
before do
|
|
2008
|
-
@db[:test_copy].delete
|
|
2009
|
-
end
|
|
2010
|
-
after(:all) do
|
|
2011
|
-
@db.drop_table?(:test_copy)
|
|
2012
|
-
end
|
|
2013
|
-
|
|
2014
|
-
it "should work with UTF-8 characters using the :data option" do
|
|
2015
|
-
@db.copy_into(:test_copy, :data=>(["\u00E4\n"]*2))
|
|
2016
|
-
@ds.select_map([:t]).map{|a| a.map{|s| s.force_encoding('UTF-8')}}.must_equal([["\u00E4"]] * 2)
|
|
2017
|
-
end
|
|
2018
|
-
|
|
2019
|
-
it "should work with UTF-8 characters using a block" do
|
|
2020
|
-
buf = (["\u00E4\n"]*2)
|
|
2021
|
-
@db.copy_into(:test_copy){buf.shift}
|
|
2022
|
-
@ds.select_map([:t]).map{|a| a.map{|s| s.force_encoding('UTF-8')}}.must_equal([["\u00E4"]] * 2)
|
|
2023
|
-
end
|
|
2024
|
-
end
|
|
2025
|
-
|
|
2026
|
-
describe "Postgres::Database#copy_table" do
|
|
2027
|
-
before(:all) do
|
|
2028
|
-
@db = DB
|
|
2029
|
-
@db.create_table!(:test_copy){Integer :x; Integer :y}
|
|
2030
|
-
ds = @db[:test_copy]
|
|
2031
|
-
ds.insert(1, 2)
|
|
2032
|
-
ds.insert(3, 4)
|
|
2033
|
-
end
|
|
2034
|
-
after(:all) do
|
|
2035
|
-
@db.drop_table?(:test_copy)
|
|
2036
|
-
end
|
|
2037
|
-
|
|
2038
|
-
it "without a block or options should return a text version of the table as a single string" do
|
|
2039
|
-
@db.copy_table(:test_copy).must_equal "1\t2\n3\t4\n"
|
|
2040
|
-
end
|
|
2041
|
-
|
|
2042
|
-
it "without a block and with :format=>:csv should return a csv version of the table as a single string" do
|
|
2043
|
-
@db.copy_table(:test_copy, :format=>:csv).must_equal "1,2\n3,4\n"
|
|
2044
|
-
end
|
|
2045
|
-
|
|
2046
|
-
it "should treat string as SQL code" do
|
|
2047
|
-
@db.copy_table('COPY "test_copy" TO STDOUT').must_equal "1\t2\n3\t4\n"
|
|
2048
|
-
end
|
|
2049
|
-
|
|
2050
|
-
it "should respect given :options options" do
|
|
2051
|
-
@db.copy_table(:test_copy, :options=>"FORMAT csv, HEADER TRUE").must_equal "x,y\n1,2\n3,4\n"
|
|
2052
|
-
end
|
|
2053
|
-
|
|
2054
|
-
it "should respect given :options options when :format is used" do
|
|
2055
|
-
@db.copy_table(:test_copy, :format=>:csv, :options=>"QUOTE '''', FORCE_QUOTE *").must_equal "'1','2'\n'3','4'\n"
|
|
2056
|
-
end
|
|
2057
|
-
|
|
2058
|
-
it "should accept dataset as first argument" do
|
|
2059
|
-
@db.copy_table(@db[:test_copy].cross_join(Sequel[:test_copy].as(:tc)).order(Sequel[:test_copy][:x], Sequel[:test_copy][:y], Sequel[:tc][:x], Sequel[:tc][:y])).must_equal "1\t2\t1\t2\n1\t2\t3\t4\n3\t4\t1\t2\n3\t4\t3\t4\n"
|
|
2060
|
-
end
|
|
2061
|
-
|
|
2062
|
-
it "with a block and no options should yield each row as a string in text format" do
|
|
2063
|
-
buf = []
|
|
2064
|
-
@db.copy_table(:test_copy){|b| buf << b}
|
|
2065
|
-
buf.must_equal ["1\t2\n", "3\t4\n"]
|
|
2066
|
-
end
|
|
2067
|
-
|
|
2068
|
-
it "with a block and :format=>:csv should yield each row as a string in csv format" do
|
|
2069
|
-
buf = []
|
|
2070
|
-
@db.copy_table(:test_copy, :format=>:csv){|b| buf << b}
|
|
2071
|
-
buf.must_equal ["1,2\n", "3,4\n"]
|
|
2072
|
-
end
|
|
2073
|
-
|
|
2074
|
-
it "should work fine when using a block that is terminated early with a following copy_table" do
|
|
2075
|
-
buf = []
|
|
2076
|
-
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.must_raise(Sequel::DatabaseDisconnectError)
|
|
2077
|
-
buf.must_equal ["1,2\n"]
|
|
2078
|
-
buf.clear
|
|
2079
|
-
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.must_raise(Sequel::DatabaseDisconnectError)
|
|
2080
|
-
buf.must_equal ["1,2\n"]
|
|
2081
|
-
buf.clear
|
|
2082
|
-
@db.copy_table(:test_copy){|b| buf << b}
|
|
2083
|
-
buf.must_equal ["1\t2\n", "3\t4\n"]
|
|
2084
|
-
end
|
|
2085
|
-
|
|
2086
|
-
it "should work fine when using a block that is terminated early with a following regular query" do
|
|
2087
|
-
buf = []
|
|
2088
|
-
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.must_raise(Sequel::DatabaseDisconnectError)
|
|
2089
|
-
buf.must_equal ["1,2\n"]
|
|
2090
|
-
buf.clear
|
|
2091
|
-
proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.must_raise(Sequel::DatabaseDisconnectError)
|
|
2092
|
-
buf.must_equal ["1,2\n"]
|
|
2093
|
-
@db[:test_copy].select_order_map(:x).must_equal [1, 3]
|
|
2094
|
-
end
|
|
2095
|
-
|
|
2096
|
-
it "should not swallow error raised by block" do
|
|
2097
|
-
begin
|
|
2098
|
-
@db.copy_table(:test_copy){|b| raise ArgumentError, "foo"}
|
|
2099
|
-
rescue => e
|
|
2100
|
-
end
|
|
2101
|
-
|
|
2102
|
-
e.must_be_kind_of Sequel::DatabaseDisconnectError
|
|
2103
|
-
e.wrapped_exception.must_be_kind_of ArgumentError
|
|
2104
|
-
e.message.must_include "foo"
|
|
2105
|
-
end
|
|
2106
|
-
|
|
2107
|
-
it "should handle errors raised during row processing" do
|
|
2108
|
-
proc{@db.copy_table(@db[:test_copy].select(Sequel[1]/(Sequel[:x] - 3)))}.must_raise Sequel::DatabaseError
|
|
2109
|
-
@db.get(1).must_equal 1
|
|
2110
|
-
end
|
|
2111
|
-
end
|
|
2112
|
-
end
|
|
2113
|
-
|
|
2114
|
-
if uses_pg && DB.server_version >= 90000
|
|
2115
|
-
describe "Postgres::Database LISTEN/NOTIFY" do
|
|
2116
|
-
before(:all) do
|
|
2117
|
-
@db = DB
|
|
2118
|
-
end
|
|
2119
|
-
|
|
2120
|
-
it "should support listen and notify" do
|
|
2121
|
-
notify_pid = @db.synchronize{|conn| conn.backend_pid}
|
|
2122
|
-
|
|
2123
|
-
called = false
|
|
2124
|
-
@db.listen('foo', :after_listen=>proc{@db.notify('foo')}) do |ev, pid, payload|
|
|
2125
|
-
ev.must_equal 'foo'
|
|
2126
|
-
pid.must_equal notify_pid
|
|
2127
|
-
['', nil].must_include(payload)
|
|
2128
|
-
called = true
|
|
2129
|
-
end.must_equal 'foo'
|
|
2130
|
-
called.must_equal true
|
|
2131
|
-
|
|
2132
|
-
# Check weird identifier names
|
|
2133
|
-
called = false
|
|
2134
|
-
@db.listen('FOO bar', :after_listen=>proc{@db.notify('FOO bar')}) do |ev, pid, payload|
|
|
2135
|
-
ev.must_equal 'FOO bar'
|
|
2136
|
-
pid.must_equal notify_pid
|
|
2137
|
-
['', nil].must_include(payload)
|
|
2138
|
-
called = true
|
|
2139
|
-
end.must_equal 'FOO bar'
|
|
2140
|
-
called.must_equal true
|
|
2141
|
-
|
|
2142
|
-
# Check identifier symbols
|
|
2143
|
-
called = false
|
|
2144
|
-
@db.listen(:foo, :after_listen=>proc{@db.notify(:foo)}) do |ev, pid, payload|
|
|
2145
|
-
ev.must_equal 'foo'
|
|
2146
|
-
pid.must_equal notify_pid
|
|
2147
|
-
['', nil].must_include(payload)
|
|
2148
|
-
called = true
|
|
2149
|
-
end.must_equal 'foo'
|
|
2150
|
-
called.must_equal true
|
|
2151
|
-
|
|
2152
|
-
called = false
|
|
2153
|
-
@db.listen('foo', :after_listen=>proc{@db.notify('foo', :payload=>'bar')}) do |ev, pid, payload|
|
|
2154
|
-
ev.must_equal 'foo'
|
|
2155
|
-
pid.must_equal notify_pid
|
|
2156
|
-
payload.must_equal 'bar'
|
|
2157
|
-
called = true
|
|
2158
|
-
end.must_equal 'foo'
|
|
2159
|
-
called.must_equal true
|
|
2160
|
-
|
|
2161
|
-
@db.listen('foo', :after_listen=>proc{@db.notify('foo')}).must_equal 'foo'
|
|
2162
|
-
|
|
2163
|
-
called = false
|
|
2164
|
-
called2 = false
|
|
2165
|
-
i = 0
|
|
2166
|
-
@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|
|
|
2167
|
-
if !called
|
|
2168
|
-
ev.must_equal 'foo'
|
|
2169
|
-
pid.must_equal notify_pid
|
|
2170
|
-
payload.must_equal 'bar'
|
|
2171
|
-
called = true
|
|
2172
|
-
else
|
|
2173
|
-
ev.must_equal 'bar'
|
|
2174
|
-
pid.must_equal notify_pid
|
|
2175
|
-
payload.must_equal 'foo'
|
|
2176
|
-
called2 = true
|
|
2177
|
-
break
|
|
2178
|
-
end
|
|
2179
|
-
end.must_be_nil
|
|
2180
|
-
called.must_equal true
|
|
2181
|
-
called2.must_equal true
|
|
2182
|
-
i.must_equal 1
|
|
2183
|
-
end
|
|
2184
|
-
|
|
2185
|
-
it "should accept a :timeout option in listen" do
|
|
2186
|
-
@db.listen('foo2', :timeout=>0.001).must_be_nil
|
|
2187
|
-
called = false
|
|
2188
|
-
@db.listen('foo2', :timeout=>0.001){|ev, pid, payload| called = true}.must_be_nil
|
|
2189
|
-
called.must_equal false
|
|
2190
|
-
i = 0
|
|
2191
|
-
@db.listen('foo2', :timeout=>0.001, :loop=>proc{i+=1; throw :stop if i > 3}){|ev, pid, payload| called = true}.must_be_nil
|
|
2192
|
-
i.must_equal 4
|
|
2193
|
-
|
|
2194
|
-
called = false
|
|
2195
|
-
i = 0
|
|
2196
|
-
@db.listen('foo2', :timeout=>proc{i+=1; 0.001}){|ev, pid, payload| called = true}.must_be_nil
|
|
2197
|
-
called.must_equal false
|
|
2198
|
-
i.must_equal 1
|
|
2199
|
-
|
|
2200
|
-
i = 0
|
|
2201
|
-
t = 0
|
|
2202
|
-
@db.listen('foo2', :timeout=>proc{t+=1; 0.001}, :loop=>proc{i+=1; throw :stop if i > 3}){|ev, pid, payload| called = true}.must_be_nil
|
|
2203
|
-
called.must_equal false
|
|
2204
|
-
t.must_equal 4
|
|
2205
|
-
|
|
2206
|
-
end unless RUBY_PLATFORM =~ /mingw/ # Ruby freezes on this spec on this platform/version
|
|
2207
|
-
end
|
|
2208
|
-
end
|
|
2209
|
-
|
|
2210
|
-
describe 'PostgreSQL special float handling' do
|
|
2211
|
-
before do
|
|
2212
|
-
@db = DB
|
|
2213
|
-
@db.create_table!(:test5){Float :value}
|
|
2214
|
-
@ds = @db[:test5]
|
|
2215
|
-
end
|
|
2216
|
-
after do
|
|
2217
|
-
@db.drop_table?(:test5)
|
|
2218
|
-
end
|
|
2219
|
-
|
|
2220
|
-
it 'inserts NaN' do
|
|
2221
|
-
nan = 0.0/0.0
|
|
2222
|
-
@ds.insert(:value=>nan)
|
|
2223
|
-
@ds.all[0][:value].nan?.must_equal true
|
|
2224
|
-
end
|
|
2225
|
-
|
|
2226
|
-
it 'inserts +Infinity' do
|
|
2227
|
-
inf = 1.0/0.0
|
|
2228
|
-
@ds.insert(:value=>inf)
|
|
2229
|
-
@ds.all[0][:value].infinite?.must_be :>, 0
|
|
2230
|
-
end
|
|
2231
|
-
|
|
2232
|
-
it 'inserts -Infinity' do
|
|
2233
|
-
inf = -1.0/0.0
|
|
2234
|
-
@ds.insert(:value=>inf)
|
|
2235
|
-
@ds.all[0][:value].infinite?.must_be :<, 0
|
|
2236
|
-
end
|
|
2237
|
-
end if DB.adapter_scheme == :postgres
|
|
2238
|
-
|
|
2239
|
-
describe 'PostgreSQL array handling' do
|
|
2240
|
-
before(:all) do
|
|
2241
|
-
@db = DB
|
|
2242
|
-
@ds = @db[:items]
|
|
2243
|
-
@tp = lambda{@db.schema(:items).map{|a| a.last[:type]}}
|
|
2244
|
-
end
|
|
2245
|
-
after do
|
|
2246
|
-
@db.drop_table?(:items)
|
|
2247
|
-
end
|
|
2248
|
-
|
|
2249
|
-
it 'insert and retrieve integer and float arrays of various sizes' do
|
|
2250
|
-
@db.create_table!(:items) do
|
|
2251
|
-
column :i2, 'int2[]'
|
|
2252
|
-
column :i4, 'int4[]'
|
|
2253
|
-
column :i8, 'int8[]'
|
|
2254
|
-
column :r, 'real[]'
|
|
2255
|
-
column :dp, 'double precision[]'
|
|
2256
|
-
end
|
|
2257
|
-
@tp.call.must_equal [:smallint_array, :integer_array, :bigint_array, :real_array, :float_array]
|
|
2258
|
-
@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"))
|
|
2259
|
-
@ds.count.must_equal 1
|
|
2260
|
-
rs = @ds.all
|
|
2261
|
-
rs.must_equal [{:i2=>[1], :i4=>[nil, 2], :i8=>[3, nil], :r=>[4.0, nil, 4.5], :dp=>[5.0, nil, 5.5]}]
|
|
2262
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2263
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2264
|
-
@ds.delete
|
|
2265
|
-
@ds.insert(rs.first)
|
|
2266
|
-
@ds.all.must_equal rs
|
|
2267
|
-
|
|
2268
|
-
@ds.delete
|
|
2269
|
-
@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"))
|
|
2270
|
-
|
|
2271
|
-
rs = @ds.all
|
|
2272
|
-
rs.must_equal [{: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]]}]
|
|
2273
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2274
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2275
|
-
@ds.delete
|
|
2276
|
-
@ds.insert(rs.first)
|
|
2277
|
-
@ds.all.must_equal rs
|
|
2278
|
-
end
|
|
2279
|
-
|
|
2280
|
-
it 'insert and retrieve decimal arrays' do
|
|
2281
|
-
@db.create_table!(:items) do
|
|
2282
|
-
column :n, 'numeric[]'
|
|
2283
|
-
end
|
|
2284
|
-
@tp.call.must_equal [:decimal_array]
|
|
2285
|
-
@ds.insert(Sequel.pg_array([BigDecimal('1.000000000000000000001'), nil, BigDecimal('1')], :numeric))
|
|
2286
|
-
@ds.count.must_equal 1
|
|
2287
|
-
rs = @ds.all
|
|
2288
|
-
rs.must_equal [{:n=>[BigDecimal('1.000000000000000000001'), nil, BigDecimal('1')]}]
|
|
2289
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2290
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2291
|
-
@ds.delete
|
|
2292
|
-
@ds.insert(rs.first)
|
|
2293
|
-
@ds.all.must_equal rs
|
|
2294
|
-
|
|
2295
|
-
@ds.delete
|
|
2296
|
-
@ds.insert(Sequel.pg_array([[BigDecimal('1.0000000000000000000000000000001'), nil], [nil, BigDecimal('1')]], :numeric))
|
|
2297
|
-
rs = @ds.all
|
|
2298
|
-
rs.must_equal [{:n=>[[BigDecimal('1.0000000000000000000000000000001'), nil], [nil, BigDecimal('1')]]}]
|
|
2299
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2300
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2301
|
-
@ds.delete
|
|
2302
|
-
@ds.insert(rs.first)
|
|
2303
|
-
@ds.all.must_equal rs
|
|
2304
|
-
end
|
|
2305
|
-
|
|
2306
|
-
it 'insert and retrieve string arrays' do
|
|
2307
|
-
@db.create_table!(:items) do
|
|
2308
|
-
column :c, 'char(4)[]'
|
|
2309
|
-
column :vc, 'varchar[]'
|
|
2310
|
-
column :t, 'text[]'
|
|
2311
|
-
end
|
|
2312
|
-
@tp.call.must_equal [:character_array, :varchar_array, :string_array]
|
|
2313
|
-
@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))
|
|
2314
|
-
@ds.count.must_equal 1
|
|
2315
|
-
rs = @ds.all
|
|
2316
|
-
rs.must_equal [{:c=>['a ', nil, 'NULL', 'b"\'c'], :vc=>['a', nil, 'NULL', 'b"\'c', '', ''], :t=>['a', nil, 'NULL', 'b"\'c']}]
|
|
2317
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2318
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2319
|
-
@ds.delete
|
|
2320
|
-
@ds.insert(rs.first)
|
|
2321
|
-
@ds.all.must_equal rs
|
|
2322
|
-
|
|
2323
|
-
@ds.delete
|
|
2324
|
-
@ds.insert(Sequel.pg_array([[['a'], [nil]], [['NULL'], ['b"\'c']]], 'char(4)'), Sequel.pg_array([[['a[],\\[\\]\\,\\""NULL",'], ['']], [['NULL'], ['b"\'c']]], :varchar), Sequel.pg_array([[['a'], [nil]], [['NULL'], ['b"\'c']]], :text))
|
|
2325
|
-
rs = @ds.all
|
|
2326
|
-
rs.must_equal [{:c=>[[['a '], [nil]], [['NULL'], ['b"\'c']]], :vc=>[[['a[],\\[\\]\\,\\""NULL",'], ['']], [['NULL'], ['b"\'c']]], :t=>[[['a'], [nil]], [['NULL'], ['b"\'c']]]}]
|
|
2327
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2328
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2329
|
-
@ds.delete
|
|
2330
|
-
@ds.insert(rs.first)
|
|
2331
|
-
@ds.all.must_equal rs
|
|
2332
|
-
end
|
|
2333
|
-
|
|
2334
|
-
it 'insert and retrieve arrays of other types' do
|
|
2335
|
-
@db.create_table!(:items) do
|
|
2336
|
-
column :b, 'bool[]'
|
|
2337
|
-
column :d, 'date[]'
|
|
2338
|
-
column :t, 'time[]'
|
|
2339
|
-
column :ts, 'timestamp[]'
|
|
2340
|
-
column :tstz, 'timestamptz[]'
|
|
2341
|
-
end
|
|
2342
|
-
@tp.call.must_equal [:boolean_array, :date_array, :time_array, :datetime_array, :datetime_timezone_array]
|
|
2343
|
-
|
|
2344
|
-
d = Date.today
|
|
2345
|
-
t = Sequel::SQLTime.create(10, 20, 30)
|
|
2346
|
-
ts = Time.local(2011, 1, 2, 3, 4, 5)
|
|
2347
|
-
|
|
2348
|
-
@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))
|
|
2349
|
-
@ds.count.must_equal 1
|
|
2350
|
-
rs = @ds.all
|
|
2351
|
-
rs.must_equal [{:b=>[true, false], :d=>[d, nil], :t=>[t, nil], :ts=>[ts, nil], :tstz=>[ts, nil]}]
|
|
2352
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2353
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2354
|
-
@ds.delete
|
|
2355
|
-
@ds.insert(rs.first)
|
|
2356
|
-
@ds.all.must_equal rs
|
|
2357
|
-
|
|
2358
|
-
@db.create_table!(:items) do
|
|
2359
|
-
column :ba, 'bytea[]'
|
|
2360
|
-
column :tz, 'timetz[]'
|
|
2361
|
-
column :o, 'oid[]'
|
|
2362
|
-
end
|
|
2363
|
-
@tp.call.must_equal [:blob_array, :time_timezone_array, :oid_array]
|
|
2364
|
-
@ds.insert(Sequel.pg_array([Sequel.blob("a\0"), nil], :bytea), Sequel.pg_array([t, nil], :timetz), Sequel.pg_array([1, 2, 3], :oid))
|
|
2365
|
-
@ds.count.must_equal 1
|
|
2366
|
-
rs = @ds.all
|
|
2367
|
-
rs.must_equal [{:ba=>[Sequel.blob("a\0"), nil], :tz=>[t, nil], :o=>[1, 2, 3]}]
|
|
2368
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2369
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2370
|
-
@ds.delete
|
|
2371
|
-
@ds.insert(rs.first)
|
|
2372
|
-
@ds.all.must_equal rs
|
|
2373
|
-
|
|
2374
|
-
@db.create_table!(:items) do
|
|
2375
|
-
column :x, 'xml[]'
|
|
2376
|
-
column :m, 'money[]'
|
|
2377
|
-
column :b, 'bit[]'
|
|
2378
|
-
column :vb, 'bit varying[]'
|
|
2379
|
-
column :u, 'uuid[]'
|
|
2380
|
-
column :xi, 'xid[]'
|
|
2381
|
-
column :c, 'cid[]'
|
|
2382
|
-
column :n, 'name[]'
|
|
2383
|
-
column :o, 'oidvector[]'
|
|
2384
|
-
end
|
|
2385
|
-
@tp.call.must_equal [:xml_array, :money_array, :bit_array, :varbit_array, :uuid_array, :xid_array, :cid_array, :name_array, :oidvector_array]
|
|
2386
|
-
@ds.insert(Sequel.pg_array(['<a></a>'], :xml),
|
|
2387
|
-
Sequel.pg_array(['1'], :money),
|
|
2388
|
-
Sequel.pg_array(['1'], :bit),
|
|
2389
|
-
Sequel.pg_array(['10'], :varbit),
|
|
2390
|
-
Sequel.pg_array(['c0f24910-39e7-11e4-916c-0800200c9a66'], :uuid),
|
|
2391
|
-
Sequel.pg_array(['12'], :xid),
|
|
2392
|
-
Sequel.pg_array(['12'], :cid),
|
|
2393
|
-
Sequel.pg_array(['N'], :name),
|
|
2394
|
-
Sequel.pg_array(['1 2'], :oidvector))
|
|
2395
|
-
@ds.count.must_equal 1
|
|
2396
|
-
rs = @ds.all
|
|
2397
|
-
r = rs.first
|
|
2398
|
-
m = r.delete(:m)
|
|
2399
|
-
m.class.must_equal(Sequel::Postgres::PGArray)
|
|
2400
|
-
m.to_a.must_be_kind_of(Array)
|
|
2401
|
-
m.first.must_be_kind_of(String)
|
|
2402
|
-
r.must_be(:==, :x=>['<a></a>'], :b=>['1'], :vb=>['10'], :u=>['c0f24910-39e7-11e4-916c-0800200c9a66'], :xi=>['12'], :c=>['12'], :n=>['N'], :o=>['1 2'])
|
|
2403
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2404
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2405
|
-
r[:m] = m
|
|
2406
|
-
@ds.delete
|
|
2407
|
-
@ds.insert(r)
|
|
2408
|
-
@ds.all.must_equal rs
|
|
2409
|
-
end
|
|
2410
|
-
|
|
2411
|
-
it 'insert and retrieve empty arrays' do
|
|
2412
|
-
@db.create_table!(:items) do
|
|
2413
|
-
column :n, 'integer[]'
|
|
2414
|
-
end
|
|
2415
|
-
@ds.insert(:n=>Sequel.pg_array([], :integer))
|
|
2416
|
-
@ds.count.must_equal 1
|
|
2417
|
-
rs = @ds.all
|
|
2418
|
-
rs.must_equal [{:n=>[]}]
|
|
2419
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2420
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2421
|
-
@ds.delete
|
|
2422
|
-
@ds.insert(rs.first)
|
|
2423
|
-
@ds.all.must_equal rs
|
|
2424
|
-
end
|
|
2425
|
-
|
|
2426
|
-
it 'convert ruby array :default values' do
|
|
2427
|
-
@db.create_table!(:items) do
|
|
2428
|
-
column :n, 'integer[]', :default=>[]
|
|
2429
|
-
end
|
|
2430
|
-
@ds.insert
|
|
2431
|
-
@ds.count.must_equal 1
|
|
2432
|
-
rs = @ds.all
|
|
2433
|
-
rs.must_equal [{:n=>[]}]
|
|
2434
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2435
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2436
|
-
@ds.delete
|
|
2437
|
-
@ds.insert(rs.first)
|
|
2438
|
-
@ds.all.must_equal rs
|
|
2439
|
-
end
|
|
2440
|
-
|
|
2441
|
-
it 'insert and retrieve custom array types' do
|
|
2442
|
-
point= Class.new do
|
|
2443
|
-
attr_reader :array
|
|
2444
|
-
def initialize(array)
|
|
2445
|
-
@array = array
|
|
2446
|
-
end
|
|
2447
|
-
def sql_literal_append(ds, sql)
|
|
2448
|
-
sql << "'(#{array.join(',')})'"
|
|
2449
|
-
end
|
|
2450
|
-
def ==(other)
|
|
2451
|
-
if other.is_a?(self.class)
|
|
2452
|
-
array == other.array
|
|
2453
|
-
else
|
|
2454
|
-
super
|
|
2455
|
-
end
|
|
2456
|
-
end
|
|
2457
|
-
end
|
|
2458
|
-
@db.register_array_type(:point){|s| point.new(s[1...-1].split(',').map{|i| i.to_i})}
|
|
2459
|
-
@db.create_table!(:items) do
|
|
2460
|
-
column :b, 'point[]'
|
|
2461
|
-
end
|
|
2462
|
-
@tp.call.must_equal [:point_array]
|
|
2463
|
-
pv = point.new([1, 2])
|
|
2464
|
-
@ds.insert(Sequel.pg_array([pv], :point))
|
|
2465
|
-
@ds.count.must_equal 1
|
|
2466
|
-
rs = @ds.all
|
|
2467
|
-
rs.must_equal [{:b=>[pv]}]
|
|
2468
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2469
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2470
|
-
@ds.delete
|
|
2471
|
-
@ds.insert(rs.first)
|
|
2472
|
-
@ds.all.must_equal rs
|
|
2473
|
-
end
|
|
2474
|
-
|
|
2475
|
-
it 'retrieve arrays with explicit bounds' do
|
|
2476
|
-
@db.create_table!(:items) do
|
|
2477
|
-
column :n, 'integer[]'
|
|
2478
|
-
end
|
|
2479
|
-
@ds.insert(:n=>"[0:1]={2,3}")
|
|
2480
|
-
rs = @ds.all
|
|
2481
|
-
rs.must_equal [{:n=>[2,3]}]
|
|
2482
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2483
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2484
|
-
@ds.delete
|
|
2485
|
-
@ds.insert(rs.first)
|
|
2486
|
-
@ds.all.must_equal rs
|
|
2487
|
-
|
|
2488
|
-
@ds.delete
|
|
2489
|
-
@ds.insert(:n=>"[0:1][0:0]={{2},{3}}")
|
|
2490
|
-
rs = @ds.all
|
|
2491
|
-
rs.must_equal [{:n=>[[2], [3]]}]
|
|
2492
|
-
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
|
2493
|
-
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
|
2494
|
-
@ds.delete
|
|
2495
|
-
@ds.insert(rs.first)
|
|
2496
|
-
@ds.all.must_equal rs
|
|
2497
|
-
end
|
|
2498
|
-
|
|
2499
|
-
it 'use arrays in bound variables' do
|
|
2500
|
-
@db.create_table!(:items) do
|
|
2501
|
-
column :i, 'int4[]'
|
|
2502
|
-
end
|
|
2503
|
-
@ds.call(:insert, {:i=>[1,2]}, {:i=>:$i})
|
|
2504
|
-
@ds.get(:i).must_equal [1, 2]
|
|
2505
|
-
@ds.filter(:i=>:$i).call(:first, :i=>[1,2]).must_equal(:i=>[1,2])
|
|
2506
|
-
@ds.filter(:i=>:$i).call(:first, :i=>[1,3]).must_be_nil
|
|
2507
|
-
|
|
2508
|
-
# NULL values
|
|
2509
|
-
@ds.delete
|
|
2510
|
-
@ds.call(:insert, {:i=>[nil,nil]}, {:i=>:$i})
|
|
2511
|
-
@ds.first.must_equal(:i=>[nil, nil])
|
|
2512
|
-
|
|
2513
|
-
@db.create_table!(:items) do
|
|
2514
|
-
column :i, 'text[]'
|
|
2515
|
-
end
|
|
2516
|
-
a = ["\"\\\\\"{}\n\t\r \v\b123afP", 'NULL', nil, '']
|
|
2517
|
-
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a))
|
|
2518
|
-
@ds.get(:i).must_equal a
|
|
2519
|
-
@ds.filter(:i=>:$i).call(:first, :i=>a).must_equal(:i=>a)
|
|
2520
|
-
@ds.filter(:i=>:$i).call(:first, :i=>['', nil, nil, 'a']).must_be_nil
|
|
2521
|
-
|
|
2522
|
-
@db.create_table!(:items) do
|
|
2523
|
-
column :i, 'date[]'
|
|
2524
|
-
end
|
|
2525
|
-
a = [Date.today]
|
|
2526
|
-
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'date'))
|
|
2527
|
-
@ds.get(:i).must_equal a
|
|
2528
|
-
@ds.filter(:i=>:$i).call(:first, :i=>a).must_equal(:i=>a)
|
|
2529
|
-
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([Date.today-1], 'date')).must_be_nil
|
|
2530
|
-
|
|
2531
|
-
@db.create_table!(:items) do
|
|
2532
|
-
column :i, 'timestamp[]'
|
|
2533
|
-
end
|
|
2534
|
-
a = [Time.local(2011, 1, 2, 3, 4, 5)]
|
|
2535
|
-
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'timestamp'))
|
|
2536
|
-
@ds.get(:i).must_equal a
|
|
2537
|
-
@ds.filter(:i=>:$i).call(:first, :i=>a).must_equal(:i=>a)
|
|
2538
|
-
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([a.first-1], 'timestamp')).must_be_nil
|
|
2539
|
-
|
|
2540
|
-
@db.create_table!(:items) do
|
|
2541
|
-
column :i, 'boolean[]'
|
|
2542
|
-
end
|
|
2543
|
-
a = [true, false]
|
|
2544
|
-
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'boolean'))
|
|
2545
|
-
@ds.get(:i).must_equal a
|
|
2546
|
-
@ds.filter(:i=>:$i).call(:first, :i=>a).must_equal(:i=>a)
|
|
2547
|
-
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([false, true], 'boolean')).must_be_nil
|
|
2548
|
-
|
|
2549
|
-
@db.create_table!(:items) do
|
|
2550
|
-
column :i, 'bytea[]'
|
|
2551
|
-
end
|
|
2552
|
-
a = [Sequel.blob("a\0'\"")]
|
|
2553
|
-
@ds.call(:insert, {:i=>:$i}, :i=>Sequel.pg_array(a, 'bytea'))
|
|
2554
|
-
@ds.get(:i).must_equal a
|
|
2555
|
-
@ds.filter(:i=>:$i).call(:first, :i=>a).must_equal(:i=>a)
|
|
2556
|
-
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.pg_array([Sequel.blob("b\0")], 'bytea')).must_be_nil
|
|
2557
|
-
end if uses_pg_or_jdbc
|
|
2558
|
-
|
|
2559
|
-
it 'with models' do
|
|
2560
|
-
@db.create_table!(:items) do
|
|
2561
|
-
primary_key :id
|
|
2562
|
-
column :i, 'integer[]'
|
|
2563
|
-
column :f, 'double precision[]'
|
|
2564
|
-
column :d, 'numeric[]'
|
|
2565
|
-
column :t, 'text[]'
|
|
2566
|
-
end
|
|
2567
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
2568
|
-
h = {:i=>[1,2, nil], :f=>[[1, 2.5], [3, 4.5]], :d=>[1, BigDecimal('1.000000000000000000001')], :t=>[%w'a b c', ['NULL', nil, '1']]}
|
|
2569
|
-
o = c.create(h)
|
|
2570
|
-
o.i.must_equal [1, 2, nil]
|
|
2571
|
-
o.f.must_equal [[1, 2.5], [3, 4.5]]
|
|
2572
|
-
o.d.must_equal [BigDecimal('1'), BigDecimal('1.000000000000000000001')]
|
|
2573
|
-
o.t.must_equal [%w'a b c', ['NULL', nil, '1']]
|
|
2574
|
-
c.where(:i=>o.i, :f=>o.f, :d=>o.d, :t=>o.t).all.must_equal [o]
|
|
2575
|
-
o2 = c.new(h)
|
|
2576
|
-
c.where(:i=>o2.i, :f=>o2.f, :d=>o2.d, :t=>o2.t).all.must_equal [o]
|
|
2577
|
-
|
|
2578
|
-
@db.create_table!(:items) do
|
|
2579
|
-
primary_key :id
|
|
2580
|
-
column :i, 'int2[]'
|
|
2581
|
-
column :f, 'real[]'
|
|
2582
|
-
column :d, 'numeric(30,28)[]'
|
|
2583
|
-
column :t, 'varchar[]'
|
|
2584
|
-
end
|
|
2585
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
2586
|
-
o = c.create(:i=>[1,2, nil], :f=>[[1, 2.5], [3, 4.5]], :d=>[1, BigDecimal('1.000000000000000000001')], :t=>[%w'a b c', ['NULL', nil, '1']])
|
|
2587
|
-
o.i.must_equal [1, 2, nil]
|
|
2588
|
-
o.f.must_equal [[1, 2.5], [3, 4.5]]
|
|
2589
|
-
o.d.must_equal [BigDecimal('1'), BigDecimal('1.000000000000000000001')]
|
|
2590
|
-
o.t.must_equal [%w'a b c', ['NULL', nil, '1']]
|
|
2591
|
-
c.where(:i=>o.i, :f=>o.f, :d=>o.d, :t=>o.t).all.must_equal [o]
|
|
2592
|
-
o2 = c.new(h)
|
|
2593
|
-
c.where(:i=>o2.i, :f=>o2.f, :d=>o2.d, :t=>o2.t).all.must_equal [o]
|
|
2594
|
-
end
|
|
2595
|
-
|
|
2596
|
-
it 'with empty array default values and defaults_setter plugin' do
|
|
2597
|
-
@db.create_table!(:items) do
|
|
2598
|
-
column :n, 'integer[]', :default=>[]
|
|
2599
|
-
end
|
|
2600
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
2601
|
-
c.plugin :defaults_setter, :cache=>true
|
|
2602
|
-
o = c.new
|
|
2603
|
-
o.n.class.must_equal(Sequel::Postgres::PGArray)
|
|
2604
|
-
o.n.to_a.must_be_same_as(o.n.to_a)
|
|
2605
|
-
o.n << 1
|
|
2606
|
-
o.save.n.must_equal [1]
|
|
2607
|
-
end
|
|
2608
|
-
|
|
2609
|
-
it 'operations/functions with pg_array_ops' do
|
|
2610
|
-
Sequel.extension :pg_array_ops
|
|
2611
|
-
@db.create_table!(:items){column :i, 'integer[]'; column :i2, 'integer[]'; column :i3, 'integer[]'; column :i4, 'integer[]'; column :i5, 'integer[]'}
|
|
2612
|
-
@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]))
|
|
2613
|
-
|
|
2614
|
-
@ds.get(Sequel.pg_array(:i) > :i3).must_equal false
|
|
2615
|
-
@ds.get(Sequel.pg_array(:i3) > :i).must_equal true
|
|
2616
|
-
|
|
2617
|
-
@ds.get(Sequel.pg_array(:i) >= :i3).must_equal false
|
|
2618
|
-
@ds.get(Sequel.pg_array(:i) >= :i).must_equal true
|
|
2619
|
-
|
|
2620
|
-
@ds.get(Sequel.pg_array(:i3) < :i).must_equal false
|
|
2621
|
-
@ds.get(Sequel.pg_array(:i) < :i3).must_equal true
|
|
2622
|
-
|
|
2623
|
-
@ds.get(Sequel.pg_array(:i3) <= :i).must_equal false
|
|
2624
|
-
@ds.get(Sequel.pg_array(:i) <= :i).must_equal true
|
|
2625
|
-
|
|
2626
|
-
@ds.get(Sequel.expr(5=>Sequel.pg_array(:i).any)).must_equal false
|
|
2627
|
-
@ds.get(Sequel.expr(1=>Sequel.pg_array(:i).any)).must_equal true
|
|
2628
|
-
|
|
2629
|
-
@ds.get(Sequel.expr(1=>Sequel.pg_array(:i3).all)).must_equal false
|
|
2630
|
-
@ds.get(Sequel.expr(4=>Sequel.pg_array(:i3).all)).must_equal true
|
|
2631
|
-
|
|
2632
|
-
@ds.get(Sequel.expr(1=>Sequel.pg_array(:i)[1..1].any)).must_equal true
|
|
2633
|
-
@ds.get(Sequel.expr(2=>Sequel.pg_array(:i)[1..1].any)).must_equal false
|
|
2634
|
-
|
|
2635
|
-
@ds.get(Sequel.pg_array(:i2)[1]).must_equal 2
|
|
2636
|
-
@ds.get(Sequel.pg_array(:i2)[1]).must_equal 2
|
|
2637
|
-
@ds.get(Sequel.pg_array(:i2)[2]).must_equal 1
|
|
2638
|
-
|
|
2639
|
-
@ds.get(Sequel.pg_array(:i4)[2][1]).must_equal 4
|
|
2640
|
-
@ds.get(Sequel.pg_array(:i4)[2][2]).must_equal 3
|
|
2641
|
-
|
|
2642
|
-
@ds.get(Sequel.pg_array(:i).contains(:i2)).must_equal true
|
|
2643
|
-
@ds.get(Sequel.pg_array(:i).contains(:i3)).must_equal false
|
|
2644
|
-
|
|
2645
|
-
@ds.get(Sequel.pg_array(:i2).contained_by(:i)).must_equal true
|
|
2646
|
-
@ds.get(Sequel.pg_array(:i).contained_by(:i2)).must_equal false
|
|
2647
|
-
|
|
2648
|
-
@ds.get(Sequel.pg_array(:i).overlaps(:i2)).must_equal true
|
|
2649
|
-
@ds.get(Sequel.pg_array(:i2).overlaps(:i3)).must_equal false
|
|
2650
|
-
|
|
2651
|
-
@ds.get(Sequel.pg_array(:i).dims).must_equal '[1:3]'
|
|
2652
|
-
@ds.get(Sequel.pg_array(:i).length).must_equal 3
|
|
2653
|
-
@ds.get(Sequel.pg_array(:i).lower).must_equal 1
|
|
2654
|
-
|
|
2655
|
-
if @db.server_version >= 80400
|
|
2656
|
-
@ds.select(Sequel.pg_array(:i).unnest).from_self.count.must_equal 3
|
|
2657
|
-
end
|
|
2658
|
-
if @db.server_version >= 90000
|
|
2659
|
-
@ds.get(Sequel.pg_array(:i5).join).must_equal '15'
|
|
2660
|
-
@ds.get(Sequel.pg_array(:i5).join(':')).must_equal '1:5'
|
|
2661
|
-
@ds.get(Sequel.pg_array(:i5).join(':', '*')).must_equal '1:*:5'
|
|
2662
|
-
end
|
|
2663
|
-
if @db.server_version >= 90300
|
|
2664
|
-
@ds.get(Sequel.pg_array(:i5).remove(1).length).must_equal 2
|
|
2665
|
-
@ds.get(Sequel.pg_array(:i5).replace(1, 4).contains([1])).must_equal false
|
|
2666
|
-
@ds.get(Sequel.pg_array(:i5).replace(1, 4).contains([4])).must_equal true
|
|
2667
|
-
end
|
|
2668
|
-
if @db.server_version >= 90400
|
|
2669
|
-
@ds.get(Sequel.pg_array(:i).cardinality).must_equal 3
|
|
2670
|
-
@ds.get(Sequel.pg_array(:i4).cardinality).must_equal 4
|
|
2671
|
-
@ds.get(Sequel.pg_array(:i5).cardinality).must_equal 3
|
|
2672
|
-
|
|
2673
|
-
@ds.from{Sequel.pg_array([1,2,3]).op.unnest([4,5,6], [7,8]).as(:t1, [:a, :b, :c])}.select_order_map([:a, :b, :c]).must_equal [[1, 4, 7], [2, 5, 8], [3, 6, nil]]
|
|
2674
|
-
end
|
|
2675
|
-
|
|
2676
|
-
@ds.get(Sequel.pg_array(:i).push(4)).must_equal [1, 2, 3, 4]
|
|
2677
|
-
@ds.get(Sequel.pg_array(:i).unshift(4)).must_equal [4, 1, 2, 3]
|
|
2678
|
-
@ds.get(Sequel.pg_array(:i).concat(:i2)).must_equal [1, 2, 3, 2, 1]
|
|
2679
|
-
|
|
2680
|
-
if @db.type_supported?(:hstore)
|
|
2681
|
-
Sequel.extension :pg_hstore_ops
|
|
2682
|
-
@db.get(Sequel.pg_array(['a', 'b']).op.hstore['a']).must_equal 'b'
|
|
2683
|
-
@db.get(Sequel.pg_array(['a', 'b']).op.hstore(['c', 'd'])['a']).must_equal 'c'
|
|
2684
|
-
end
|
|
2685
|
-
end
|
|
2686
|
-
end
|
|
2687
|
-
|
|
2688
|
-
describe 'PostgreSQL hstore handling' do
|
|
2689
|
-
before(:all) do
|
|
2690
|
-
@db = DB
|
|
2691
|
-
@ds = @db[:items]
|
|
2692
|
-
@h = {'a'=>'b', 'c'=>nil, 'd'=>'NULL', 'e'=>'\\\\" \\\' ,=>'}
|
|
2693
|
-
end
|
|
2694
|
-
after do
|
|
2695
|
-
@db.drop_table?(:items)
|
|
2696
|
-
end
|
|
2697
|
-
|
|
2698
|
-
it 'insert and retrieve hstore values' do
|
|
2699
|
-
@db.create_table!(:items) do
|
|
2700
|
-
column :h, :hstore
|
|
2701
|
-
end
|
|
2702
|
-
@ds.insert(Sequel.hstore(@h))
|
|
2703
|
-
@ds.count.must_equal 1
|
|
2704
|
-
rs = @ds.all
|
|
2705
|
-
v = rs.first[:h]
|
|
2706
|
-
v.must_equal @h
|
|
2707
|
-
v.class.must_equal(Sequel::Postgres::HStore)
|
|
2708
|
-
v.to_hash.must_be_kind_of(Hash)
|
|
2709
|
-
v.to_hash.must_equal @h
|
|
2710
|
-
@ds.delete
|
|
2711
|
-
@ds.insert(rs.first)
|
|
2712
|
-
@ds.all.must_equal rs
|
|
2713
|
-
end
|
|
2714
|
-
|
|
2715
|
-
it 'insert and retrieve hstore[] values' do
|
|
2716
|
-
@db.create_table!(:items) do
|
|
2717
|
-
column :h, 'hstore[]'
|
|
2718
|
-
end
|
|
2719
|
-
@ds.insert(Sequel.pg_array([Sequel.hstore(@h)], :hstore))
|
|
2720
|
-
@ds.count.must_equal 1
|
|
2721
|
-
rs = @ds.all
|
|
2722
|
-
v = rs.first[:h].first
|
|
2723
|
-
v.class.must_equal(Sequel::Postgres::HStore)
|
|
2724
|
-
v.to_hash.must_be_kind_of(Hash)
|
|
2725
|
-
v.to_hash.must_equal @h
|
|
2726
|
-
@ds.delete
|
|
2727
|
-
@ds.insert(rs.first)
|
|
2728
|
-
@ds.all.must_equal rs
|
|
2729
|
-
end
|
|
2730
|
-
|
|
2731
|
-
it 'use hstore in bound variables' do
|
|
2732
|
-
@db.create_table!(:items) do
|
|
2733
|
-
column :i, :hstore
|
|
2734
|
-
end
|
|
2735
|
-
@ds.call(:insert, {:i=>Sequel.hstore(@h)}, {:i=>:$i})
|
|
2736
|
-
@ds.get(:i).must_equal @h
|
|
2737
|
-
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.hstore(@h)).must_equal(:i=>@h)
|
|
2738
|
-
@ds.filter(:i=>:$i).call(:first, :i=>Sequel.hstore({})).must_be_nil
|
|
2739
|
-
|
|
2740
|
-
@ds.delete
|
|
2741
|
-
@ds.call(:insert, {:i=>Sequel.hstore('a'=>nil)}, {:i=>:$i})
|
|
2742
|
-
@ds.get(:i).must_equal Sequel.hstore('a'=>nil)
|
|
2743
|
-
|
|
2744
|
-
@ds.delete
|
|
2745
|
-
@ds.call(:insert, {:i=>@h}, {:i=>:$i})
|
|
2746
|
-
@ds.get(:i).must_equal @h
|
|
2747
|
-
@ds.filter(:i=>:$i).call(:first, :i=>@h).must_equal(:i=>@h)
|
|
2748
|
-
@ds.filter(:i=>:$i).call(:first, :i=>{}).must_be_nil
|
|
2749
|
-
end if uses_pg_or_jdbc
|
|
2750
|
-
|
|
2751
|
-
it 'with models and associations' do
|
|
2752
|
-
@db.create_table!(:items) do
|
|
2753
|
-
primary_key :id
|
|
2754
|
-
column :h, :hstore
|
|
2755
|
-
end
|
|
2756
|
-
c = Class.new(Sequel::Model(@db[:items])) do
|
|
2757
|
-
def self.name
|
|
2758
|
-
'Item'
|
|
2759
|
-
end
|
|
2760
|
-
unrestrict_primary_key
|
|
2761
|
-
def item_id
|
|
2762
|
-
h['item_id'].to_i if h
|
|
2763
|
-
end
|
|
2764
|
-
def left_item_id
|
|
2765
|
-
h['left_item_id'].to_i if h
|
|
2766
|
-
end
|
|
2767
|
-
end
|
|
2768
|
-
Sequel.extension :pg_hstore_ops
|
|
2769
|
-
c.plugin :many_through_many
|
|
2770
|
-
|
|
2771
|
-
h = {'item_id'=>"2", 'left_item_id'=>"1"}
|
|
2772
|
-
o2 = c.create(:id=>2)
|
|
2773
|
-
o = c.create(:id=>1, :h=>h)
|
|
2774
|
-
o.h.must_equal h
|
|
2775
|
-
|
|
2776
|
-
c.many_to_one :item, :class=>c, :key_column=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer)
|
|
2777
|
-
c.one_to_many :items, :class=>c, :key=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer), :key_method=>:item_id
|
|
2778
|
-
c.many_to_many :related_items, :class=>c, :join_table=>Sequel[:items].as(:i), :left_key=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer), :right_key=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer)
|
|
2779
|
-
|
|
2780
|
-
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), :reciprocal=>:other_items
|
|
2781
|
-
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), :reciprocal=>:other_item
|
|
2782
|
-
c.many_to_many :other_related_items, :class=>c, :join_table=>Sequel[:items].as(:i), :left_key=>:id, :right_key=>:id,
|
|
2783
|
-
:left_primary_key_column=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer),
|
|
2784
|
-
:left_primary_key=>:left_item_id,
|
|
2785
|
-
:right_primary_key=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer),
|
|
2786
|
-
:right_primary_key_method=>:left_item_id
|
|
2787
|
-
|
|
2788
|
-
c.many_through_many :mtm_items, [
|
|
2789
|
-
[:items, Sequel.cast(Sequel.hstore(:h)['item_id'], Integer), Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer)],
|
|
2790
|
-
[:items, Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer), Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer)]
|
|
2791
|
-
],
|
|
2792
|
-
:class=>c,
|
|
2793
|
-
:left_primary_key_column=>Sequel.cast(Sequel.hstore(:h)['item_id'], Integer),
|
|
2794
|
-
:left_primary_key=>:item_id,
|
|
2795
|
-
:right_primary_key=>Sequel.cast(Sequel.hstore(:h)['left_item_id'], Integer),
|
|
2796
|
-
:right_primary_key_method=>:left_item_id
|
|
2797
|
-
|
|
2798
|
-
# Lazily Loading
|
|
2799
|
-
o.item.must_equal o2
|
|
2800
|
-
o2.items.must_equal [o]
|
|
2801
|
-
o.related_items.must_equal [o2]
|
|
2802
|
-
o2.other_item.must_equal o
|
|
2803
|
-
o.other_items.must_equal [o2]
|
|
2804
|
-
o.other_related_items.must_equal [o]
|
|
2805
|
-
o.mtm_items.must_equal [o]
|
|
2806
|
-
|
|
2807
|
-
# Eager Loading via eager
|
|
2808
|
-
os = c.eager(:item, :related_items, :other_items, :other_related_items, :mtm_items).where(:id=>1).all.first
|
|
2809
|
-
os.item.must_equal o2
|
|
2810
|
-
os.related_items.must_equal [o2]
|
|
2811
|
-
os.other_items.must_equal [o2]
|
|
2812
|
-
os.other_related_items.must_equal [o]
|
|
2813
|
-
os.mtm_items.must_equal [o]
|
|
2814
|
-
os = c.eager(:items, :other_item).where(:id=>2).all.first
|
|
2815
|
-
os.items.must_equal [o]
|
|
2816
|
-
os.other_item.must_equal o
|
|
2817
|
-
|
|
2818
|
-
# Eager Loading via eager_graph
|
|
2819
|
-
c.eager_graph(:item).where(Sequel[:items][:id]=>1).all.first.item.must_equal o2
|
|
2820
|
-
c.eager_graph(:items).where(Sequel[:items][:id]=>2).all.first.items.must_equal [o]
|
|
2821
|
-
c.eager_graph(:related_items).where(Sequel[:items][:id]=>1).all.first.related_items.must_equal [o2]
|
|
2822
|
-
c.eager_graph(:other_item).where(Sequel[:items][:id]=>2).all.first.other_item.must_equal o
|
|
2823
|
-
c.eager_graph(:other_items).where(Sequel[:items][:id]=>1).all.first.other_items.must_equal [o2]
|
|
2824
|
-
c.eager_graph(:other_related_items).where(Sequel[:items][:id]=>1).all.first.other_related_items.must_equal [o]
|
|
2825
|
-
c.eager_graph(:mtm_items).where(Sequel[:items][:id]=>1).all.first.mtm_items.must_equal [o]
|
|
2826
|
-
|
|
2827
|
-
# Filter By Associations - Model Instances
|
|
2828
|
-
c.filter(:item=>o2).all.must_equal [o]
|
|
2829
|
-
c.filter(:items=>o).all.must_equal [o2]
|
|
2830
|
-
c.filter(:related_items=>o2).all.must_equal [o]
|
|
2831
|
-
c.filter(:other_item=>o).all.must_equal [o2]
|
|
2832
|
-
c.filter(:other_items=>o2).all.must_equal [o]
|
|
2833
|
-
c.filter(:other_related_items=>o).all.must_equal [o]
|
|
2834
|
-
c.filter(:mtm_items=>o).all.must_equal [o]
|
|
2835
|
-
|
|
2836
|
-
# Filter By Associations - Model Datasets
|
|
2837
|
-
c.filter(:item=>c.filter(:id=>o2.id)).all.must_equal [o]
|
|
2838
|
-
c.filter(:items=>c.filter(:id=>o.id)).all.must_equal [o2]
|
|
2839
|
-
c.filter(:related_items=>c.filter(:id=>o2.id)).all.must_equal [o]
|
|
2840
|
-
c.filter(:other_item=>c.filter(:id=>o.id)).all.must_equal [o2]
|
|
2841
|
-
c.filter(:other_items=>c.filter(:id=>o2.id)).all.must_equal [o]
|
|
2842
|
-
c.filter(:other_related_items=>c.filter(:id=>o.id)).all.must_equal [o]
|
|
2843
|
-
c.filter(:mtm_items=>c.filter(:id=>o.id)).all.must_equal [o]
|
|
2844
|
-
end
|
|
2845
|
-
|
|
2846
|
-
it 'with empty hstore default values and defaults_setter plugin' do
|
|
2847
|
-
@db.create_table!(:items) do
|
|
2848
|
-
hstore :h, :default=>Sequel.hstore({})
|
|
2849
|
-
end
|
|
2850
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
2851
|
-
c.plugin :defaults_setter, :cache=>true
|
|
2852
|
-
o = c.new
|
|
2853
|
-
o.h.class.must_equal(Sequel::Postgres::HStore)
|
|
2854
|
-
o.h.to_hash.must_be_same_as(o.h.to_hash)
|
|
2855
|
-
o.h['a'] = 'b'
|
|
2856
|
-
o.save.h.must_equal('a'=>'b')
|
|
2857
|
-
end
|
|
2858
|
-
|
|
2859
|
-
it 'operations/functions with pg_hstore_ops' do
|
|
2860
|
-
Sequel.extension :pg_hstore_ops, :pg_array_ops
|
|
2861
|
-
@db.create_table!(:items){hstore :h1; hstore :h2; hstore :h3; String :t}
|
|
2862
|
-
@ds.insert(Sequel.hstore('a'=>'b', 'c'=>nil), Sequel.hstore('a'=>'b'), Sequel.hstore('d'=>'e'))
|
|
2863
|
-
h1 = Sequel.hstore(:h1)
|
|
2864
|
-
h2 = Sequel.hstore(:h2)
|
|
2865
|
-
h3 = Sequel.hstore(:h3)
|
|
2866
|
-
|
|
2867
|
-
@ds.get(h1['a']).must_equal 'b'
|
|
2868
|
-
@ds.get(h1['d']).must_be_nil
|
|
2869
|
-
|
|
2870
|
-
@ds.get(h2.concat(h3).keys.length).must_equal 2
|
|
2871
|
-
@ds.get(h1.concat(h3).keys.length).must_equal 3
|
|
2872
|
-
@ds.get(h2.merge(h3).keys.length).must_equal 2
|
|
2873
|
-
@ds.get(h1.merge(h3).keys.length).must_equal 3
|
|
2874
|
-
|
|
2875
|
-
@ds.get(h1.contain_all(%w'a c')).must_equal true
|
|
2876
|
-
@ds.get(h1.contain_all(%w'a d')).must_equal false
|
|
2877
|
-
|
|
2878
|
-
@ds.get(h1.contain_any(%w'a d')).must_equal true
|
|
2879
|
-
@ds.get(h1.contain_any(%w'e d')).must_equal false
|
|
2880
|
-
|
|
2881
|
-
@ds.get(h1.contains(h2)).must_equal true
|
|
2882
|
-
@ds.get(h1.contains(h3)).must_equal false
|
|
2883
|
-
|
|
2884
|
-
@ds.get(h2.contained_by(h1)).must_equal true
|
|
2885
|
-
@ds.get(h2.contained_by(h3)).must_equal false
|
|
2886
|
-
|
|
2887
|
-
@ds.get(h1.defined('a')).must_equal true
|
|
2888
|
-
@ds.get(h1.defined('c')).must_equal false
|
|
2889
|
-
@ds.get(h1.defined('d')).must_equal false
|
|
2890
|
-
|
|
2891
|
-
@ds.get(h1.delete('a')['c']).must_be_nil
|
|
2892
|
-
@ds.get(h1.delete(%w'a d')['c']).must_be_nil
|
|
2893
|
-
@ds.get(h1.delete(h2)['c']).must_be_nil
|
|
2894
|
-
|
|
2895
|
-
@ds.from(Sequel.hstore('a'=>'b', 'c'=>nil).op.each).order(:key).all.must_equal [{:key=>'a', :value=>'b'}, {:key=>'c', :value=>nil}]
|
|
2896
|
-
|
|
2897
|
-
@ds.get(h1.has_key?('c')).must_equal true
|
|
2898
|
-
@ds.get(h1.include?('c')).must_equal true
|
|
2899
|
-
@ds.get(h1.key?('c')).must_equal true
|
|
2900
|
-
@ds.get(h1.member?('c')).must_equal true
|
|
2901
|
-
@ds.get(h1.exist?('c')).must_equal true
|
|
2902
|
-
@ds.get(h1.has_key?('d')).must_equal false
|
|
2903
|
-
@ds.get(h1.include?('d')).must_equal false
|
|
2904
|
-
@ds.get(h1.key?('d')).must_equal false
|
|
2905
|
-
@ds.get(h1.member?('d')).must_equal false
|
|
2906
|
-
@ds.get(h1.exist?('d')).must_equal false
|
|
2907
|
-
|
|
2908
|
-
@ds.get(h1.hstore.hstore.hstore.keys.length).must_equal 2
|
|
2909
|
-
@ds.get(h1.keys.length).must_equal 2
|
|
2910
|
-
@ds.get(h2.keys.length).must_equal 1
|
|
2911
|
-
@ds.get(h1.akeys.length).must_equal 2
|
|
2912
|
-
@ds.get(h2.akeys.length).must_equal 1
|
|
2913
|
-
|
|
2914
|
-
@ds.from(Sequel.hstore('t'=>'s').op.populate(Sequel::SQL::Cast.new(nil, :items))).select_map(:t).must_equal ['s']
|
|
2915
|
-
@ds.from(Sequel[:items].as(: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).must_equal ['s']
|
|
2916
|
-
|
|
2917
|
-
@ds.from(Sequel.hstore('t'=>'s', 'a'=>'b').op.skeys.as(:s)).select_order_map(:s).must_equal %w'a t'
|
|
2918
|
-
@ds.from((Sequel.hstore('t'=>'s', 'a'=>'b').op - 'a').skeys.as(:s)).select_order_map(:s).must_equal %w't'
|
|
2919
|
-
|
|
2920
|
-
@ds.get(h1.slice(%w'a c').keys.length).must_equal 2
|
|
2921
|
-
@ds.get(h1.slice(%w'd c').keys.length).must_equal 1
|
|
2922
|
-
@ds.get(h1.slice(%w'd e').keys.length).must_be_nil
|
|
2923
|
-
|
|
2924
|
-
@ds.from(Sequel.hstore('t'=>'s', 'a'=>'b').op.svals.as(:s)).select_order_map(:s).must_equal %w'b s'
|
|
2925
|
-
|
|
2926
|
-
@ds.get(h1.to_array.length).must_equal 4
|
|
2927
|
-
@ds.get(h2.to_array.length).must_equal 2
|
|
2928
|
-
|
|
2929
|
-
@ds.get(h1.to_matrix.length).must_equal 2
|
|
2930
|
-
@ds.get(h2.to_matrix.length).must_equal 1
|
|
2931
|
-
|
|
2932
|
-
@ds.get(h1.values.length).must_equal 2
|
|
2933
|
-
@ds.get(h2.values.length).must_equal 1
|
|
2934
|
-
@ds.get(h1.avals.length).must_equal 2
|
|
2935
|
-
@ds.get(h2.avals.length).must_equal 1
|
|
2936
|
-
end
|
|
2937
|
-
end if DB.type_supported?(:hstore)
|
|
2938
|
-
|
|
2939
|
-
describe 'PostgreSQL json type' do
|
|
2940
|
-
before(:all) do
|
|
2941
|
-
@db = DB
|
|
2942
|
-
@ds = @db[:items]
|
|
2943
|
-
@a = [1, 2, {'a'=>'b'}, 3.0]
|
|
2944
|
-
@h = {'a'=>'b', '1'=>[3, 4, 5]}
|
|
2945
|
-
end
|
|
2946
|
-
after do
|
|
2947
|
-
@db.drop_table?(:items)
|
|
2948
|
-
end
|
|
2949
|
-
|
|
2950
|
-
json_types = [:json]
|
|
2951
|
-
json_types << :jsonb if DB.server_version >= 90400
|
|
2952
|
-
json_types.each do |json_type|
|
|
2953
|
-
json_array_type = "#{json_type}[]"
|
|
2954
|
-
pg_json = lambda{|v| Sequel.send(:"pg_#{json_type}", v)}
|
|
2955
|
-
hash_class = json_type == :jsonb ? Sequel::Postgres::JSONBHash : Sequel::Postgres::JSONHash
|
|
2956
|
-
array_class = json_type == :jsonb ? Sequel::Postgres::JSONBArray : Sequel::Postgres::JSONArray
|
|
2957
|
-
|
|
2958
|
-
it 'insert and retrieve json values' do
|
|
2959
|
-
@db.create_table!(:items){column :j, json_type}
|
|
2960
|
-
@ds.insert(pg_json.call(@h))
|
|
2961
|
-
@ds.count.must_equal 1
|
|
2962
|
-
rs = @ds.all
|
|
2963
|
-
v = rs.first[:j]
|
|
2964
|
-
v.class.must_equal(hash_class)
|
|
2965
|
-
v.to_hash.must_be_kind_of(Hash)
|
|
2966
|
-
v.must_equal @h
|
|
2967
|
-
v.to_hash.must_equal @h
|
|
2968
|
-
@ds.delete
|
|
2969
|
-
@ds.insert(rs.first)
|
|
2970
|
-
@ds.all.must_equal rs
|
|
2971
|
-
|
|
2972
|
-
@ds.delete
|
|
2973
|
-
@ds.insert(pg_json.call(@a))
|
|
2974
|
-
@ds.count.must_equal 1
|
|
2975
|
-
rs = @ds.all
|
|
2976
|
-
v = rs.first[:j]
|
|
2977
|
-
v.class.must_equal(array_class)
|
|
2978
|
-
v.to_a.must_be_kind_of(Array)
|
|
2979
|
-
v.must_equal @a
|
|
2980
|
-
v.to_a.must_equal @a
|
|
2981
|
-
@ds.delete
|
|
2982
|
-
@ds.insert(rs.first)
|
|
2983
|
-
@ds.all.must_equal rs
|
|
2984
|
-
end
|
|
2985
|
-
|
|
2986
|
-
it 'insert and retrieve json[] values' do
|
|
2987
|
-
@db.create_table!(:items){column :j, json_array_type}
|
|
2988
|
-
j = Sequel.pg_array([pg_json.call('a'=>1), pg_json.call(['b', 2])])
|
|
2989
|
-
@ds.insert(j)
|
|
2990
|
-
@ds.count.must_equal 1
|
|
2991
|
-
rs = @ds.all
|
|
2992
|
-
v = rs.first[:j]
|
|
2993
|
-
v.class.must_equal(Sequel::Postgres::PGArray)
|
|
2994
|
-
v.to_a.must_be_kind_of(Array)
|
|
2995
|
-
v.must_equal j
|
|
2996
|
-
v.to_a.must_equal j
|
|
2997
|
-
@ds.delete
|
|
2998
|
-
@ds.insert(rs.first)
|
|
2999
|
-
@ds.all.must_equal rs
|
|
3000
|
-
end
|
|
3001
|
-
|
|
3002
|
-
it 'with models' do
|
|
3003
|
-
@db.create_table!(:items) do
|
|
3004
|
-
primary_key :id
|
|
3005
|
-
column :h, json_type
|
|
3006
|
-
end
|
|
3007
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
3008
|
-
c.create(:h=>pg_json.call(@h)).h.must_equal @h
|
|
3009
|
-
c.create(:h=>pg_json.call(@a)).h.must_equal @a
|
|
3010
|
-
end
|
|
3011
|
-
|
|
3012
|
-
it 'with empty json default values and defaults_setter plugin' do
|
|
3013
|
-
@db.create_table!(:items) do
|
|
3014
|
-
column :h, json_type, :default=>hash_class.new({})
|
|
3015
|
-
column :a, json_type, :default=>array_class.new([])
|
|
3016
|
-
end
|
|
3017
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
3018
|
-
c.plugin :defaults_setter, :cache=>true
|
|
3019
|
-
o = c.new
|
|
3020
|
-
o.h.class.must_equal(hash_class)
|
|
3021
|
-
o.a.class.must_equal(array_class)
|
|
3022
|
-
o.h.to_hash.must_be_same_as(o.h.to_hash)
|
|
3023
|
-
o.a.to_a.must_be_same_as(o.a.to_a)
|
|
3024
|
-
o.h['a'] = 'b'
|
|
3025
|
-
o.a << 1
|
|
3026
|
-
o.save
|
|
3027
|
-
o.h.must_equal('a'=>'b')
|
|
3028
|
-
o.a.must_equal([1])
|
|
3029
|
-
end
|
|
3030
|
-
|
|
3031
|
-
it 'use json in bound variables' do
|
|
3032
|
-
@db.create_table!(:items){column :i, json_type}
|
|
3033
|
-
@ds.call(:insert, {:i=>pg_json.call(@h)}, {:i=>:$i})
|
|
3034
|
-
@ds.get(:i).must_equal @h
|
|
3035
|
-
|
|
3036
|
-
@ds.delete
|
|
3037
|
-
@ds.call(:insert, {:i=>pg_json.call('a'=>nil)}, {:i=>:$i})
|
|
3038
|
-
@ds.get(:i).must_equal pg_json.call('a'=>nil)
|
|
3039
|
-
|
|
3040
|
-
@db.create_table!(:items){column :i, json_array_type}
|
|
3041
|
-
j = Sequel.pg_array([pg_json.call('a'=>1), pg_json.call(['b', 2])], json_type)
|
|
3042
|
-
@ds.call(:insert, {:i=>j}, {:i=>:$i})
|
|
3043
|
-
@ds.get(:i).must_equal j
|
|
3044
|
-
end if uses_pg_or_jdbc
|
|
3045
|
-
|
|
3046
|
-
it 'operations/functions with pg_json_ops' do
|
|
3047
|
-
Sequel.extension :pg_json_ops
|
|
3048
|
-
jo = pg_json.call('a'=>1, 'b'=>{'c'=>2, 'd'=>{'e'=>3}}).op
|
|
3049
|
-
ja = pg_json.call([2, 3, %w'a b']).op
|
|
3050
|
-
|
|
3051
|
-
@db.get(jo['a']).must_equal 1
|
|
3052
|
-
@db.get(jo['b']['c']).must_equal 2
|
|
3053
|
-
@db.get(jo[%w'b c']).must_equal 2
|
|
3054
|
-
@db.get(jo['b'].get_text(%w'd e')).must_equal "3"
|
|
3055
|
-
@db.get(jo[%w'b d'].get_text('e')).must_equal "3"
|
|
3056
|
-
@db.get(ja[1]).must_equal 3
|
|
3057
|
-
@db.get(ja[%w'2 1']).must_equal 'b'
|
|
3058
|
-
|
|
3059
|
-
@db.get(jo.extract('a')).must_equal 1
|
|
3060
|
-
@db.get(jo.extract('b').extract('c')).must_equal 2
|
|
3061
|
-
@db.get(jo.extract('b', 'c')).must_equal 2
|
|
3062
|
-
@db.get(jo.extract('b', 'd', 'e')).must_equal 3
|
|
3063
|
-
@db.get(jo.extract_text('b', 'd')).gsub(' ', '').must_equal '{"e":3}'
|
|
3064
|
-
@db.get(jo.extract_text('b', 'd', 'e')).must_equal '3'
|
|
3065
|
-
|
|
3066
|
-
@db.get(ja.array_length).must_equal 3
|
|
3067
|
-
@db.from(ja.array_elements.as(:v)).select_map(:v).must_equal [2, 3, %w'a b']
|
|
3068
|
-
|
|
3069
|
-
if DB.server_version >= 90400
|
|
3070
|
-
@db.get(jo.typeof).must_equal 'object'
|
|
3071
|
-
@db.get(ja.typeof).must_equal 'array'
|
|
3072
|
-
@db.from(ja.array_elements_text.as(:v)).select_map(:v).map{|s| s.gsub(' ', '')}.must_equal ['2', '3', '["a","b"]']
|
|
3073
|
-
@db.from(jo.to_record.as(:v, [Sequel.lit('a integer'), Sequel.lit('b text')])).select_map(:a).must_equal [1]
|
|
3074
|
-
@db.from(pg_json.call([{'a'=>1, 'b'=>1}]).op.to_recordset.as(:v, [Sequel.lit('a integer'), Sequel.lit('b integer')])).select_map(:a).must_equal [1]
|
|
3075
|
-
|
|
3076
|
-
if json_type == :jsonb
|
|
3077
|
-
@db.get(jo.has_key?('a')).must_equal true
|
|
3078
|
-
@db.get(jo.has_key?('c')).must_equal false
|
|
3079
|
-
@db.get(pg_json.call(['2', '3', %w'a b']).op.include?('2')).must_equal true
|
|
3080
|
-
@db.get(pg_json.call(['2', '3', %w'a b']).op.include?('4')).must_equal false
|
|
3081
|
-
|
|
3082
|
-
@db.get(jo.contain_all(['a', 'b'])).must_equal true
|
|
3083
|
-
@db.get(jo.contain_all(['a', 'c'])).must_equal false
|
|
3084
|
-
@db.get(jo.contain_all(['d', 'c'])).must_equal false
|
|
3085
|
-
@db.get(jo.contain_any(['a', 'b'])).must_equal true
|
|
3086
|
-
@db.get(jo.contain_any(['a', 'c'])).must_equal true
|
|
3087
|
-
@db.get(jo.contain_any(['d', 'c'])).must_equal false
|
|
3088
|
-
|
|
3089
|
-
@db.get(jo.contains(jo)).must_equal true
|
|
3090
|
-
@db.get(jo.contained_by(jo)).must_equal true
|
|
3091
|
-
@db.get(jo.contains('a'=>1)).must_equal true
|
|
3092
|
-
@db.get(jo.contained_by('a'=>1)).must_equal false
|
|
3093
|
-
@db.get(pg_json.call('a'=>1).op.contains(jo)).must_equal false
|
|
3094
|
-
@db.get(pg_json.call('a'=>1).op.contained_by(jo)).must_equal true
|
|
3095
|
-
|
|
3096
|
-
@db.get(ja.contains(ja)).must_equal true
|
|
3097
|
-
@db.get(ja.contained_by(ja)).must_equal true
|
|
3098
|
-
@db.get(ja.contains([2,3])).must_equal true
|
|
3099
|
-
@db.get(ja.contained_by([2,3])).must_equal false
|
|
3100
|
-
@db.get(pg_json.call([2,3]).op.contains(ja)).must_equal false
|
|
3101
|
-
@db.get(pg_json.call([2,3]).op.contained_by(ja)).must_equal true
|
|
3102
|
-
end
|
|
3103
|
-
end
|
|
3104
|
-
|
|
3105
|
-
if DB.server_version >= 90500 && json_type == :jsonb
|
|
3106
|
-
@db.get(pg_json.call([nil, 2]).op.strip_nulls[1]).must_equal 2
|
|
3107
|
-
@db.get(pg_json.call([nil, 2]).op.pretty).must_equal "[\n null,\n 2\n]"
|
|
3108
|
-
@db.from((jo - 'b').keys.as(:k)).select_order_map(:k).must_equal %w'a'
|
|
3109
|
-
@db.from(jo.delete_path(['b','c'])['b'].keys.as(:k)).select_order_map(:k).must_equal %w'd'
|
|
3110
|
-
@db.from(jo.concat('c'=>'d').keys.as(:k)).select_order_map(:k).must_equal %w'a b c'
|
|
3111
|
-
@db.get(jo.set(%w'a', 'f'=>'g')['a']['f']).must_equal 'g'
|
|
3112
|
-
end
|
|
3113
|
-
|
|
3114
|
-
if DB.server_version >= 90600 && json_type == :jsonb
|
|
3115
|
-
@db.get(pg_json.call([3]).op.insert(['0'], {'a'=>2})[0]['a']).must_equal 2
|
|
3116
|
-
@db.get(pg_json.call([3]).op.insert(['0'], {'a'=>2}, false)[0]['a']).must_equal 2
|
|
3117
|
-
@db.get(pg_json.call([3]).op.insert(['0'], {'a'=>2}, true)[0]).must_equal 3
|
|
3118
|
-
@db.get(pg_json.call([3]).op.insert(['0'], {'a'=>2}, true)[1]['a']).must_equal 2
|
|
3119
|
-
end
|
|
3120
|
-
|
|
3121
|
-
@db.from(jo.keys.as(:k)).select_order_map(:k).must_equal %w'a b'
|
|
3122
|
-
@db.from(jo.each).select_order_map(:key).must_equal %w'a b'
|
|
3123
|
-
@db.from(jo.each).order(:key).select_map(:value).must_equal [1, {'c'=>2, 'd'=>{'e'=>3}}]
|
|
3124
|
-
@db.from(jo.each_text).select_order_map(:key).must_equal %w'a b'
|
|
3125
|
-
@db.from(jo.each_text).order(:key).where(:key=>'b').get(:value).gsub(' ', '').must_match(/\{"d":\{"e":3\},"c":2\}|\{"c":2,"d":\{"e":3\}\}/)
|
|
3126
|
-
|
|
3127
|
-
Sequel.extension :pg_row_ops
|
|
3128
|
-
@db.create_table!(:items) do
|
|
3129
|
-
Integer :a
|
|
3130
|
-
String :b
|
|
3131
|
-
end
|
|
3132
|
-
j = Sequel.pg_json('a'=>1, 'b'=>'c').op
|
|
3133
|
-
@db.get(j.populate(Sequel.cast(nil, :items)).pg_row[:a]).must_equal 1
|
|
3134
|
-
@db.get(j.populate(Sequel.cast(nil, :items)).pg_row[:b]).must_equal 'c'
|
|
3135
|
-
j = Sequel.pg_json([{'a'=>1, 'b'=>'c'}, {'a'=>2, 'b'=>'d'}]).op
|
|
3136
|
-
@db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:a).must_equal [1, 2]
|
|
3137
|
-
@db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:b).must_equal %w'c d'
|
|
3138
|
-
end if DB.server_version >= 90300
|
|
3139
|
-
end
|
|
3140
|
-
end if DB.server_version >= 90200
|
|
3141
|
-
|
|
3142
|
-
describe 'PostgreSQL inet/cidr types' do
|
|
3143
|
-
ipv6_broken = (IPAddr.new('::1'); false) rescue true
|
|
3144
|
-
|
|
3145
|
-
before(:all) do
|
|
3146
|
-
@db = DB
|
|
3147
|
-
@ds = @db[:items]
|
|
3148
|
-
@v4 = '127.0.0.1'
|
|
3149
|
-
@v4nm = '127.0.0.0/8'
|
|
3150
|
-
@v6 = '2001:4f8:3:ba:2e0:81ff:fe22:d1f1'
|
|
3151
|
-
@v6nm = '2001:4f8:3:ba::/64'
|
|
3152
|
-
@ipv4 = IPAddr.new(@v4)
|
|
3153
|
-
@ipv4nm = IPAddr.new(@v4nm)
|
|
3154
|
-
unless ipv6_broken
|
|
3155
|
-
@ipv6 = IPAddr.new(@v6)
|
|
3156
|
-
@ipv6nm = IPAddr.new(@v6nm)
|
|
3157
|
-
end
|
|
3158
|
-
end
|
|
3159
|
-
after do
|
|
3160
|
-
@db.drop_table?(:items)
|
|
3161
|
-
end
|
|
3162
|
-
|
|
3163
|
-
it 'insert and retrieve inet/cidr values' do
|
|
3164
|
-
@db.create_table!(:items){inet :i; cidr :c}
|
|
3165
|
-
@ds.insert(@ipv4, @ipv4nm)
|
|
3166
|
-
@ds.count.must_equal 1
|
|
3167
|
-
rs = @ds.all
|
|
3168
|
-
rs.first[:i].must_equal @ipv4
|
|
3169
|
-
rs.first[:c].must_equal @ipv4nm
|
|
3170
|
-
rs.first[:i].must_be_kind_of(IPAddr)
|
|
3171
|
-
rs.first[:c].must_be_kind_of(IPAddr)
|
|
3172
|
-
@ds.delete
|
|
3173
|
-
@ds.insert(rs.first)
|
|
3174
|
-
@ds.all.must_equal rs
|
|
3175
|
-
|
|
3176
|
-
unless ipv6_broken
|
|
3177
|
-
@ds.delete
|
|
3178
|
-
@ds.insert(@ipv6, @ipv6nm)
|
|
3179
|
-
@ds.count.must_equal 1
|
|
3180
|
-
rs = @ds.all
|
|
3181
|
-
rs.first[:j]
|
|
3182
|
-
rs.first[:i].must_equal @ipv6
|
|
3183
|
-
rs.first[:c].must_equal @ipv6nm
|
|
3184
|
-
rs.first[:i].must_be_kind_of(IPAddr)
|
|
3185
|
-
rs.first[:c].must_be_kind_of(IPAddr)
|
|
3186
|
-
@ds.delete
|
|
3187
|
-
@ds.insert(rs.first)
|
|
3188
|
-
@ds.all.must_equal rs
|
|
3189
|
-
end
|
|
3190
|
-
end
|
|
3191
|
-
|
|
3192
|
-
it 'insert and retrieve inet/cidr/macaddr array values' do
|
|
3193
|
-
@db.create_table!(:items){column :i, 'inet[]'; column :c, 'cidr[]'; column :m, 'macaddr[]'}
|
|
3194
|
-
@ds.insert(Sequel.pg_array([@ipv4], 'inet'), Sequel.pg_array([@ipv4nm], 'cidr'), Sequel.pg_array(['12:34:56:78:90:ab'], 'macaddr'))
|
|
3195
|
-
@ds.count.must_equal 1
|
|
3196
|
-
rs = @ds.all
|
|
3197
|
-
rs.first.values.all?{|c| c.is_a?(Sequel::Postgres::PGArray)}.must_equal true
|
|
3198
|
-
rs.first[:i].first.must_equal @ipv4
|
|
3199
|
-
rs.first[:c].first.must_equal @ipv4nm
|
|
3200
|
-
rs.first[:m].first.must_equal '12:34:56:78:90:ab'
|
|
3201
|
-
rs.first[:i].first.must_be_kind_of(IPAddr)
|
|
3202
|
-
rs.first[:c].first.must_be_kind_of(IPAddr)
|
|
3203
|
-
@ds.delete
|
|
3204
|
-
@ds.insert(rs.first)
|
|
3205
|
-
@ds.all.must_equal rs
|
|
3206
|
-
end
|
|
3207
|
-
|
|
3208
|
-
it 'use ipaddr in bound variables' do
|
|
3209
|
-
@db.create_table!(:items){inet :i; cidr :c}
|
|
3210
|
-
|
|
3211
|
-
@ds.call(:insert, {:i=>@ipv4, :c=>@ipv4nm}, {:i=>:$i, :c=>:$c})
|
|
3212
|
-
@ds.get(:i).must_equal @ipv4
|
|
3213
|
-
@ds.get(:c).must_equal @ipv4nm
|
|
3214
|
-
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv4, :c=>@ipv4nm).must_equal(:i=>@ipv4, :c=>@ipv4nm)
|
|
3215
|
-
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv6, :c=>@ipv6nm).must_be_nil
|
|
3216
|
-
@ds.filter(:i=>:$i, :c=>:$c).call(:delete, :i=>@ipv4, :c=>@ipv4nm).must_equal 1
|
|
3217
|
-
|
|
3218
|
-
unless ipv6_broken
|
|
3219
|
-
@ds.call(:insert, {:i=>@ipv6, :c=>@ipv6nm}, {:i=>:$i, :c=>:$c})
|
|
3220
|
-
@ds.get(:i).must_equal @ipv6
|
|
3221
|
-
@ds.get(:c).must_equal @ipv6nm
|
|
3222
|
-
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv6, :c=>@ipv6nm).must_equal(:i=>@ipv6, :c=>@ipv6nm)
|
|
3223
|
-
@ds.filter(:i=>:$i, :c=>:$c).call(:first, :i=>@ipv4, :c=>@ipv4nm).must_be_nil
|
|
3224
|
-
@ds.filter(:i=>:$i, :c=>:$c).call(:delete, :i=>@ipv6, :c=>@ipv6nm).must_equal 1
|
|
3225
|
-
end
|
|
3226
|
-
|
|
3227
|
-
@db.create_table!(:items){column :i, 'inet[]'; column :c, 'cidr[]'; column :m, 'macaddr[]'}
|
|
3228
|
-
@ds.call(:insert, {:i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab']}, {:i=>:$i, :c=>:$c, :m=>:$m})
|
|
3229
|
-
@ds.filter(:i=>:$i, :c=>:$c, :m=>:$m).call(:first, :i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab']).must_equal(:i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab'])
|
|
3230
|
-
@ds.filter(:i=>:$i, :c=>:$c, :m=>:$m).call(:first, :i=>[], :c=>[], :m=>[]).must_be_nil
|
|
3231
|
-
@ds.filter(:i=>:$i, :c=>:$c, :m=>:$m).call(:delete, :i=>[@ipv4], :c=>[@ipv4nm], :m=>['12:34:56:78:90:ab']).must_equal 1
|
|
3232
|
-
end if uses_pg_or_jdbc
|
|
3233
|
-
|
|
3234
|
-
it 'parse default values for schema' do
|
|
3235
|
-
@db.create_table!(:items) do
|
|
3236
|
-
inet :i, :default=>IPAddr.new('127.0.0.1')
|
|
3237
|
-
cidr :c, :default=>IPAddr.new('127.0.0.1')
|
|
3238
|
-
end
|
|
3239
|
-
@db.schema(:items)[0][1][:ruby_default].must_equal IPAddr.new('127.0.0.1')
|
|
3240
|
-
@db.schema(:items)[1][1][:ruby_default].must_equal IPAddr.new('127.0.0.1')
|
|
3241
|
-
end
|
|
3242
|
-
|
|
3243
|
-
it 'with models' do
|
|
3244
|
-
@db.create_table!(:items) do
|
|
3245
|
-
primary_key :id
|
|
3246
|
-
inet :i
|
|
3247
|
-
cidr :c
|
|
3248
|
-
end
|
|
3249
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
3250
|
-
c.create(:i=>@v4, :c=>@v4nm).values.values_at(:i, :c).must_equal [@ipv4, @ipv4nm]
|
|
3251
|
-
unless ipv6_broken
|
|
3252
|
-
c.create(:i=>@ipv6, :c=>@ipv6nm).values.values_at(:i, :c).must_equal [@ipv6, @ipv6nm]
|
|
3253
|
-
end
|
|
3254
|
-
end
|
|
3255
|
-
|
|
3256
|
-
it 'operations/functions with pg_inet_ops' do
|
|
3257
|
-
Sequel.extension :pg_inet_ops
|
|
3258
|
-
|
|
3259
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4') << '1.2.3.0/24').must_equal true
|
|
3260
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4') << '1.2.3.4/32').must_equal false
|
|
3261
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4') << '1.2.2.0/24').must_equal false
|
|
3262
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4').contained_by('1.2.3.0/24')).must_equal true
|
|
3263
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4').contained_by('1.2.3.4/32')).must_equal false
|
|
3264
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4').contained_by('1.2.2.0/24')).must_equal false
|
|
3265
|
-
|
|
3266
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4').contained_by_or_equals('1.2.3.0/24')).must_equal true
|
|
3267
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4').contained_by_or_equals('1.2.3.4/32')).must_equal true
|
|
3268
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4').contained_by_or_equals('1.2.2.0/24')).must_equal false
|
|
3269
|
-
|
|
3270
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24') >> '1.2.3.4').must_equal true
|
|
3271
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24') >> '1.2.2.4').must_equal false
|
|
3272
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24').contains('1.2.3.4')).must_equal true
|
|
3273
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24').contains('1.2.2.4')).must_equal false
|
|
3274
|
-
|
|
3275
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24').contains_or_equals('1.2.3.4')).must_equal true
|
|
3276
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24').contains_or_equals('1.2.2.4')).must_equal false
|
|
3277
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24').contains_or_equals('1.2.3.0/24')).must_equal true
|
|
3278
|
-
|
|
3279
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/32') + 1).must_equal IPAddr.new('1.2.3.1/32')
|
|
3280
|
-
@db.get(Sequel.pg_inet_op('1.2.3.1/32') - 1).must_equal IPAddr.new('1.2.3.0/32')
|
|
3281
|
-
@db.get(Sequel.pg_inet_op('1.2.3.1/32') - '1.2.3.0/32').must_equal 1
|
|
3282
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/32') & '1.2.0.4/32').must_equal IPAddr.new('1.2.0.0/32')
|
|
3283
|
-
@db.get(Sequel.pg_inet_op('1.2.0.0/32') | '0.0.3.4/32').must_equal IPAddr.new('1.2.3.4/32')
|
|
3284
|
-
@db.get(~Sequel.pg_inet_op('0.0.0.0/32')).must_equal IPAddr.new('255.255.255.255/32')
|
|
3285
|
-
|
|
3286
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').abbrev).must_equal '1.2.3.4/24'
|
|
3287
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').broadcast).must_equal IPAddr.new('1.2.3.255/24')
|
|
3288
|
-
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/96').broadcast).must_equal IPAddr.new('1234:3456:5678:789a:9abc:bced::/96')
|
|
3289
|
-
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/128').broadcast).must_equal IPAddr.new('1234:3456:5678:789a:9abc:bced:edf0:f012/128')
|
|
3290
|
-
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/64').broadcast).must_equal IPAddr.new('1234:3456:5678:789a::/64')
|
|
3291
|
-
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/32').broadcast).must_equal IPAddr.new('1234:3456::/32')
|
|
3292
|
-
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/0').broadcast).must_equal IPAddr.new('::/0')
|
|
3293
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').family).must_equal 4
|
|
3294
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').host).must_equal '1.2.3.4'
|
|
3295
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').hostmask).must_equal IPAddr.new('0.0.0.255/32')
|
|
3296
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').masklen).must_equal 24
|
|
3297
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').netmask).must_equal IPAddr.new('255.255.255.0/32')
|
|
3298
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').network).must_equal IPAddr.new('1.2.3.0/24')
|
|
3299
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/24').set_masklen(16)).must_equal IPAddr.new('1.2.3.4/16')
|
|
3300
|
-
@db.get(Sequel.pg_inet_op('1.2.3.4/32').text).must_equal '1.2.3.4/32'
|
|
3301
|
-
|
|
3302
|
-
if @db.server_version >= 90400
|
|
3303
|
-
@db.get(Sequel.pg_inet_op('1.2.3.0/24').contains_or_contained_by('1.2.0.0/16')).must_equal true
|
|
3304
|
-
@db.get(Sequel.pg_inet_op('1.2.0.0/16').contains_or_contained_by('1.2.3.0/24')).must_equal true
|
|
3305
|
-
@db.get(Sequel.pg_inet_op('1.3.0.0/16').contains_or_contained_by('1.2.3.0/24')).must_equal false
|
|
3306
|
-
end
|
|
3307
|
-
end
|
|
3308
|
-
end
|
|
3309
|
-
|
|
3310
|
-
describe 'PostgreSQL custom range types' do
|
|
3311
|
-
after do
|
|
3312
|
-
@db.run "DROP TYPE timerange";
|
|
3313
|
-
end
|
|
3314
|
-
|
|
3315
|
-
it "should allow registration and use" do
|
|
3316
|
-
@db = DB
|
|
3317
|
-
@db.run "CREATE TYPE timerange AS range (subtype = time)"
|
|
3318
|
-
@db.register_range_type('timerange')
|
|
3319
|
-
r = Sequel::SQLTime.create(10, 11, 12)..Sequel::SQLTime.create(11, 12, 13)
|
|
3320
|
-
@db.get(Sequel.pg_range(r, :timerange)).to_range.must_equal r
|
|
3321
|
-
end
|
|
3322
|
-
end if DB.server_version >= 90200
|
|
3323
|
-
|
|
3324
|
-
describe 'PostgreSQL range types' do
|
|
3325
|
-
before(:all) do
|
|
3326
|
-
@db = DB
|
|
3327
|
-
@ds = @db[:items]
|
|
3328
|
-
@map = {:i4=>'int4range', :i8=>'int8range', :n=>'numrange', :d=>'daterange', :t=>'tsrange', :tz=>'tstzrange'}
|
|
3329
|
-
@r = {:i4=>1...2, :i8=>2...3, :n=>BigDecimal('1.0')..BigDecimal('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)}
|
|
3330
|
-
@ra = {}
|
|
3331
|
-
@pgr = {}
|
|
3332
|
-
@pgra = {}
|
|
3333
|
-
@r.each{|k, v| @ra[k] = Sequel.pg_array([v], @map[k])}
|
|
3334
|
-
@r.each{|k, v| @pgr[k] = Sequel.pg_range(v)}
|
|
3335
|
-
@r.each{|k, v| @pgra[k] = Sequel.pg_array([Sequel.pg_range(v)], @map[k])}
|
|
3336
|
-
end
|
|
3337
|
-
after do
|
|
3338
|
-
@db.drop_table?(:items)
|
|
3339
|
-
end
|
|
3340
|
-
|
|
3341
|
-
it 'insert and retrieve range type values' do
|
|
3342
|
-
@db.create_table!(:items){int4range :i4; int8range :i8; numrange :n; daterange :d; tsrange :t; tstzrange :tz}
|
|
3343
|
-
[@r, @pgr].each do |input|
|
|
3344
|
-
h = {}
|
|
3345
|
-
input.each{|k, v| h[k] = Sequel.cast(v, @map[k])}
|
|
3346
|
-
@ds.insert(h)
|
|
3347
|
-
@ds.count.must_equal 1
|
|
3348
|
-
rs = @ds.all
|
|
3349
|
-
rs.first.each do |k, v|
|
|
3350
|
-
v.class.must_equal(Sequel::Postgres::PGRange)
|
|
3351
|
-
v.to_range.must_be_kind_of(Range)
|
|
3352
|
-
v.must_be :==, @r[k]
|
|
3353
|
-
v.to_range.must_equal @r[k]
|
|
3354
|
-
end
|
|
3355
|
-
@ds.delete
|
|
3356
|
-
@ds.insert(rs.first)
|
|
3357
|
-
@ds.all.must_equal rs
|
|
3358
|
-
@ds.delete
|
|
3359
|
-
end
|
|
3360
|
-
end
|
|
3361
|
-
|
|
3362
|
-
it 'insert and retrieve arrays of range type values' do
|
|
3363
|
-
@db.create_table!(:items){column :i4, 'int4range[]'; column :i8, 'int8range[]'; column :n, 'numrange[]'; column :d, 'daterange[]'; column :t, 'tsrange[]'; column :tz, 'tstzrange[]'}
|
|
3364
|
-
[@ra, @pgra].each do |input|
|
|
3365
|
-
@ds.insert(input)
|
|
3366
|
-
@ds.count.must_equal 1
|
|
3367
|
-
rs = @ds.all
|
|
3368
|
-
rs.first.each do |k, v|
|
|
3369
|
-
v.class.must_equal(Sequel::Postgres::PGArray)
|
|
3370
|
-
v.to_a.must_be_kind_of(Array)
|
|
3371
|
-
v.first.class.must_equal(Sequel::Postgres::PGRange)
|
|
3372
|
-
v.first.to_range.must_be_kind_of(Range)
|
|
3373
|
-
v.must_be :==, @ra[k].to_a
|
|
3374
|
-
v.first.must_be :==, @r[k]
|
|
3375
|
-
end
|
|
3376
|
-
@ds.delete
|
|
3377
|
-
@ds.insert(rs.first)
|
|
3378
|
-
@ds.all.must_equal rs
|
|
3379
|
-
@ds.delete
|
|
3380
|
-
end
|
|
3381
|
-
end
|
|
3382
|
-
|
|
3383
|
-
it 'use range types in bound variables' do
|
|
3384
|
-
@db.create_table!(:items){int4range :i4; int8range :i8; numrange :n; daterange :d; tsrange :t; tstzrange :tz}
|
|
3385
|
-
h = {}
|
|
3386
|
-
@r.keys.each{|k| h[k] = :"$#{k}"}
|
|
3387
|
-
r2 = {}
|
|
3388
|
-
@r.each{|k, v| r2[k] = Range.new(v.begin, v.end+2)}
|
|
3389
|
-
@ds.call(:insert, @r, h)
|
|
3390
|
-
@ds.first.must_be :==, @r
|
|
3391
|
-
@ds.filter(h).call(:first, @r).must_be :==, @r
|
|
3392
|
-
@ds.filter(h).call(:first, @pgr).must_be :==, @r
|
|
3393
|
-
@ds.filter(h).call(:first, r2).must_be_nil
|
|
3394
|
-
@ds.filter(h).call(:delete, @r).must_equal 1
|
|
3395
|
-
|
|
3396
|
-
@db.create_table!(:items){column :i4, 'int4range[]'; column :i8, 'int8range[]'; column :n, 'numrange[]'; column :d, 'daterange[]'; column :t, 'tsrange[]'; column :tz, 'tstzrange[]'}
|
|
3397
|
-
@r.each{|k, v| r2[k] = [Range.new(v.begin, v.end+2)]}
|
|
3398
|
-
@ds.call(:insert, @ra, h)
|
|
3399
|
-
@ds.filter(h).call(:first, @ra).each{|k, v| v.must_be :==, @ra[k].to_a}
|
|
3400
|
-
@ds.filter(h).call(:first, @pgra).each{|k, v| v.must_be :==, @ra[k].to_a}
|
|
3401
|
-
@ds.filter(h).call(:first, r2).must_be_nil
|
|
3402
|
-
@ds.filter(h).call(:delete, @ra).must_equal 1
|
|
3403
|
-
end if uses_pg_or_jdbc
|
|
3404
|
-
|
|
3405
|
-
it 'parse default values for schema' do
|
|
3406
|
-
@db.create_table!(:items) do
|
|
3407
|
-
Integer :j
|
|
3408
|
-
int4range :i, :default=>1..4
|
|
3409
|
-
end
|
|
3410
|
-
@db.schema(:items)[0][1][:ruby_default].must_be_nil
|
|
3411
|
-
@db.schema(:items)[1][1][:ruby_default].must_equal Sequel::Postgres::PGRange.new(1, 5, :exclude_end=>true, :db_type=>'int4range')
|
|
3412
|
-
end
|
|
3413
|
-
|
|
3414
|
-
it 'with models' do
|
|
3415
|
-
@db.create_table!(:items){primary_key :id; int4range :i4; int8range :i8; numrange :n; daterange :d; tsrange :t; tstzrange :tz}
|
|
3416
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
3417
|
-
v = c.create(@r).values
|
|
3418
|
-
v.delete(:id)
|
|
3419
|
-
v.must_be :==, @r
|
|
3420
|
-
|
|
3421
|
-
@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[]'}
|
|
3422
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
3423
|
-
v = c.create(@ra).values
|
|
3424
|
-
v.delete(:id)
|
|
3425
|
-
v.each{|k,v1| v1.must_be :==, @ra[k].to_a}
|
|
3426
|
-
end
|
|
3427
|
-
|
|
3428
|
-
it 'works with current_datetime_timestamp extension' do
|
|
3429
|
-
ds = @db.dataset.extension(:current_datetime_timestamp)
|
|
3430
|
-
tsr = ds.get(Sequel.pg_range(ds.current_datetime..ds.current_datetime, :tstzrange))
|
|
3431
|
-
tsr.begin.must_be_kind_of Time
|
|
3432
|
-
tsr.end.must_be_kind_of Time
|
|
3433
|
-
end
|
|
3434
|
-
|
|
3435
|
-
it 'operations/functions with pg_range_ops' do
|
|
3436
|
-
Sequel.extension :pg_range_ops
|
|
3437
|
-
|
|
3438
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.contains(2..4)).must_equal true
|
|
3439
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.contains(3..6)).must_equal false
|
|
3440
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.contains(0..6)).must_equal false
|
|
3441
|
-
|
|
3442
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.contained_by(0..6)).must_equal true
|
|
3443
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.contained_by(3..6)).must_equal false
|
|
3444
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.contained_by(2..4)).must_equal false
|
|
3445
|
-
|
|
3446
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.overlaps(5..6)).must_equal true
|
|
3447
|
-
@db.get(Sequel.pg_range(1...5, :int4range).op.overlaps(5..6)).must_equal false
|
|
3448
|
-
|
|
3449
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(6..10)).must_equal true
|
|
3450
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(5..10)).must_equal false
|
|
3451
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(-1..0)).must_equal false
|
|
3452
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.left_of(-1..3)).must_equal false
|
|
3453
|
-
|
|
3454
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(6..10)).must_equal false
|
|
3455
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(5..10)).must_equal false
|
|
3456
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(-1..0)).must_equal true
|
|
3457
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.right_of(-1..3)).must_equal false
|
|
3458
|
-
|
|
3459
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_before(6..10)).must_equal true
|
|
3460
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_before(5..10)).must_equal true
|
|
3461
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_before(-1..0)).must_equal false
|
|
3462
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_before(-1..3)).must_equal false
|
|
3463
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.ends_before(-1..7)).must_equal true
|
|
3464
|
-
|
|
3465
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_after(6..10)).must_equal false
|
|
3466
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_after(5..10)).must_equal false
|
|
3467
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_after(3..10)).must_equal false
|
|
3468
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_after(-1..10)).must_equal true
|
|
3469
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_after(-1..0)).must_equal true
|
|
3470
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_after(-1..3)).must_equal true
|
|
3471
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.starts_after(-5..-1)).must_equal true
|
|
3472
|
-
|
|
3473
|
-
@db.get(Sequel.pg_range(1..5, :int4range).op.adjacent_to(6..10)).must_equal true
|
|
3474
|
-
@db.get(Sequel.pg_range(1...5, :int4range).op.adjacent_to(6..10)).must_equal false
|
|
3475
|
-
|
|
3476
|
-
@db.get((Sequel.pg_range(1..5, :int4range).op + (6..10)).adjacent_to(6..10)).must_equal false
|
|
3477
|
-
@db.get((Sequel.pg_range(1..5, :int4range).op + (6..10)).adjacent_to(11..20)).must_equal true
|
|
3478
|
-
|
|
3479
|
-
@db.get((Sequel.pg_range(1..5, :int4range).op * (2..6)).adjacent_to(6..10)).must_equal true
|
|
3480
|
-
@db.get((Sequel.pg_range(1..4, :int4range).op * (2..6)).adjacent_to(6..10)).must_equal false
|
|
3481
|
-
|
|
3482
|
-
@db.get((Sequel.pg_range(1..5, :int4range).op - (2..6)).adjacent_to(2..10)).must_equal true
|
|
3483
|
-
@db.get((Sequel.pg_range(0..4, :int4range).op - (3..6)).adjacent_to(4..10)).must_equal false
|
|
3484
|
-
|
|
3485
|
-
@db.get(Sequel.pg_range(0..4, :int4range).op.lower).must_equal 0
|
|
3486
|
-
@db.get(Sequel.pg_range(0..4, :int4range).op.upper).must_equal 5
|
|
3487
|
-
|
|
3488
|
-
@db.get(Sequel.pg_range(0..4, :int4range).op.isempty).must_equal false
|
|
3489
|
-
@db.get(Sequel::Postgres::PGRange.empty(:int4range).op.isempty).must_equal true
|
|
3490
|
-
|
|
3491
|
-
@db.get(Sequel.pg_range(1..5, :numrange).op.lower_inc).must_equal true
|
|
3492
|
-
@db.get(Sequel::Postgres::PGRange.new(1, 5, :exclude_begin=>true, :db_type=>:numrange).op.lower_inc).must_equal false
|
|
3493
|
-
|
|
3494
|
-
@db.get(Sequel.pg_range(1..5, :numrange).op.upper_inc).must_equal true
|
|
3495
|
-
@db.get(Sequel.pg_range(1...5, :numrange).op.upper_inc).must_equal false
|
|
3496
|
-
|
|
3497
|
-
@db.get(Sequel::Postgres::PGRange.new(1, 5, :db_type=>:int4range).op.lower_inf).must_equal false
|
|
3498
|
-
@db.get(Sequel::Postgres::PGRange.new(nil, 5, :db_type=>:int4range).op.lower_inf).must_equal true
|
|
3499
|
-
|
|
3500
|
-
@db.get(Sequel::Postgres::PGRange.new(1, 5, :db_type=>:int4range).op.upper_inf).must_equal false
|
|
3501
|
-
@db.get(Sequel::Postgres::PGRange.new(1, nil, :db_type=>:int4range).op.upper_inf).must_equal true
|
|
3502
|
-
end
|
|
3503
|
-
end if DB.server_version >= 90200
|
|
3504
|
-
|
|
3505
|
-
describe 'PostgreSQL interval types' do
|
|
3506
|
-
before(:all) do
|
|
3507
|
-
@db = DB
|
|
3508
|
-
@ds = @db[:items]
|
|
3509
|
-
end
|
|
3510
|
-
after do
|
|
3511
|
-
@db.drop_table?(:items)
|
|
3512
|
-
end
|
|
3513
|
-
|
|
3514
|
-
it 'insert and retrieve interval values' do
|
|
3515
|
-
@db.create_table!(:items){interval :i}
|
|
3516
|
-
[
|
|
3517
|
-
['0', '00:00:00', 0, []],
|
|
3518
|
-
['1', '00:00:01', 1, [[:seconds, 1]]],
|
|
3519
|
-
['1 microsecond', '00:00:00.000001', 0.000001, [[:seconds, 0.000001]]],
|
|
3520
|
-
['1 millisecond', '00:00:00.001', 0.001, [[:seconds, 0.001]]],
|
|
3521
|
-
['1 second', '00:00:01', 1, [[:seconds, 1]]],
|
|
3522
|
-
['1 minute', '00:01:00', 60, [[:seconds, 60]]],
|
|
3523
|
-
['1 hour', '01:00:00', 3600, [[:seconds, 3600]]],
|
|
3524
|
-
['123000 hours', '123000:00:00', 442800000, [[:seconds, 442800000]]],
|
|
3525
|
-
['1 day', '1 day', 86400, [[:days, 1]]],
|
|
3526
|
-
['1 week', '7 days', 86400*7, [[:days, 7]]],
|
|
3527
|
-
['1 month', '1 mon', 86400*30, [[:months, 1]]],
|
|
3528
|
-
['1 year', '1 year', 31557600, [[:years, 1]]],
|
|
3529
|
-
['1 decade', '10 years', 31557600*10, [[:years, 10]]],
|
|
3530
|
-
['1 century', '100 years', 31557600*100, [[:years, 100]]],
|
|
3531
|
-
['1 millennium', '1000 years', 31557600*1000, [[:years, 1000]]],
|
|
3532
|
-
['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]]],
|
|
3533
|
-
['-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]]],
|
|
3534
|
-
['+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]]],
|
|
3535
|
-
].each do |instr, outstr, value, parts|
|
|
3536
|
-
@ds.insert(instr)
|
|
3537
|
-
@ds.count.must_equal 1
|
|
3538
|
-
@ds.get(Sequel.cast(:i, String)).must_equal outstr
|
|
3539
|
-
rs = @ds.all
|
|
3540
|
-
rs.first[:i].is_a?(ActiveSupport::Duration).must_equal true
|
|
3541
|
-
rs.first[:i].must_equal ActiveSupport::Duration.new(value, parts)
|
|
3542
|
-
rs.first[:i].parts.sort_by{|k,v| k.to_s}.reject{|k,v| v == 0}.must_equal parts.sort_by{|k,v| k.to_s}
|
|
3543
|
-
@ds.delete
|
|
3544
|
-
@ds.insert(rs.first)
|
|
3545
|
-
@ds.all.must_equal rs
|
|
3546
|
-
@ds.delete
|
|
3547
|
-
end
|
|
3548
|
-
end
|
|
3549
|
-
|
|
3550
|
-
it 'insert and retrieve interval array values' do
|
|
3551
|
-
@db.create_table!(:items){column :i, 'interval[]'}
|
|
3552
|
-
@ds.insert(Sequel.pg_array(['1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds'], 'interval'))
|
|
3553
|
-
@ds.count.must_equal 1
|
|
3554
|
-
rs = @ds.all
|
|
3555
|
-
rs.first[:i].is_a?(Sequel::Postgres::PGArray).must_equal true
|
|
3556
|
-
rs.first[:i].first.is_a?(ActiveSupport::Duration).must_equal true
|
|
3557
|
-
rs.first[:i].first.must_equal 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]])
|
|
3558
|
-
rs.first[:i].first.parts.sort_by{|k,v| k.to_s}.must_equal [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]].sort_by{|k,v| k.to_s}
|
|
3559
|
-
@ds.delete
|
|
3560
|
-
@ds.insert(rs.first)
|
|
3561
|
-
@ds.all.must_equal rs
|
|
3562
|
-
end
|
|
3563
|
-
|
|
3564
|
-
it 'use intervals in bound variables' do
|
|
3565
|
-
@db.create_table!(:items){interval :i}
|
|
3566
|
-
@ds.insert('1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds')
|
|
3567
|
-
d = @ds.get(:i)
|
|
3568
|
-
@ds.delete
|
|
3569
|
-
|
|
3570
|
-
@ds.call(:insert, {:i=>d}, {:i=>:$i})
|
|
3571
|
-
@ds.get(:i).must_equal d
|
|
3572
|
-
@ds.filter(:i=>:$i).call(:first, :i=>d).must_equal(:i=>d)
|
|
3573
|
-
@ds.filter(:i=>Sequel.cast(:$i, :interval)).call(:first, :i=>'0').must_be_nil
|
|
3574
|
-
@ds.filter(:i=>:$i).call(:delete, :i=>d).must_equal 1
|
|
3575
|
-
|
|
3576
|
-
@db.create_table!(:items){column :i, 'interval[]'}
|
|
3577
|
-
@ds.call(:insert, {:i=>[d]}, {:i=>:$i})
|
|
3578
|
-
@ds.filter(:i=>:$i).call(:first, :i=>[d]).must_equal(:i=>[d])
|
|
3579
|
-
@ds.filter(:i=>:$i).call(:first, :i=>[]).must_be_nil
|
|
3580
|
-
@ds.filter(:i=>:$i).call(:delete, :i=>[d]).must_equal 1
|
|
3581
|
-
end if uses_pg_or_jdbc
|
|
3582
|
-
|
|
3583
|
-
it 'parse default values for schema' do
|
|
3584
|
-
@db.create_table!(:items) do
|
|
3585
|
-
Integer :j
|
|
3586
|
-
interval :i, :default=>ActiveSupport::Duration.new(3*86400, :days=>3)
|
|
3587
|
-
end
|
|
3588
|
-
@db.schema(:items)[0][1][:ruby_default].must_be_nil
|
|
3589
|
-
@db.schema(:items)[1][1][:ruby_default].must_equal ActiveSupport::Duration.new(3*86400, :days=>3)
|
|
3590
|
-
end
|
|
3591
|
-
|
|
3592
|
-
it 'with models' do
|
|
3593
|
-
@db.create_table!(:items) do
|
|
3594
|
-
primary_key :id
|
|
3595
|
-
interval :i
|
|
3596
|
-
end
|
|
3597
|
-
c = Class.new(Sequel::Model(@db[:items]))
|
|
3598
|
-
v = c.create(:i=>'1 year 2 mons 25 days 05:06:07').i
|
|
3599
|
-
v.is_a?(ActiveSupport::Duration).must_equal true
|
|
3600
|
-
v.must_equal 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]])
|
|
3601
|
-
v.parts.sort_by{|k,_| k.to_s}.must_equal [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]].sort_by{|k,_| k.to_s}
|
|
3602
|
-
end
|
|
3603
|
-
end if (begin require 'active_support/duration'; require 'active_support/inflector'; require 'active_support/core_ext/string/inflections'; true; rescue LoadError; false end)
|
|
3604
|
-
|
|
3605
|
-
describe 'PostgreSQL row-valued/composite types' do
|
|
3606
|
-
before(:all) do
|
|
3607
|
-
@db = DB
|
|
3608
|
-
Sequel.extension :pg_array_ops, :pg_row_ops
|
|
3609
|
-
@ds = @db[:person]
|
|
3610
|
-
|
|
3611
|
-
@db.drop_table?(:company, :person, :address)
|
|
3612
|
-
|
|
3613
|
-
@db.create_table(:address) do
|
|
3614
|
-
String :street
|
|
3615
|
-
String :city
|
|
3616
|
-
String :zip
|
|
3617
|
-
end
|
|
3618
|
-
@db.create_table(:person) do
|
|
3619
|
-
Integer :id
|
|
3620
|
-
address :address
|
|
3621
|
-
end
|
|
3622
|
-
@db.create_table(:company) do
|
|
3623
|
-
Integer :id
|
|
3624
|
-
column :employees, 'person[]'
|
|
3625
|
-
end
|
|
3626
|
-
oids = @db.conversion_procs.keys
|
|
3627
|
-
@db.register_row_type(:address)
|
|
3628
|
-
@db.register_row_type(Sequel.qualify(:public, :person))
|
|
3629
|
-
@db.register_row_type(Sequel[:public][:company])
|
|
3630
|
-
@new_oids = @db.conversion_procs.keys - oids
|
|
3631
|
-
end
|
|
3632
|
-
after(:all) do
|
|
3633
|
-
@new_oids.each{|oid| @db.conversion_procs.delete(oid)}
|
|
3634
|
-
@db.row_types.clear
|
|
3635
|
-
@db.drop_table?(:company, :person, :address)
|
|
3636
|
-
end
|
|
3637
|
-
after do
|
|
3638
|
-
[:company, :person, :address].each{|t| @db[t].delete}
|
|
3639
|
-
end
|
|
3640
|
-
|
|
3641
|
-
it 'insert and retrieve row types' do
|
|
3642
|
-
@ds.insert(:id=>1, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345']))
|
|
3643
|
-
@ds.count.must_equal 1
|
|
3644
|
-
# Single row valued type
|
|
3645
|
-
rs = @ds.all
|
|
3646
|
-
v = rs.first[:address]
|
|
3647
|
-
v.class.superclass.must_equal(Sequel::Postgres::PGRow::HashRow)
|
|
3648
|
-
v.to_hash.must_be_kind_of(Hash)
|
|
3649
|
-
v.to_hash.must_equal(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345')
|
|
3650
|
-
@ds.delete
|
|
3651
|
-
@ds.insert(rs.first)
|
|
3652
|
-
@ds.all.must_equal rs
|
|
3653
|
-
|
|
3654
|
-
# Nested row value type
|
|
3655
|
-
p = @ds.get(:person)
|
|
3656
|
-
p[:id].must_equal 1
|
|
3657
|
-
p[:address].must_equal v
|
|
3658
|
-
end
|
|
3659
|
-
|
|
3660
|
-
it 'insert and retrieve row types containing domains' do
|
|
3661
|
-
begin
|
|
3662
|
-
@db << "DROP DOMAIN IF EXISTS positive_integer CASCADE"
|
|
3663
|
-
@db << "CREATE DOMAIN positive_integer AS integer CHECK (VALUE > 0)"
|
|
3664
|
-
@db.create_table!(:domain_check) do
|
|
3665
|
-
positive_integer :id
|
|
3666
|
-
end
|
|
3667
|
-
@db.register_row_type(:domain_check)
|
|
3668
|
-
@db.get(@db.row_type(:domain_check, [1])).must_equal(:id=>1)
|
|
3669
|
-
@db.register_row_type(Sequel[:public][:domain_check])
|
|
3670
|
-
@db.get(@db.row_type(Sequel[:public][:domain_check], [1])).must_equal(:id=>1)
|
|
3671
|
-
@db.get(@db.row_type(Sequel.qualify(:public, :domain_check), [1])).must_equal(:id=>1)
|
|
3672
|
-
ensure
|
|
3673
|
-
@db.drop_table(:domain_check)
|
|
3674
|
-
@db << "DROP DOMAIN positive_integer"
|
|
3675
|
-
end
|
|
3676
|
-
end
|
|
3677
|
-
|
|
3678
|
-
it 'insert and retrieve arrays of row types' do
|
|
3679
|
-
@ds = @db[:company]
|
|
3680
|
-
@ds.insert(:id=>1, :employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])])]))
|
|
3681
|
-
@ds.count.must_equal 1
|
|
3682
|
-
v = @ds.get(:company)
|
|
3683
|
-
v.class.superclass.must_equal(Sequel::Postgres::PGRow::HashRow)
|
|
3684
|
-
v.to_hash.must_be_kind_of(Hash)
|
|
3685
|
-
v[:id].must_equal 1
|
|
3686
|
-
employees = v[:employees]
|
|
3687
|
-
employees.class.must_equal(Sequel::Postgres::PGArray)
|
|
3688
|
-
employees.to_a.must_be_kind_of(Array)
|
|
3689
|
-
employees.must_equal [{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}]
|
|
3690
|
-
@ds.delete
|
|
3691
|
-
@ds.insert(v[:id], v[:employees])
|
|
3692
|
-
@ds.get(:company).must_equal v
|
|
3693
|
-
end
|
|
3694
|
-
|
|
3695
|
-
it 'use row types in bound variables' do
|
|
3696
|
-
@ds.call(:insert, {:address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])}, {:address=>:$address, :id=>1})
|
|
3697
|
-
@ds.get(:address).must_equal(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345')
|
|
3698
|
-
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345']))[:id].must_equal 1
|
|
3699
|
-
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12356'])).must_be_nil
|
|
3700
|
-
|
|
3701
|
-
@ds.delete
|
|
3702
|
-
@ds.call(:insert, {:address=>Sequel.pg_row([nil, nil, nil])}, {:address=>:$address, :id=>1})
|
|
3703
|
-
@ds.get(:address).must_equal(:street=>nil, :city=>nil, :zip=>nil)
|
|
3704
|
-
end if uses_pg_or_jdbc
|
|
3705
|
-
|
|
3706
|
-
it 'use arrays of row types in bound variables' do
|
|
3707
|
-
@ds = @db[:company]
|
|
3708
|
-
@ds.call(:insert, {:employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])])])}, {:employees=>:$employees, :id=>1})
|
|
3709
|
-
@ds.get(:company).must_equal(:id=>1, :employees=>[{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}])
|
|
3710
|
-
@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].must_equal 1
|
|
3711
|
-
@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'])])])).must_be_nil
|
|
3712
|
-
|
|
3713
|
-
@ds.delete
|
|
3714
|
-
@ds.call(:insert, {:employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row([nil, nil, nil])])])}, {:employees=>:$employees, :id=>1})
|
|
3715
|
-
@ds.get(:employees).must_equal [{:address=>{:city=>nil, :zip=>nil, :street=>nil}, :id=>1}]
|
|
3716
|
-
end if uses_pg_or_jdbc
|
|
3717
|
-
|
|
3718
|
-
it 'operations/functions with pg_row_ops' do
|
|
3719
|
-
@ds.insert(:id=>1, :address=>Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345']))
|
|
3720
|
-
@ds.get(Sequel.pg_row(:address)[:street]).must_equal '123 Sesame St'
|
|
3721
|
-
@ds.get(Sequel.pg_row(:address)[:city]).must_equal 'Somewhere'
|
|
3722
|
-
@ds.get(Sequel.pg_row(:address)[:zip]).must_equal '12345'
|
|
3723
|
-
|
|
3724
|
-
@ds = @db[:company]
|
|
3725
|
-
@ds.insert(:id=>1, :employees=>Sequel.pg_array([@db.row_type(:person, [1, Sequel.pg_row(['123 Sesame St', 'Somewhere', '12345'])])]))
|
|
3726
|
-
@ds.get(Sequel.pg_row(:company)[:id]).must_equal 1
|
|
3727
|
-
@ds.get(Sequel.pg_row(:company)[:employees]).must_equal [{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}]
|
|
3728
|
-
@ds.get(Sequel.pg_row(:company)[:employees][1]).must_equal(:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'})
|
|
3729
|
-
@ds.get(Sequel.pg_row(:company)[:employees][1][:address]).must_equal(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345')
|
|
3730
|
-
@ds.get(Sequel.pg_row(:company)[:employees][1][:id]).must_equal 1
|
|
3731
|
-
@ds.get(Sequel.pg_row(:company)[:employees][1][:address][:street]).must_equal '123 Sesame St'
|
|
3732
|
-
@ds.get(Sequel.pg_row(:company)[:employees][1][:address][:city]).must_equal 'Somewhere'
|
|
3733
|
-
@ds.get(Sequel.pg_row(:company)[:employees][1][:address][:zip]).must_equal '12345'
|
|
3734
|
-
end
|
|
3735
|
-
|
|
3736
|
-
describe "#splat and #*" do
|
|
3737
|
-
before(:all) do
|
|
3738
|
-
@db.create_table!(:a){Integer :a}
|
|
3739
|
-
@db.create_table!(:b){a :b; Integer :a}
|
|
3740
|
-
@db.register_row_type(:a)
|
|
3741
|
-
@db.register_row_type(:b)
|
|
3742
|
-
@db[:b].insert(:a=>1, :b=>@db.row_type(:a, [2]))
|
|
3743
|
-
end
|
|
3744
|
-
after(:all) do
|
|
3745
|
-
@db.drop_table?(:b, :a)
|
|
3746
|
-
end
|
|
3747
|
-
|
|
3748
|
-
it "splat should reference the table type" do
|
|
3749
|
-
@db[:b].select(:a).first.must_equal(:a=>1)
|
|
3750
|
-
@db[:b].select(Sequel[:b][:a]).first.must_equal(:a=>1)
|
|
3751
|
-
@db[:b].select(Sequel.pg_row(:b)[:a]).first.must_equal(:a=>2)
|
|
3752
|
-
@db[:b].select(Sequel.pg_row(:b).splat[:a]).first.must_equal(:a=>1)
|
|
3753
|
-
|
|
3754
|
-
@db[:b].select(:b).first.must_equal(:b=>{:a=>2})
|
|
3755
|
-
@db[:b].select(Sequel.pg_row(:b).splat).first.must_equal(:a=>1, :b=>{:a=>2})
|
|
3756
|
-
@db[:b].select(Sequel.pg_row(:b).splat(:b)).first.must_equal(:b=>{:a=>1, :b=>{:a=>2}})
|
|
3757
|
-
end
|
|
3758
|
-
|
|
3759
|
-
it "* should expand the table type into separate columns" do
|
|
3760
|
-
ds = @db[:b].select(Sequel.pg_row(:b).splat(:b)).from_self(:alias=>:t)
|
|
3761
|
-
ds.first.must_equal(:b=>{:a=>1, :b=>{:a=>2}})
|
|
3762
|
-
ds.select(Sequel.pg_row(:b).*).first.must_equal(:a=>1, :b=>{:a=>2})
|
|
3763
|
-
ds.select(Sequel.pg_row(:b)[:b]).first.must_equal(:b=>{:a=>2})
|
|
3764
|
-
ds.select(Sequel.pg_row(Sequel[:t][:b]).*).first.must_equal(:a=>1, :b=>{:a=>2})
|
|
3765
|
-
ds.select(Sequel.pg_row(Sequel[:t][:b])[:b]).first.must_equal(:b=>{:a=>2})
|
|
3766
|
-
ds.select(Sequel.pg_row(:b)[:a]).first.must_equal(:a=>1)
|
|
3767
|
-
ds.select(Sequel.pg_row(Sequel[:t][:b])[:a]).first.must_equal(:a=>1)
|
|
3768
|
-
end
|
|
3769
|
-
end
|
|
3770
|
-
|
|
3771
|
-
describe "with models" do
|
|
3772
|
-
before(:all) do
|
|
3773
|
-
class Address < Sequel::Model(:address)
|
|
3774
|
-
plugin :pg_row
|
|
3775
|
-
end
|
|
3776
|
-
class Person < Sequel::Model(:person)
|
|
3777
|
-
plugin :pg_row
|
|
3778
|
-
end
|
|
3779
|
-
class Company < Sequel::Model(:company)
|
|
3780
|
-
plugin :pg_row
|
|
3781
|
-
end
|
|
3782
|
-
@a = Address.new(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345')
|
|
3783
|
-
@es = Sequel.pg_array([Person.new(:id=>1, :address=>@a)])
|
|
3784
|
-
end
|
|
3785
|
-
after(:all) do
|
|
3786
|
-
Object.send(:remove_const, :Address) rescue nil
|
|
3787
|
-
Object.send(:remove_const, :Person) rescue nil
|
|
3788
|
-
Object.send(:remove_const, :Company) rescue nil
|
|
3789
|
-
end
|
|
3790
|
-
|
|
3791
|
-
it 'insert and retrieve row types as model objects' do
|
|
3792
|
-
@ds.insert(:id=>1, :address=>@a)
|
|
3793
|
-
@ds.count.must_equal 1
|
|
3794
|
-
# Single row valued type
|
|
3795
|
-
rs = @ds.all
|
|
3796
|
-
v = rs.first[:address]
|
|
3797
|
-
v.must_be_kind_of(Address)
|
|
3798
|
-
v.must_equal @a
|
|
3799
|
-
@ds.delete
|
|
3800
|
-
@ds.insert(rs.first)
|
|
3801
|
-
@ds.all.must_equal rs
|
|
3802
|
-
|
|
3803
|
-
# Nested row value type
|
|
3804
|
-
p = @ds.get(:person)
|
|
3805
|
-
p.must_be_kind_of(Person)
|
|
3806
|
-
p.id.must_equal 1
|
|
3807
|
-
p.address.must_be_kind_of(Address)
|
|
3808
|
-
p.address.must_equal @a
|
|
3809
|
-
end
|
|
3810
|
-
|
|
3811
|
-
it 'insert and retrieve arrays of row types as model objects' do
|
|
3812
|
-
@ds = @db[:company]
|
|
3813
|
-
@ds.insert(:id=>1, :employees=>@es)
|
|
3814
|
-
@ds.count.must_equal 1
|
|
3815
|
-
v = @ds.get(:company)
|
|
3816
|
-
v.must_be_kind_of(Company)
|
|
3817
|
-
v.id.must_equal 1
|
|
3818
|
-
employees = v[:employees]
|
|
3819
|
-
employees.class.must_equal(Sequel::Postgres::PGArray)
|
|
3820
|
-
employees.to_a.must_be_kind_of(Array)
|
|
3821
|
-
employees.must_equal @es
|
|
3822
|
-
@ds.delete
|
|
3823
|
-
@ds.insert(v.id, v.employees)
|
|
3824
|
-
@ds.get(:company).must_equal v
|
|
3825
|
-
end
|
|
3826
|
-
|
|
3827
|
-
it 'use model objects in bound variables' do
|
|
3828
|
-
@ds.call(:insert, {:address=>@a}, {:address=>:$address, :id=>1})
|
|
3829
|
-
@ds.get(:address).must_equal @a
|
|
3830
|
-
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>@a)[:id].must_equal 1
|
|
3831
|
-
@ds.filter(:address=>Sequel.cast(:$address, :address)).call(:first, :address=>Address.new(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12356')).must_be_nil
|
|
3832
|
-
end if uses_pg_or_jdbc
|
|
3833
|
-
|
|
3834
|
-
it 'use arrays of model objects in bound variables' do
|
|
3835
|
-
@ds = @db[:company]
|
|
3836
|
-
@ds.call(:insert, {:employees=>@es}, {:employees=>:$employees, :id=>1})
|
|
3837
|
-
@ds.get(:company).must_equal Company.new(:id=>1, :employees=>@es)
|
|
3838
|
-
@ds.filter(:employees=>Sequel.cast(:$employees, 'person[]')).call(:first, :employees=>@es)[:id].must_equal 1
|
|
3839
|
-
@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'])])])).must_be_nil
|
|
3840
|
-
end if uses_pg_or_jdbc
|
|
3841
|
-
|
|
3842
|
-
it 'model typecasting' do
|
|
3843
|
-
a = Address.new(:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345')
|
|
3844
|
-
o = Person.create(:id=>1, :address=>['123 Sesame St', 'Somewhere', '12345'])
|
|
3845
|
-
o.address.must_equal a
|
|
3846
|
-
o = Person.create(:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'})
|
|
3847
|
-
o.address.must_equal a
|
|
3848
|
-
o = Person.create(:id=>1, :address=>a)
|
|
3849
|
-
o.address.must_equal a
|
|
3850
|
-
|
|
3851
|
-
e = Person.new(:id=>1, :address=>a)
|
|
3852
|
-
o = Company.create(:id=>1, :employees=>[{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}])
|
|
3853
|
-
o.employees.must_equal [e]
|
|
3854
|
-
o = Company.create(:id=>1, :employees=>[e])
|
|
3855
|
-
o.employees.must_equal [e]
|
|
3856
|
-
end
|
|
3857
|
-
end
|
|
3858
|
-
end
|
|
3859
|
-
|
|
3860
|
-
describe 'pg_static_cache_updater extension' do
|
|
3861
|
-
before(:all) do
|
|
3862
|
-
@db = DB
|
|
3863
|
-
@db.extension :pg_static_cache_updater
|
|
3864
|
-
@db.drop_function(@db.default_static_cache_update_name, :cascade=>true, :if_exists=>true)
|
|
3865
|
-
@db.create_static_cache_update_function
|
|
3866
|
-
|
|
3867
|
-
@db.create_table!(:things) do
|
|
3868
|
-
primary_key :id
|
|
3869
|
-
String :name
|
|
3870
|
-
end
|
|
3871
|
-
@Thing = Class.new(Sequel::Model(:things))
|
|
3872
|
-
@Thing.plugin :static_cache
|
|
3873
|
-
@db.create_static_cache_update_trigger(:things)
|
|
3874
|
-
end
|
|
3875
|
-
after(:all) do
|
|
3876
|
-
@db.drop_table(:things)
|
|
3877
|
-
@db.drop_function(@db.default_static_cache_update_name)
|
|
3878
|
-
end
|
|
3879
|
-
|
|
3880
|
-
it "should reload model static cache when underlying table changes" do
|
|
3881
|
-
@Thing.all.must_equal []
|
|
3882
|
-
q = Queue.new
|
|
3883
|
-
q1 = Queue.new
|
|
3884
|
-
|
|
3885
|
-
@db.listen_for_static_cache_updates(@Thing, :timeout=>0, :loop=>proc{q.push(nil); q1.pop.call}, :before_thread_exit=>proc{q.push(nil)})
|
|
3886
|
-
|
|
3887
|
-
q.pop
|
|
3888
|
-
q1.push(proc{@db[:things].insert(1, 'A')})
|
|
3889
|
-
q.pop
|
|
3890
|
-
@Thing.all.must_equal [@Thing.load(:id=>1, :name=>'A')]
|
|
3891
|
-
|
|
3892
|
-
q1.push(proc{@db[:things].update(:name=>'B')})
|
|
3893
|
-
q.pop
|
|
3894
|
-
@Thing.all.must_equal [@Thing.load(:id=>1, :name=>'B')]
|
|
3895
|
-
|
|
3896
|
-
q1.push(proc{@db[:things].delete})
|
|
3897
|
-
q.pop
|
|
3898
|
-
@Thing.all.must_equal []
|
|
3899
|
-
|
|
3900
|
-
q1.push(proc{throw :stop})
|
|
3901
|
-
q.pop
|
|
3902
|
-
end
|
|
3903
|
-
end if uses_pg && DB.server_version >= 90000
|
|
3904
|
-
|
|
3905
|
-
describe 'PostgreSQL enum types' do
|
|
3906
|
-
before do
|
|
3907
|
-
@db = DB
|
|
3908
|
-
@initial_enum_values = %w'a b c d'
|
|
3909
|
-
@db.create_enum(:test_enum, @initial_enum_values)
|
|
3910
|
-
|
|
3911
|
-
@db.create_table!(:test_enumt) do
|
|
3912
|
-
test_enum :t
|
|
3913
|
-
end
|
|
3914
|
-
end
|
|
3915
|
-
after do
|
|
3916
|
-
@db.drop_table?(:test_enumt)
|
|
3917
|
-
@db.drop_enum(:test_enum)
|
|
3918
|
-
end
|
|
3919
|
-
|
|
3920
|
-
it "should return correct entries in the schema" do
|
|
3921
|
-
s = @db.schema(:test_enumt)
|
|
3922
|
-
s.first.last[:type].must_equal :enum
|
|
3923
|
-
s.first.last[:enum_values].must_equal @initial_enum_values
|
|
3924
|
-
end
|
|
3925
|
-
|
|
3926
|
-
it "should add array parsers for enum values" do
|
|
3927
|
-
@db.get(Sequel.pg_array(%w'a b', :test_enum)).must_equal %w'a b'
|
|
3928
|
-
end
|
|
3929
|
-
|
|
3930
|
-
it "should set up model typecasting correctly" do
|
|
3931
|
-
c = Class.new(Sequel::Model(:test_enumt))
|
|
3932
|
-
o = c.new
|
|
3933
|
-
o.t = :a
|
|
3934
|
-
o.t.must_equal 'a'
|
|
3935
|
-
end
|
|
3936
|
-
|
|
3937
|
-
it "should add values to existing enum" do
|
|
3938
|
-
@db.add_enum_value(:test_enum, 'e')
|
|
3939
|
-
@db.add_enum_value(:test_enum, 'f', :after=>'a')
|
|
3940
|
-
@db.add_enum_value(:test_enum, 'g', :before=>'b')
|
|
3941
|
-
@db.add_enum_value(:test_enum, 'a', :if_not_exists=>true) if @db.server_version >= 90300
|
|
3942
|
-
@db.schema(:test_enumt, :reload=>true).first.last[:enum_values].must_equal %w'a f g b c d e'
|
|
3943
|
-
end if DB.server_version >= 90100
|
|
3944
|
-
|
|
3945
|
-
it "should rename existing enum" do
|
|
3946
|
-
@db.rename_enum(:test_enum, :new_enum)
|
|
3947
|
-
@db.schema(:test_enumt, :reload=>true).first.last[:db_type].must_equal 'new_enum'
|
|
3948
|
-
@db.schema(:test_enumt, :reload=>true).first.last[:enum_values].must_equal @initial_enum_values
|
|
3949
|
-
@db.rename_enum(:new_enum, :test_enum)
|
|
3950
|
-
end
|
|
3951
|
-
|
|
3952
|
-
it "should rename enum values" do
|
|
3953
|
-
@db.rename_enum_value(:test_enum, :b, :x)
|
|
3954
|
-
new_enum_values = @initial_enum_values
|
|
3955
|
-
new_enum_values[new_enum_values.index('b')] = 'x'
|
|
3956
|
-
@db.schema(:test_enumt, :reload=>true).first.last[:enum_values].must_equal new_enum_values
|
|
3957
|
-
@db.rename_enum_value(:test_enum, :x, :b)
|
|
3958
|
-
end if DB.server_version >= 100000
|
|
3959
|
-
end
|
|
3960
|
-
|
|
3961
|
-
describe "PostgreSQL stored procedures for datasets" do
|
|
3962
|
-
before do
|
|
3963
|
-
@db = DB
|
|
3964
|
-
@db.create_table!(:items) do
|
|
3965
|
-
primary_key :id
|
|
3966
|
-
integer :numb
|
|
3967
|
-
end
|
|
3968
|
-
@db.execute(<<-SQL)
|
|
3969
|
-
create or replace function insert_item(numb bigint)
|
|
3970
|
-
returns items.id%type
|
|
3971
|
-
as $$
|
|
3972
|
-
declare
|
|
3973
|
-
l_id items.id%type;
|
|
3974
|
-
begin
|
|
3975
|
-
l_id := 1;
|
|
3976
|
-
|
|
3977
|
-
insert into items(id, numb) values(l_id, numb);
|
|
3978
|
-
|
|
3979
|
-
return l_id;
|
|
3980
|
-
end;
|
|
3981
|
-
$$ language plpgsql;
|
|
3982
|
-
SQL
|
|
3983
|
-
|
|
3984
|
-
@ds = @db[:items]
|
|
3985
|
-
end
|
|
3986
|
-
|
|
3987
|
-
after do
|
|
3988
|
-
@db.drop_function("insert_item", :if_exists=>true)
|
|
3989
|
-
@db.drop_table?(:items)
|
|
3990
|
-
end
|
|
3991
|
-
|
|
3992
|
-
it "should correctly call stored procedure for inserting record" do
|
|
3993
|
-
result = @ds.call_sproc(:insert, :insert_item, 100)
|
|
3994
|
-
result.must_be_nil
|
|
3995
|
-
|
|
3996
|
-
@ds.call(:all).must_equal [{:id=>1, :numb=>100}]
|
|
3997
|
-
end
|
|
3998
|
-
end if DB.adapter_scheme == :jdbc
|
|
3999
|
-
|
|
4000
|
-
describe "pg_auto_constraint_validations plugin" do
|
|
4001
|
-
before(:all) do
|
|
4002
|
-
@db = DB
|
|
4003
|
-
@db.create_table!(:test1) do
|
|
4004
|
-
Integer :id, :primary_key=>true
|
|
4005
|
-
Integer :i, :unique=>true, :null=>false
|
|
4006
|
-
constraint :valid_i, Sequel[:i] < 10
|
|
4007
|
-
constraint(:valid_i_id, Sequel[:i] + Sequel[:id] < 20)
|
|
4008
|
-
end
|
|
4009
|
-
@db.run "CREATE OR REPLACE FUNCTION valid_test1(t1 test1) RETURNS boolean AS 'SELECT t1.i != -100' LANGUAGE SQL;"
|
|
4010
|
-
@db.alter_table(:test1) do
|
|
4011
|
-
add_constraint(:valid_test1, Sequel.function(:valid_test1, :test1))
|
|
4012
|
-
end
|
|
4013
|
-
@db.create_table!(:test2) do
|
|
4014
|
-
Integer :test2_id, :primary_key=>true
|
|
4015
|
-
foreign_key :test1_id, :test1
|
|
4016
|
-
index [:test1_id], :unique=>true, :where=>(Sequel[:test1_id] < 10)
|
|
4017
|
-
end
|
|
4018
|
-
@c1 = Sequel::Model(:test1)
|
|
4019
|
-
@c2 = Sequel::Model(:test2)
|
|
4020
|
-
@c1.plugin :update_primary_key
|
|
4021
|
-
@c1.plugin :pg_auto_constraint_validations
|
|
4022
|
-
@c2.plugin :pg_auto_constraint_validations
|
|
4023
|
-
@c1.unrestrict_primary_key
|
|
4024
|
-
@c2.unrestrict_primary_key
|
|
4025
|
-
end
|
|
4026
|
-
before do
|
|
4027
|
-
@c2.dataset.delete
|
|
4028
|
-
@c1.dataset.delete
|
|
4029
|
-
@c1.insert(:id=>1, :i=>2)
|
|
4030
|
-
@c2.insert(:test2_id=>3, :test1_id=>1)
|
|
4031
|
-
end
|
|
4032
|
-
after(:all) do
|
|
4033
|
-
@db.run "ALTER TABLE test1 DROP CONSTRAINT IF EXISTS valid_test1"
|
|
4034
|
-
@db.run "DROP FUNCTION IF EXISTS valid_test1(test1)"
|
|
4035
|
-
@db.drop_table?(:test2, :test1)
|
|
4036
|
-
end
|
|
4037
|
-
|
|
4038
|
-
it "should handle check constraint failures as validation errors when creating" do
|
|
4039
|
-
o = @c1.new(:id=>5, :i=>12)
|
|
4040
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4041
|
-
o.errors.must_equal(:i=>['is invalid'])
|
|
4042
|
-
end
|
|
4043
|
-
|
|
4044
|
-
it "should handle check constraint failures where the columns are unknown, if columns are explicitly specified" do
|
|
4045
|
-
o = @c1.new(:id=>5, :i=>-100)
|
|
4046
|
-
proc{o.save}.must_raise Sequel::CheckConstraintViolation
|
|
4047
|
-
@c1.pg_auto_constraint_validation_override(:valid_test1, :i, "should not be -100")
|
|
4048
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4049
|
-
o.errors.must_equal(:i=>['should not be -100'])
|
|
4050
|
-
end
|
|
4051
|
-
|
|
4052
|
-
it "should handle check constraint failures as validation errors when updating" do
|
|
4053
|
-
o = @c1.new(:id=>5, :i=>3)
|
|
4054
|
-
o.save
|
|
4055
|
-
proc{o.update(:i=>12)}.must_raise Sequel::ValidationFailed
|
|
4056
|
-
o.errors.must_equal(:i=>['is invalid'])
|
|
4057
|
-
end
|
|
4058
|
-
|
|
4059
|
-
it "should handle unique constraint failures as validation errors when creating" do
|
|
4060
|
-
o = @c1.new(:id=>5, :i=>2)
|
|
4061
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4062
|
-
o.errors.must_equal(:i=>['is already taken'])
|
|
4063
|
-
end
|
|
4064
|
-
|
|
4065
|
-
it "should handle unique constraint failures as validation errors when updating" do
|
|
4066
|
-
o = @c1.new(:id=>5, :i=>3)
|
|
4067
|
-
o.save
|
|
4068
|
-
proc{o.update(:i=>2)}.must_raise Sequel::ValidationFailed
|
|
4069
|
-
o.errors.must_equal(:i=>['is already taken'])
|
|
4070
|
-
end
|
|
4071
|
-
|
|
4072
|
-
it "should handle unique constraint failures as validation errors for partial unique indexes" do
|
|
4073
|
-
@c1.create(:id=>2, :i=>3)
|
|
4074
|
-
@c2.create(:test2_id=>6, :test1_id=>2)
|
|
4075
|
-
o = @c2.new(:test2_id=>5, :test1_id=>2)
|
|
4076
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4077
|
-
o.errors.must_equal(:test1_id=>['is already taken'])
|
|
4078
|
-
end
|
|
4079
|
-
|
|
4080
|
-
it "should handle not null constraint failures as validation errors when creating" do
|
|
4081
|
-
o = @c1.new(:id=>5)
|
|
4082
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4083
|
-
o.errors.must_equal(:i=>['is not present'])
|
|
4084
|
-
end
|
|
4085
|
-
|
|
4086
|
-
it "should handle not null constraint failures as validation errors when updating" do
|
|
4087
|
-
o = @c1.new(:id=>5, :i=>3)
|
|
4088
|
-
o.save
|
|
4089
|
-
proc{o.update(:i=>nil)}.must_raise Sequel::ValidationFailed
|
|
4090
|
-
o.errors.must_equal(:i=>['is not present'])
|
|
4091
|
-
end
|
|
4092
|
-
|
|
4093
|
-
it "should handle foreign key constraint failures as validation errors when creating" do
|
|
4094
|
-
o = @c2.new(:test2_id=>4, :test1_id=>2)
|
|
4095
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4096
|
-
o.errors.must_equal(:test1_id=>['is invalid'])
|
|
4097
|
-
end
|
|
4098
|
-
|
|
4099
|
-
it "should handle foreign key constraint failures as validation errors when updating" do
|
|
4100
|
-
o = @c2.first
|
|
4101
|
-
proc{o.update(:test1_id=>2)}.must_raise Sequel::ValidationFailed
|
|
4102
|
-
o.errors.must_equal(:test1_id=>['is invalid'])
|
|
4103
|
-
end
|
|
4104
|
-
|
|
4105
|
-
it "should handle foreign key constraint failures in other tables as validation errors when updating" do
|
|
4106
|
-
o = @c1[1]
|
|
4107
|
-
proc{o.update(:id=>2)}.must_raise Sequel::ValidationFailed
|
|
4108
|
-
o.errors.must_equal(:id=>['cannot be changed currently'])
|
|
4109
|
-
end
|
|
4110
|
-
|
|
4111
|
-
it "should handle multi-column constraint failures as validation errors" do
|
|
4112
|
-
c = Class.new(@c1)
|
|
4113
|
-
o = c.new(:id=>18, :i=>8)
|
|
4114
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4115
|
-
[{[:i, :id]=>['is invalid']}, {[:id, :i]=>['is invalid']}].must_include o.errors
|
|
4116
|
-
end
|
|
4117
|
-
|
|
4118
|
-
it "should handle multi-column constraint failures as validation errors when using the error_splitter plugin" do
|
|
4119
|
-
c = Class.new(@c1)
|
|
4120
|
-
c.plugin :error_splitter
|
|
4121
|
-
o = c.new(:id=>18, :i=>8)
|
|
4122
|
-
proc{o.save}.must_raise Sequel::ValidationFailed
|
|
4123
|
-
o.errors.must_equal(:i=>['is invalid'], :id=>['is invalid'])
|
|
4124
|
-
end
|
|
4125
|
-
end if DB.respond_to?(:error_info)
|