sequel 3.21.0 → 3.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +1131 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +106 -65
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +68 -52
- data/doc/advanced_associations.rdoc +201 -75
- data/doc/association_basics.rdoc +327 -79
- data/doc/bin_sequel.rdoc +144 -0
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +10 -10
- data/doc/dataset_filtering.rdoc +54 -42
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +89 -557
- data/doc/model_hooks.rdoc +80 -29
- data/doc/object_model.rdoc +576 -0
- data/doc/opening_databases.rdoc +121 -53
- data/doc/prepared_statements.rdoc +41 -15
- data/doc/querying.rdoc +137 -56
- data/doc/reflection.rdoc +36 -10
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/release_notes/3.37.0.txt +338 -0
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/release_notes/3.40.0.txt +73 -0
- data/doc/release_notes/3.41.0.txt +155 -0
- data/doc/schema_modification.rdoc +585 -0
- data/doc/sharding.rdoc +99 -8
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +169 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +78 -43
- data/lib/sequel/adapters/ado/access.rb +334 -0
- data/lib/sequel/adapters/ado/mssql.rb +18 -12
- data/lib/sequel/adapters/ado.rb +69 -21
- data/lib/sequel/adapters/amalgalite.rb +17 -14
- data/lib/sequel/adapters/cubrid.rb +143 -0
- data/lib/sequel/adapters/db2.rb +178 -85
- data/lib/sequel/adapters/dbi.rb +19 -21
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +2 -61
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +20 -39
- data/lib/sequel/adapters/firebird.rb +33 -210
- data/lib/sequel/adapters/ibmdb.rb +452 -0
- data/lib/sequel/adapters/informix.rb +6 -29
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
- data/lib/sequel/adapters/jdbc/db2.rb +78 -0
- data/lib/sequel/adapters/jdbc/derby.rb +325 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +68 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +72 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +308 -114
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +130 -230
- data/lib/sequel/adapters/mysql2.rb +64 -63
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +29 -10
- data/lib/sequel/adapters/openbase.rb +7 -11
- data/lib/sequel/adapters/oracle.rb +364 -57
- data/lib/sequel/adapters/postgres.rb +379 -145
- data/lib/sequel/adapters/shared/access.rb +236 -11
- data/lib/sequel/adapters/shared/cubrid.rb +216 -0
- data/lib/sequel/adapters/shared/db2.rb +353 -0
- data/lib/sequel/adapters/shared/firebird.rb +231 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +412 -116
- data/lib/sequel/adapters/shared/mysql.rb +396 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
- data/lib/sequel/adapters/shared/oracle.rb +262 -45
- data/lib/sequel/adapters/shared/postgres.rb +688 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +317 -96
- data/lib/sequel/adapters/sqlite.rb +109 -46
- data/lib/sequel/adapters/swift/mysql.rb +10 -12
- data/lib/sequel/adapters/swift/postgres.rb +13 -79
- data/lib/sequel/adapters/swift/sqlite.rb +9 -6
- data/lib/sequel/adapters/swift.rb +31 -27
- data/lib/sequel/adapters/tinytds.rb +177 -25
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
- data/lib/sequel/adapters/utils/pg_types.rb +81 -0
- data/lib/sequel/adapters/utils/split_alter_table.rb +36 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +23 -13
- data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
- data/lib/sequel/connection_pool/single.rb +11 -3
- data/lib/sequel/connection_pool/threaded.rb +69 -20
- data/lib/sequel/connection_pool.rb +20 -18
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +66 -29
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +192 -51
- data/lib/sequel/database/query.rb +299 -114
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +310 -69
- data/lib/sequel/dataset/actions.rb +344 -90
- data/lib/sequel/dataset/features.rb +101 -8
- data/lib/sequel/dataset/graph.rb +42 -15
- data/lib/sequel/dataset/misc.rb +52 -25
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +322 -68
- data/lib/sequel/dataset/sql.rb +716 -293
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +83 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +72 -0
- data/lib/sequel/extensions/connection_validator.rb +109 -0
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
- data/lib/sequel/extensions/eval_inspect.rb +173 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +100 -11
- data/lib/sequel/extensions/named_timezones.rb +9 -0
- data/lib/sequel/extensions/null_dataset.rb +94 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +539 -0
- data/lib/sequel/extensions/pg_array_ops.rb +263 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
- data/lib/sequel/extensions/pg_hstore.rb +334 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
- data/lib/sequel/extensions/pg_inet.rb +113 -0
- data/lib/sequel/extensions/pg_interval.rb +191 -0
- data/lib/sequel/extensions/pg_json.rb +212 -0
- data/lib/sequel/extensions/pg_range.rb +513 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +576 -0
- data/lib/sequel/extensions/pg_row_ops.rb +182 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
- data/lib/sequel/extensions/pretty_table.rb +17 -72
- data/lib/sequel/extensions/query.rb +8 -4
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +282 -76
- data/lib/sequel/extensions/select_remove.rb +39 -0
- data/lib/sequel/extensions/server_block.rb +140 -0
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +8 -110
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
- data/lib/sequel/extensions/to_dot.rb +99 -83
- data/lib/sequel/model/associations.rb +1263 -409
- data/lib/sequel/model/base.rb +624 -171
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +24 -2
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +137 -16
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +72 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +134 -15
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +77 -6
- data/lib/sequel/plugins/list.rb +13 -2
- data/lib/sequel/plugins/many_through_many.rb +103 -51
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +150 -66
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/prepared_statements.rb +168 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +31 -17
- data/lib/sequel/plugins/schema.rb +8 -3
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +57 -12
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +29 -3
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/touch.rb +18 -6
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +57 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +721 -141
- data/lib/sequel/timezones.rb +67 -40
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +53 -39
- data/spec/adapters/mssql_spec.rb +261 -66
- data/spec/adapters/mysql_spec.rb +597 -352
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +2103 -341
- data/spec/adapters/spec_helper.rb +16 -6
- data/spec/adapters/sqlite_spec.rb +237 -76
- data/spec/core/connection_pool_spec.rb +270 -141
- data/spec/core/database_spec.rb +980 -524
- data/spec/core/dataset_spec.rb +1658 -1243
- data/spec/core/expression_filters_spec.rb +741 -334
- data/spec/core/mock_adapter_spec.rb +453 -0
- data/spec/core/object_graph_spec.rb +88 -129
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +556 -53
- data/spec/core/spec_helper.rb +7 -48
- data/spec/core_extensions_spec.rb +626 -0
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +227 -33
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- data/spec/extensions/caching_spec.rb +47 -51
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/connection_validator_spec.rb +118 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +88 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/eval_inspect_spec.rb +67 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +97 -128
- data/spec/extensions/identity_map_spec.rb +142 -24
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -12
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +49 -40
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +368 -254
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +268 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +112 -0
- data/spec/extensions/pg_array_spec.rb +324 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
- data/spec/extensions/pg_hstore_spec.rb +200 -0
- data/spec/extensions/pg_inet_spec.rb +47 -0
- data/spec/extensions/pg_interval_spec.rb +72 -0
- data/spec/extensions/pg_json_spec.rb +99 -0
- data/spec/extensions/pg_range_ops_spec.rb +56 -0
- data/spec/extensions/pg_range_spec.rb +395 -0
- data/spec/extensions/pg_row_ops_spec.rb +58 -0
- data/spec/extensions/pg_row_plugin_spec.rb +49 -0
- data/spec/extensions/pg_row_spec.rb +340 -0
- data/spec/extensions/pg_statement_cache_spec.rb +208 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +167 -0
- data/spec/extensions/query_spec.rb +9 -3
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +434 -49
- data/spec/extensions/schema_spec.rb +30 -49
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +86 -48
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +65 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +34 -67
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/subclasses_spec.rb +14 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +8 -11
- data/spec/extensions/touch_spec.rb +53 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +9 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +77 -68
- data/spec/extensions/validation_helpers_spec.rb +48 -37
- data/spec/extensions/xml_serializer_spec.rb +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +25 -5
- data/spec/integration/dataset_test.rb +729 -141
- data/spec/integration/eager_loader_test.rb +38 -54
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +871 -160
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +377 -57
- data/spec/integration/spec_helper.rb +49 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +40 -8
- data/spec/model/association_reflection_spec.rb +207 -8
- data/spec/model/associations_spec.rb +1206 -693
- data/spec/model/base_spec.rb +334 -100
- data/spec/model/dataset_methods_spec.rb +45 -27
- data/spec/model/eager_loading_spec.rb +828 -692
- data/spec/model/hooks_spec.rb +355 -67
- data/spec/model/model_spec.rb +251 -179
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +506 -232
- data/spec/model/spec_helper.rb +16 -77
- data/spec/model/validations_spec.rb +38 -2
- data/spec/rcov.opts +2 -0
- metadata +223 -81
- data/spec/core/core_sql_spec.rb +0 -451
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
|
+
|
|
3
|
+
describe "null_dataset extension" do
|
|
4
|
+
before do
|
|
5
|
+
@db = Sequel::mock(:fetch=>{:id=>1}, :autoid=>1, :numrows=>1, :columns=>[:id])
|
|
6
|
+
@ds = @db[:table].nullify
|
|
7
|
+
@i = 0
|
|
8
|
+
@pr = proc{|*a| @i += 1}
|
|
9
|
+
end
|
|
10
|
+
after do
|
|
11
|
+
@db.sqls.should == [] unless @skip_check
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should make each be a noop" do
|
|
15
|
+
@ds.each(&@pr).should equal(@ds)
|
|
16
|
+
@i.should == 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should make fetch_rows be a noop" do
|
|
20
|
+
@ds.fetch_rows("SELECT 1", &@pr).should == nil
|
|
21
|
+
@i.should == 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should make insert be a noop" do
|
|
25
|
+
@ds.insert(1).should == nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should make update be a noop" do
|
|
29
|
+
@ds.update(:a=>1).should == 0
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should make delete be a noop" do
|
|
33
|
+
@ds.delete.should == 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should make truncate be a noop" do
|
|
37
|
+
@ds.truncate.should == nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should make execute_* be a noop" do
|
|
41
|
+
@ds.send(:execute_ddl,'FOO').should == nil
|
|
42
|
+
@ds.send(:execute_insert,'FOO').should == nil
|
|
43
|
+
@ds.send(:execute_dui,'FOO').should == nil
|
|
44
|
+
@ds.send(:execute,'FOO').should == nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should have working columns" do
|
|
48
|
+
@skip_check = true
|
|
49
|
+
@ds.columns.should == [:id]
|
|
50
|
+
@db.sqls.should == ['SELECT * FROM table LIMIT 1']
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should have count return 0" do
|
|
54
|
+
@ds.count.should == 0
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should have empty return true" do
|
|
58
|
+
@ds.empty?.should == true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should make import a noop" do
|
|
62
|
+
@ds.import([:id], [[1], [2], [3]]).should == nil
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should have nullify method returned modified receiver" do
|
|
66
|
+
@skip_check = true
|
|
67
|
+
ds = @db[:table]
|
|
68
|
+
ds.nullify.should_not equal(ds)
|
|
69
|
+
ds.each(&@pr)
|
|
70
|
+
@db.sqls.should == ['SELECT * FROM table']
|
|
71
|
+
@i.should == 1
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should have null! method modify receiver" do
|
|
75
|
+
ds = @db[:table]
|
|
76
|
+
ds.nullify!.should equal(ds)
|
|
77
|
+
ds.each(&@pr)
|
|
78
|
+
@i.should == 0
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "should work with method chaining" do
|
|
82
|
+
@ds.where(:a=>1).select(:b).each(&@pr)
|
|
83
|
+
@i.should == 0
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -6,11 +6,8 @@ describe "optimistic_locking plugin" do
|
|
|
6
6
|
end
|
|
7
7
|
h = {1=>{:id=>1, :name=>'John', :lock_version=>2}}
|
|
8
8
|
lv = @lv = "lock_version"
|
|
9
|
-
@c.dataset.
|
|
10
|
-
|
|
11
|
-
@c.dataset.meta_def(:lv){lv}
|
|
12
|
-
@c.dataset.meta_def(:update) do |opts|
|
|
13
|
-
case update_sql(opts)
|
|
9
|
+
@c.instance_dataset.numrows = @c.dataset.numrows = proc do |sql|
|
|
10
|
+
case sql
|
|
14
11
|
when /UPDATE people SET (name|#{lv}) = ('Jim'|'Bob'|\d+), (?:name|#{lv}) = ('Jim'|'Bob'|\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
|
|
15
12
|
name, nlv = $1 == 'name' ? [$2, $3] : [$3, $2]
|
|
16
13
|
m = h[$4.to_i]
|
|
@@ -28,20 +25,6 @@ describe "optimistic_locking plugin" do
|
|
|
28
25
|
else
|
|
29
26
|
0
|
|
30
27
|
end
|
|
31
|
-
else
|
|
32
|
-
puts update_sql(opts)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
@c.dataset.instance_eval do
|
|
36
|
-
def fetch_rows(sql)
|
|
37
|
-
m = h[1].dup
|
|
38
|
-
v = m.delete(:lock_version)
|
|
39
|
-
m[lv.to_sym] = v
|
|
40
|
-
yield(m)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
@c.dataset.meta_def(:delete) do
|
|
44
|
-
case delete_sql
|
|
45
28
|
when /DELETE FROM people WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
|
|
46
29
|
m = h[$1.to_i]
|
|
47
30
|
if m && m[lv.to_sym] == $2.to_i
|
|
@@ -51,9 +34,15 @@ describe "optimistic_locking plugin" do
|
|
|
51
34
|
0
|
|
52
35
|
end
|
|
53
36
|
else
|
|
54
|
-
puts
|
|
37
|
+
puts sql
|
|
55
38
|
end
|
|
56
39
|
end
|
|
40
|
+
@c.instance_dataset._fetch = @c.dataset._fetch = proc do |sql|
|
|
41
|
+
m = h[1].dup
|
|
42
|
+
v = m.delete(:lock_version)
|
|
43
|
+
m[lv.to_sym] = v
|
|
44
|
+
m
|
|
45
|
+
end
|
|
57
46
|
@c.columns :id, :name, :lock_version
|
|
58
47
|
@c.plugin :optimistic_locking
|
|
59
48
|
end
|
|
@@ -106,6 +95,20 @@ describe "optimistic_locking plugin" do
|
|
|
106
95
|
proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
|
|
107
96
|
end
|
|
108
97
|
|
|
98
|
+
specify "should work correctly if attempting to refresh and save again after a failed save" do
|
|
99
|
+
p1 = @c[1]
|
|
100
|
+
p2 = @c[1]
|
|
101
|
+
p1.update(:name=>'Jim')
|
|
102
|
+
begin
|
|
103
|
+
p2.update(:name=>'Bob')
|
|
104
|
+
rescue Sequel::Plugins::OptimisticLocking::Error
|
|
105
|
+
p2.refresh
|
|
106
|
+
@c.db.sqls
|
|
107
|
+
proc{p2.update(:name=>'Bob')}.should_not raise_error
|
|
108
|
+
end
|
|
109
|
+
@c.db.sqls.first.should =~ /UPDATE people SET (name = 'Bob', lock_version = 4|lock_version = 4, name = 'Bob') WHERE \(\(id = 1\) AND \(lock_version = 3\)\)/
|
|
110
|
+
end
|
|
111
|
+
|
|
109
112
|
specify "should increment the lock column when #modified! even if no columns are changed" do
|
|
110
113
|
p1 = @c[1]
|
|
111
114
|
p1.modified!
|
|
@@ -115,7 +118,7 @@ describe "optimistic_locking plugin" do
|
|
|
115
118
|
end
|
|
116
119
|
|
|
117
120
|
specify "should not increment the lock column when the update fails" do
|
|
118
|
-
@c.
|
|
121
|
+
@c.instance_dataset.meta_def(:update) { raise Exception }
|
|
119
122
|
p1 = @c[1]
|
|
120
123
|
p1.modified!
|
|
121
124
|
lv = p1.lock_version
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
|
+
|
|
3
|
+
describe "Sequel::Postgres::ArrayOp" do
|
|
4
|
+
before do
|
|
5
|
+
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
|
6
|
+
@a = Sequel.pg_array_op(:a)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should support the standard mathematical operators" do
|
|
10
|
+
@db.literal(@a < @a).should == "(a < a)"
|
|
11
|
+
@db.literal(@a <= @a).should == "(a <= a)"
|
|
12
|
+
@db.literal(@a > @a).should == "(a > a)"
|
|
13
|
+
@db.literal(@a >= @a).should == "(a >= a)"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "#[] should support subscript access" do
|
|
17
|
+
@db.literal(@a[1]).should == "a[1]"
|
|
18
|
+
@db.literal(@a[1][2]).should == "a[1][2]"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "#any should use the ANY method" do
|
|
22
|
+
@db.literal(1=>@a.any).should == "(1 = ANY(a))"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "#all should use the ALL method" do
|
|
26
|
+
@db.literal(1=>@a.all).should == "(1 = ALL(a))"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "#contains should use the @> operator" do
|
|
30
|
+
@db.literal(@a.contains(:b)).should == "(a @> b)"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "#contained_by should use the <@ operator" do
|
|
34
|
+
@db.literal(@a.contained_by(:b)).should == "(a <@ b)"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "#overlaps should use the && operator" do
|
|
38
|
+
@db.literal(@a.overlaps(:b)).should == "(a && b)"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "#push/concat should use the || operator in append mode" do
|
|
42
|
+
@db.literal(@a.push(:b)).should == "(a || b)"
|
|
43
|
+
@db.literal(@a.concat(:b)).should == "(a || b)"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "#unshift should use the || operator in prepend mode" do
|
|
47
|
+
@db.literal(@a.unshift(:b)).should == "(b || a)"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "#dims should use the array_dims function" do
|
|
51
|
+
@db.literal(@a.dims).should == "array_dims(a)"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "#length should use the array_length function" do
|
|
55
|
+
@db.literal(@a.length).should == "array_length(a, 1)"
|
|
56
|
+
@db.literal(@a.length(2)).should == "array_length(a, 2)"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "#length should use the array_lower function" do
|
|
60
|
+
@db.literal(@a.lower).should == "array_lower(a, 1)"
|
|
61
|
+
@db.literal(@a.lower(2)).should == "array_lower(a, 2)"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "#to_string/join should use the array_to_string function" do
|
|
65
|
+
@db.literal(@a.to_string).should == "array_to_string(a, '', NULL)"
|
|
66
|
+
@db.literal(@a.join).should == "array_to_string(a, '', NULL)"
|
|
67
|
+
@db.literal(@a.join(':')).should == "array_to_string(a, ':', NULL)"
|
|
68
|
+
@db.literal(@a.join(':', '*')).should == "array_to_string(a, ':', '*')"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "#unnest should use the unnest function" do
|
|
72
|
+
@db.literal(@a.unnest).should == "unnest(a)"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "#pg_array should return self" do
|
|
76
|
+
@a.pg_array.should equal(@a)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "Sequel.pg_array_op should return arg for ArrayOp" do
|
|
80
|
+
Sequel.pg_array_op(@a).should equal(@a)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "should be able to turn expressions into array ops using pg_array" do
|
|
84
|
+
@db.literal(Sequel.qualify(:b, :a).pg_array.push(3)).should == "(b.a || 3)"
|
|
85
|
+
@db.literal(Sequel.function(:a, :b).pg_array.push(3)).should == "(a(b) || 3)"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should be able to turn literal strings into array ops using pg_array" do
|
|
89
|
+
@db.literal(Sequel.lit('a').pg_array.unnest).should == "unnest(a)"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should be able to turn symbols into array ops using Sequel.pg_array_op" do
|
|
93
|
+
@db.literal(Sequel.pg_array_op(:a).unnest).should == "unnest(a)"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should be able to turn symbols into array ops using Sequel.pg_array" do
|
|
97
|
+
@db.literal(Sequel.pg_array(:a).unnest).should == "unnest(a)"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should allow transforming PGArray instances into ArrayOp instances" do
|
|
101
|
+
@db.literal(Sequel.pg_array([1,2]).op.push(3)).should == "(ARRAY[1,2] || 3)"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should wrap array arguments in PGArrays" do
|
|
105
|
+
@db.literal(@a.contains([1, 2])).should == "(a @> ARRAY[1,2])"
|
|
106
|
+
@db.literal(@a.contained_by([1, 2])).should == "(a <@ ARRAY[1,2])"
|
|
107
|
+
@db.literal(@a.overlaps([1, 2])).should == "(a && ARRAY[1,2])"
|
|
108
|
+
@db.literal(@a.push([1, 2])).should == "(a || ARRAY[1,2])"
|
|
109
|
+
@db.literal(@a.concat([1, 2])).should == "(a || ARRAY[1,2])"
|
|
110
|
+
@db.literal(@a.unshift([1, 2])).should == "(ARRAY[1,2] || a)"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
|
+
|
|
3
|
+
describe "pg_array extension" do
|
|
4
|
+
before(:all) do
|
|
5
|
+
@pg_types = Sequel::Postgres::PG_TYPES.dup
|
|
6
|
+
end
|
|
7
|
+
after(:all) do
|
|
8
|
+
Sequel::Postgres::PG_TYPES.replace(@pg_types)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
|
13
|
+
@db.extend_datasets(Module.new{def supports_timestamp_timezones?; false; end; def supports_timestamp_usecs?; false; end})
|
|
14
|
+
@db.extension(:pg_array)
|
|
15
|
+
@m = Sequel::Postgres
|
|
16
|
+
@converter = @m::PG_TYPES
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should parse single dimensional text arrays" do
|
|
20
|
+
c = @converter[1009]
|
|
21
|
+
c.call("{a}").to_a.first.should be_a_kind_of(String)
|
|
22
|
+
c.call("{}").to_a.should == []
|
|
23
|
+
c.call("{a}").to_a.should == ['a']
|
|
24
|
+
c.call('{"a b"}').to_a.should == ['a b']
|
|
25
|
+
c.call('{a,b}').to_a.should == ['a', 'b']
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should parse multi-dimensional text arrays" do
|
|
29
|
+
c = @converter[1009]
|
|
30
|
+
c.call("{{}}").to_a.should == [[]]
|
|
31
|
+
c.call("{{a},{b}}").to_a.should == [['a'], ['b']]
|
|
32
|
+
c.call('{{"a b"},{c}}').to_a.should == [['a b'], ['c']]
|
|
33
|
+
c.call('{{{a},{b}},{{c},{d}}}').to_a.should == [[['a'], ['b']], [['c'], ['d']]]
|
|
34
|
+
c.call('{{{a,e},{b,f}},{{c,g},{d,h}}}').to_a.should == [[['a', 'e'], ['b', 'f']], [['c', 'g'], ['d', 'h']]]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should parse text arrays with embedded deliminaters" do
|
|
38
|
+
c = @converter[1009]
|
|
39
|
+
c.call('{{"{},","\\",\\,\\\\\\"\\""}}').to_a.should == [['{},', '",,\\""']]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should parse single dimensional integer arrays" do
|
|
43
|
+
c = @converter[1007]
|
|
44
|
+
c.call("{1}").to_a.first.should be_a_kind_of(Integer)
|
|
45
|
+
c.call("{}").to_a.should == []
|
|
46
|
+
c.call("{1}").to_a.should == [1]
|
|
47
|
+
c.call('{2,3}').to_a.should == [2, 3]
|
|
48
|
+
c.call('{3,4,5}').to_a.should == [3, 4, 5]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should parse multiple dimensional integer arrays" do
|
|
52
|
+
c = @converter[1007]
|
|
53
|
+
c.call("{{}}").to_a.should == [[]]
|
|
54
|
+
c.call("{{1}}").to_a.should == [[1]]
|
|
55
|
+
c.call('{{2},{3}}').to_a.should == [[2], [3]]
|
|
56
|
+
c.call('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.should == [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should parse single dimensional float arrays" do
|
|
60
|
+
c = @converter[1022]
|
|
61
|
+
c.call("{}").to_a.should == []
|
|
62
|
+
c.call("{1.5}").to_a.should == [1.5]
|
|
63
|
+
c.call('{2.5,3.5}').to_a.should == [2.5, 3.5]
|
|
64
|
+
c.call('{3.5,4.5,5.5}').to_a.should == [3.5, 4.5, 5.5]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should parse multiple dimensional float arrays" do
|
|
68
|
+
c = @converter[1022]
|
|
69
|
+
c.call("{{}}").to_a.should == [[]]
|
|
70
|
+
c.call("{{1.5}}").to_a.should == [[1.5]]
|
|
71
|
+
c.call('{{2.5},{3.5}}').to_a.should == [[2.5], [3.5]]
|
|
72
|
+
c.call('{{{1.5,2.5},{3.5,4.5}},{{5.5,6.5},{7.5,8.5}}}').to_a.should == [[[1.5, 2.5], [3.5, 4.5]], [[5.5, 6.5], [7.5, 8.5]]]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "should parse integers in float arrays as floats" do
|
|
76
|
+
c = @converter[1022]
|
|
77
|
+
c.call("{1}").to_a.first.should be_a_kind_of(Float)
|
|
78
|
+
c.call("{1}").to_a.should == [1.0]
|
|
79
|
+
c.call('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.should == [[[1.0, 2.0], [3.0, 4.0]], [[5.0, 6.0], [7.0, 8.0]]]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "should parse single dimensional decimal arrays" do
|
|
83
|
+
c = @converter[1231]
|
|
84
|
+
c.call("{}").to_a.should == []
|
|
85
|
+
c.call("{1.5}").to_a.should == [BigDecimal.new('1.5')]
|
|
86
|
+
c.call('{2.5,3.5}').to_a.should == [BigDecimal.new('2.5'), BigDecimal.new('3.5')]
|
|
87
|
+
c.call('{3.5,4.5,5.5}').to_a.should == [BigDecimal.new('3.5'), BigDecimal.new('4.5'), BigDecimal.new('5.5')]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should parse multiple dimensional decimal arrays" do
|
|
91
|
+
c = @converter[1231]
|
|
92
|
+
c.call("{{}}").to_a.should == [[]]
|
|
93
|
+
c.call("{{1.5}}").to_a.should == [[BigDecimal.new('1.5')]]
|
|
94
|
+
c.call('{{2.5},{3.5}}').to_a.should == [[BigDecimal.new('2.5')], [BigDecimal.new('3.5')]]
|
|
95
|
+
c.call('{{{1.5,2.5},{3.5,4.5}},{{5.5,6.5},{7.5,8.5}}}').to_a.should == [[[BigDecimal.new('1.5'), BigDecimal.new('2.5')], [BigDecimal.new('3.5'), BigDecimal.new('4.5')]], [[BigDecimal.new('5.5'), BigDecimal.new('6.5')], [BigDecimal.new('7.5'), BigDecimal.new('8.5')]]]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should parse decimal values with arbitrary precision" do
|
|
99
|
+
c = @converter[1231]
|
|
100
|
+
c.call("{1.000000000000000000005}").to_a.should == [BigDecimal.new('1.000000000000000000005')]
|
|
101
|
+
c.call("{{1.000000000000000000005,2.000000000000000000005},{3.000000000000000000005,4.000000000000000000005}}").to_a.should == [[BigDecimal.new('1.000000000000000000005'), BigDecimal.new('2.000000000000000000005')], [BigDecimal.new('3.000000000000000000005'), BigDecimal.new('4.000000000000000000005')]]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should parse integers in decimal arrays as BigDecimals" do
|
|
105
|
+
c = @converter[1231]
|
|
106
|
+
c.call("{1}").to_a.first.should be_a_kind_of(BigDecimal)
|
|
107
|
+
c.call("{1}").to_a.should == [BigDecimal.new('1')]
|
|
108
|
+
c.call('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.should == [[[BigDecimal.new('1'), BigDecimal.new('2')], [BigDecimal.new('3'), BigDecimal.new('4')]], [[BigDecimal.new('5'), BigDecimal.new('6')], [BigDecimal.new('7'), BigDecimal.new('8')]]]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "should parse arrays with NULL values" do
|
|
112
|
+
@converter.values_at(1007, 1009, 1022, 1231).each do |c|
|
|
113
|
+
c.call("{NULL}").should == [nil]
|
|
114
|
+
c.call("{NULL,NULL}").should == [nil,nil]
|
|
115
|
+
c.call("{{NULL,NULL},{NULL,NULL}}").should == [[nil,nil],[nil,nil]]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'should parse arrays with "NULL" values' do
|
|
120
|
+
c = @converter[1009]
|
|
121
|
+
c.call('{NULL,"NULL",NULL}').to_a.should == [nil, "NULL", nil]
|
|
122
|
+
c.call('{NULLA,"NULL",NULL}').to_a.should == ["NULLA", "NULL", nil]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should literalize arrays without types correctly" do
|
|
126
|
+
@db.literal(@m::PGArray.new([])).should == 'ARRAY[]'
|
|
127
|
+
@db.literal(@m::PGArray.new([1])).should == 'ARRAY[1]'
|
|
128
|
+
@db.literal(@m::PGArray.new([nil])).should == 'ARRAY[NULL]'
|
|
129
|
+
@db.literal(@m::PGArray.new([nil, 1])).should == 'ARRAY[NULL,1]'
|
|
130
|
+
@db.literal(@m::PGArray.new([1.0, 2.5])).should == 'ARRAY[1.0,2.5]'
|
|
131
|
+
@db.literal(@m::PGArray.new([BigDecimal.new('1'), BigDecimal.new('2.000000000000000000005')])).should == 'ARRAY[1.0,2.000000000000000000005]'
|
|
132
|
+
@db.literal(@m::PGArray.new([nil, "NULL"])).should == "ARRAY[NULL,'NULL']"
|
|
133
|
+
@db.literal(@m::PGArray.new([nil, "{},[]'\""])).should == "ARRAY[NULL,'{},[]''\"']"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "should literalize multidimensional arrays correctly" do
|
|
137
|
+
@db.literal(@m::PGArray.new([[]])).should == 'ARRAY[[]]'
|
|
138
|
+
@db.literal(@m::PGArray.new([[1, 2]])).should == 'ARRAY[[1,2]]'
|
|
139
|
+
@db.literal(@m::PGArray.new([[3], [5]])).should == 'ARRAY[[3],[5]]'
|
|
140
|
+
@db.literal(@m::PGArray.new([[[1.0]], [[2.5]]])).should == 'ARRAY[[[1.0]],[[2.5]]]'
|
|
141
|
+
@db.literal(@m::PGArray.new([[[["NULL"]]]])).should == "ARRAY[[[['NULL']]]]"
|
|
142
|
+
@db.literal(@m::PGArray.new([["a", "b"], ["{},[]'\"", nil]])).should == "ARRAY[['a','b'],['{},[]''\"',NULL]]"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "should literalize with types correctly" do
|
|
146
|
+
@db.literal(@m::PGArray.new([1], :int4)).should == 'ARRAY[1]::int4[]'
|
|
147
|
+
@db.literal(@m::PGArray.new([nil], :text)).should == 'ARRAY[NULL]::text[]'
|
|
148
|
+
@db.literal(@m::PGArray.new([nil, 1], :int8)).should == 'ARRAY[NULL,1]::int8[]'
|
|
149
|
+
@db.literal(@m::PGArray.new([1.0, 2.5], :real)).should == 'ARRAY[1.0,2.5]::real[]'
|
|
150
|
+
@db.literal(@m::PGArray.new([BigDecimal.new('1'), BigDecimal.new('2.000000000000000000005')], :decimal)).should == 'ARRAY[1.0,2.000000000000000000005]::decimal[]'
|
|
151
|
+
@db.literal(@m::PGArray.new([nil, "NULL"], :varchar)).should == "ARRAY[NULL,'NULL']::varchar[]"
|
|
152
|
+
@db.literal(@m::PGArray.new([nil, "{},[]'\""], :"varchar(255)")).should == "ARRAY[NULL,'{},[]''\"']::varchar(255)[]"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "should have Sequel.pg_array method for easy PGArray creation" do
|
|
156
|
+
@db.literal(Sequel.pg_array([1])).should == 'ARRAY[1]'
|
|
157
|
+
@db.literal(Sequel.pg_array([1, 2], :int4)).should == 'ARRAY[1,2]::int4[]'
|
|
158
|
+
@db.literal(Sequel.pg_array([[[1], [2]], [[3], [4]]], :real)).should == 'ARRAY[[[1],[2]],[[3],[4]]]::real[]'
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "should have Sequel.pg_array return existing PGArrays as-is" do
|
|
162
|
+
a = Sequel.pg_array([1])
|
|
163
|
+
Sequel.pg_array(a).should equal(a)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "should have Sequel.pg_array create a new PGArrays if type of existing does not match" do
|
|
167
|
+
a = Sequel.pg_array([1], :int4)
|
|
168
|
+
b = Sequel.pg_array(a, :int8)
|
|
169
|
+
a.should == b
|
|
170
|
+
a.should_not equal(b)
|
|
171
|
+
a.array_type.should == :int4
|
|
172
|
+
b.array_type.should == :int8
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "should support using arrays as bound variables" do
|
|
176
|
+
@db.bound_variable_arg(1, nil).should == 1
|
|
177
|
+
@db.bound_variable_arg(Sequel.pg_array([1,2]), nil).should == '{1,2}'
|
|
178
|
+
@db.bound_variable_arg([1,2], nil).should == '{1,2}'
|
|
179
|
+
@db.bound_variable_arg([[1,2]], nil).should == '{{1,2}}'
|
|
180
|
+
@db.bound_variable_arg([1.0,2.0], nil).should == '{1.0,2.0}'
|
|
181
|
+
@db.bound_variable_arg([Sequel.lit('a'), Sequel.blob("a\0'\"")], nil).should == '{a,"a\\\\000\\\\047\\""}'
|
|
182
|
+
@db.bound_variable_arg(["\\ \"", 'NULL', nil], nil).should == '{"\\\\ \\"","NULL",NULL}'
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "should parse array types from the schema correctly" do
|
|
186
|
+
@db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'integer[]'}, {:name=>'f', :db_type=>'real[]'}, {:name=>'d', :db_type=>'numeric[]'}, {:name=>'t', :db_type=>'text[]'}]
|
|
187
|
+
@db.schema(:items).map{|e| e[1][:type]}.should == [:integer, :integer_array, :float_array, :decimal_array, :string_array]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "should support typecasting of the various array types" do
|
|
191
|
+
{
|
|
192
|
+
:integer=>{:class=>Integer, :convert=>['1', 1, '1']},
|
|
193
|
+
:float=>{:db_type=>'double precision', :class=>Float, :convert=>['1.1', 1.1, '1.1']},
|
|
194
|
+
:decimal=>{:db_type=>'numeric', :class=>BigDecimal, :convert=>['1.00000000000000000000000001', BigDecimal.new('1.00000000000000000000000001'), '1.00000000000000000000000001']},
|
|
195
|
+
:string=>{:db_type=>'text', :class=>String, :convert=>[1, '1', "'1'"]},
|
|
196
|
+
:bigint=>{:class=>Integer, :convert=>['1', 1, '1']},
|
|
197
|
+
:boolean=>{:class=>TrueClass, :convert=>['t', true, 'true']},
|
|
198
|
+
:blob=>{:db_type=>'bytea', :class=>Sequel::SQL::Blob, :convert=>['1', '1', "'1'"]},
|
|
199
|
+
:date=>{:class=>Date, :convert=>['2011-10-12', Date.new(2011, 10, 12), "'2011-10-12'"]},
|
|
200
|
+
:time=>{:db_type=>'time without time zone', :class=>Sequel::SQLTime, :convert=>['01:02:03', Sequel::SQLTime.create(1, 2, 3), "'01:02:03'"]},
|
|
201
|
+
:datetime=>{:db_type=>'timestamp without time zone', :class=>Time, :convert=>['2011-10-12 01:02:03', Time.local(2011, 10, 12, 1, 2, 3), "'2011-10-12 01:02:03'"]},
|
|
202
|
+
:time_timezone=>{:db_type=>'time with time zone', :class=>Sequel::SQLTime, :convert=>['01:02:03', Sequel::SQLTime.create(1, 2, 3), "'01:02:03'"]},
|
|
203
|
+
:datetime_timezone=>{:db_type=>'timestamp with time zone', :class=>Time, :convert=>['2011-10-12 01:02:03', Time.local(2011, 10, 12, 1, 2, 3), "'2011-10-12 01:02:03'"]},
|
|
204
|
+
}.each do |type, h|
|
|
205
|
+
meth = :"#{type}_array"
|
|
206
|
+
db_type = h[:db_type]||type
|
|
207
|
+
klass = h[:class]
|
|
208
|
+
array_in, value, output = h[:convert]
|
|
209
|
+
|
|
210
|
+
[[array_in]].each do |input|
|
|
211
|
+
v = @db.typecast_value(meth, input)
|
|
212
|
+
v.should == [value]
|
|
213
|
+
v.first.should be_a_kind_of(klass)
|
|
214
|
+
v.array_type.should_not be_nil
|
|
215
|
+
@db.typecast_value(meth, Sequel.pg_array([value])).should == v
|
|
216
|
+
@db.typecast_value(meth, v).should equal(v)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
[[[array_in]]].each do |input|
|
|
220
|
+
v = @db.typecast_value(meth, input)
|
|
221
|
+
v.should == [[value]]
|
|
222
|
+
v.first.first.should be_a_kind_of(klass)
|
|
223
|
+
v.array_type.should_not be_nil
|
|
224
|
+
@db.typecast_value(meth, Sequel.pg_array([[value]])).should == v
|
|
225
|
+
@db.typecast_value(meth, v).should equal(v)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
@db.literal(@db.typecast_value(meth, [array_in])).should == "ARRAY[#{output}]::#{db_type}[]"
|
|
229
|
+
@db.literal(@db.typecast_value(meth, [])).should == "ARRAY[]::#{db_type}[]"
|
|
230
|
+
end
|
|
231
|
+
proc{@db.typecast_value(:integer_array, {})}.should raise_error(Sequel::InvalidValue)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "should support SQL::AliasMethods" do
|
|
235
|
+
@db.select(Sequel.pg_array([1], :integer).as(:col1)).sql.should == 'SELECT ARRAY[1]::integer[] AS col1'
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "should support registering custom array types" do
|
|
239
|
+
Sequel::Postgres::PGArray.register('foo')
|
|
240
|
+
@db.typecast_value(:foo_array, []).should be_a_kind_of(Sequel::Postgres::PGArray)
|
|
241
|
+
@db.fetch = [{:name=>'id', :db_type=>'foo[]'}]
|
|
242
|
+
@db.schema(:items).map{|e| e[1][:type]}.should == [:foo_array]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
it "should support registering custom types with :type_symbol option" do
|
|
246
|
+
Sequel::Postgres::PGArray.register('foo', :type_symbol=>:bar)
|
|
247
|
+
@db.typecast_value(:bar_array, []).should be_a_kind_of(Sequel::Postgres::PGArray)
|
|
248
|
+
@db.fetch = [{:name=>'id', :db_type=>'foo[]'}]
|
|
249
|
+
@db.schema(:items).map{|e| e[1][:type]}.should == [:bar_array]
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it "should support using a block as a custom conversion proc given as block" do
|
|
253
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>1234){|s| (s*2).to_i}
|
|
254
|
+
@converter[1234].call('{1}').should == [11]
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it "should support using a block as a custom conversion proc given as :converter option" do
|
|
258
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>1234, :converter=>proc{|s| (s*2).to_i})
|
|
259
|
+
@converter[1234].call('{1}').should == [11]
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it "should support using an existing scaler conversion proc via the :scalar_oid option" do
|
|
263
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>1234, :scalar_oid=>16)
|
|
264
|
+
@converter[1234].call('{t}').should == [true]
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it "should support using a given conversion procs hash via the :type_procs option" do
|
|
268
|
+
h = {16=>proc{|s| "!#{s}"}}
|
|
269
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>1234, :scalar_oid=>16, :type_procs=>h)
|
|
270
|
+
h[1234].call('{t}').should == ["!t"]
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it "should support adding methods to the given module via the :typecast_methods_module option" do
|
|
274
|
+
m = Module.new
|
|
275
|
+
Sequel::Postgres::PGArray.register('foo15', :scalar_typecast=>:boolean, :typecast_methods_module=>m)
|
|
276
|
+
@db.typecast_value(:foo15_array, ['t']).should == ['t']
|
|
277
|
+
@db.extend(m)
|
|
278
|
+
@db.typecast_value(:foo15_array, ['t']).should == [true]
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it "should raise an error if using :scalar_oid option with unexisting scalar conversion proc" do
|
|
282
|
+
proc{Sequel::Postgres::PGArray.register('foo', :scalar_oid=>0)}.should raise_error(Sequel::Error)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "should raise an error if using :converter option and a block argument" do
|
|
286
|
+
proc{Sequel::Postgres::PGArray.register('foo', :converter=>proc{}){}}.should raise_error(Sequel::Error)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
it "should raise an error if using :scalar_oid option and a block argument" do
|
|
290
|
+
proc{Sequel::Postgres::PGArray.register('foo', :scalar_oid=>16){}}.should raise_error(Sequel::Error)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it "should support registering custom types with :oid option" do
|
|
294
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>1)
|
|
295
|
+
Sequel::Postgres::PG_TYPES[1].call('{1}').should be_a_kind_of(Sequel::Postgres::PGArray)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
it "should support registering custom types with :parser=>:json option" do
|
|
299
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>2, :parser=>:json)
|
|
300
|
+
Sequel::Postgres::PG_TYPES[2].should be_a_kind_of(Sequel::Postgres::PGArray::JSONCreator)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "should support registering converters with :parser=>:json option" do
|
|
304
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>4, :parser=>:json){|s| s * 2}
|
|
305
|
+
Sequel::Postgres::PG_TYPES[4].call('{{1, 2}, {3, 4}}').should == [[2, 4], [6, 8]]
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it "should support registering custom types with :array_type option" do
|
|
309
|
+
Sequel::Postgres::PGArray.register('foo', :oid=>3, :array_type=>:blah)
|
|
310
|
+
@db.literal(Sequel::Postgres::PG_TYPES[3].call('{}')).should == 'ARRAY[]::blah[]'
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it "should use and not override existing database typecast method if :typecast_method option is given" do
|
|
314
|
+
Sequel::Postgres::PGArray.register('foo', :typecast_method=>:float)
|
|
315
|
+
@db.fetch = [{:name=>'id', :db_type=>'foo[]'}]
|
|
316
|
+
@db.schema(:items).map{|e| e[1][:type]}.should == [:float_array]
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
it "should set appropriate timestamp conversion procs when getting conversion procs" do
|
|
320
|
+
procs = @db.conversion_procs
|
|
321
|
+
procs[1185].call('{"2011-10-20 11:12:13"}').should == [Time.local(2011, 10, 20, 11, 12, 13)]
|
|
322
|
+
procs[1115].call('{"2011-10-20 11:12:13"}').should == [Time.local(2011, 10, 20, 11, 12, 13)]
|
|
323
|
+
end
|
|
324
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
|
+
|
|
3
|
+
describe "pg_auto_parameterize extension" do
|
|
4
|
+
before do
|
|
5
|
+
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
|
6
|
+
@db.synchronize{|c| def c.escape_bytea(v) v*2 end}
|
|
7
|
+
@db.extend_datasets{def use_cursor(*) clone end}
|
|
8
|
+
@db.extension :pg_auto_parameterize
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should automatically parameterize queries strings, blobs, numerics, dates, and times" do
|
|
12
|
+
pr = proc do |ds, sql, *args|
|
|
13
|
+
arg = args[0]
|
|
14
|
+
parg = args[1] || arg
|
|
15
|
+
s = ds.filter(:a=>arg).sql
|
|
16
|
+
s.should == sql
|
|
17
|
+
s.args.should == (parg == :nil ? nil : [parg])
|
|
18
|
+
end
|
|
19
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::int4)', 1)
|
|
20
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::int8)', 18446744073709551616)
|
|
21
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::double precision)', 1.1)
|
|
22
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::numeric)', BigDecimal.new('1.01'))
|
|
23
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1)', "a")
|
|
24
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::bytea)', Sequel.blob("a\0b"))
|
|
25
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = 1)', Sequel.lit('1'), :nil)
|
|
26
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::time)', Sequel::SQLTime.create(1, 2, 3, 500000))
|
|
27
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::date)', Date.today)
|
|
28
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::timestamp)', DateTime.new(2012, 1, 2, 3, 4, 5))
|
|
29
|
+
pr.call(@db[:table], 'SELECT * FROM table WHERE (a = $1::timestamp)', Time.utc(2012, 1, 2, 3, 4, 5))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should extract parameters from query string when executing" do
|
|
33
|
+
@db.fetch = {:a=>1}
|
|
34
|
+
@db.numrows = 1
|
|
35
|
+
@db.autoid = 1
|
|
36
|
+
|
|
37
|
+
@db[:table].filter(:a=>1).all.should == [{:a=>1}]
|
|
38
|
+
@db.sqls.should == ['SELECT * FROM table WHERE (a = $1::int4) -- args: [1]']
|
|
39
|
+
|
|
40
|
+
@db[:table].filter(:a=>1).update(:b=>'a').should == 1
|
|
41
|
+
@db.sqls.should == ['UPDATE table SET b = $1 WHERE (a = $2::int4) -- args: ["a", 1]']
|
|
42
|
+
|
|
43
|
+
@db[:table].filter(:a=>1).delete.should == 1
|
|
44
|
+
@db.sqls.should == ['DELETE FROM table WHERE (a = $1::int4) -- args: [1]']
|
|
45
|
+
|
|
46
|
+
@db[:table].insert(:a=>1).should == 1
|
|
47
|
+
@db.sqls.should == ['INSERT INTO table (a) VALUES ($1::int4) RETURNING id -- args: [1]']
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should not automatically paramiterize if no_auto_parameterize is used" do
|
|
51
|
+
@db[:table].no_auto_parameterize.filter(:a=>1).sql.should == 'SELECT * FROM table WHERE (a = 1)'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should not automatically parameterize prepared statements" do
|
|
55
|
+
@db[:table].filter(:a=>1, :b=>:$b).prepare(:select).sql.should =~ /SELECT \* FROM table WHERE \(\((a = 1|b = \$b)\) AND \((a = 1|b = \$b)\)\)/
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should show args with string when inspecting SQL " do
|
|
59
|
+
@db[:table].filter(:a=>1).sql.inspect.should == '"SELECT * FROM table WHERE (a = $1::int4); [1]"'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should not auto parameterize when using cursors" do
|
|
63
|
+
@db[:table].filter(:a=>1).use_cursor.opts[:no_auto_parameterize].should be_true
|
|
64
|
+
end
|
|
65
|
+
end
|