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