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
data/spec/core/dataset_spec.rb
CHANGED
|
@@ -60,12 +60,6 @@ describe "Dataset" do
|
|
|
60
60
|
db = Sequel::Database.new(:identifier_output_method=>:downcase)
|
|
61
61
|
db[:a].identifier_output_method.should == :downcase
|
|
62
62
|
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
describe "Dataset" do
|
|
66
|
-
before do
|
|
67
|
-
@dataset = Sequel::Dataset.new("db")
|
|
68
|
-
end
|
|
69
63
|
|
|
70
64
|
specify "should have quote_identifiers= method which changes literalization of identifiers" do
|
|
71
65
|
@dataset.quote_identifiers = true
|
|
@@ -111,27 +105,25 @@ describe "Dataset#clone" do
|
|
|
111
105
|
|
|
112
106
|
specify "should create an exact copy of the dataset" do
|
|
113
107
|
@dataset.row_proc = Proc.new{|r| r}
|
|
114
|
-
|
|
108
|
+
clone = @dataset.clone
|
|
115
109
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
110
|
+
clone.object_id.should_not === @dataset.object_id
|
|
111
|
+
clone.class.should == @dataset.class
|
|
112
|
+
clone.db.should == @dataset.db
|
|
113
|
+
clone.opts.should == @dataset.opts
|
|
114
|
+
clone.row_proc.should == @dataset.row_proc
|
|
120
115
|
end
|
|
121
116
|
|
|
122
117
|
specify "should deep-copy the dataset opts" do
|
|
123
|
-
|
|
118
|
+
clone = @dataset.clone
|
|
124
119
|
|
|
125
|
-
|
|
120
|
+
clone.opts.should_not equal(@dataset.opts)
|
|
126
121
|
@dataset.filter!(:a => 'b')
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
clone
|
|
132
|
-
clone.class.should == @dataset.class
|
|
133
|
-
clone.db.should == @dataset.db
|
|
134
|
-
clone.opts.should == @dataset.opts
|
|
122
|
+
clone.opts[:filter].should be_nil
|
|
123
|
+
|
|
124
|
+
clone = @dataset.clone(:from => [:other])
|
|
125
|
+
@dataset.opts[:from].should == [:items]
|
|
126
|
+
clone.opts[:from].should == [:other]
|
|
135
127
|
end
|
|
136
128
|
|
|
137
129
|
specify "should merge the specified options" do
|
|
@@ -144,12 +136,6 @@ describe "Dataset#clone" do
|
|
|
144
136
|
clone.opts.should == {:from => [:other]}
|
|
145
137
|
end
|
|
146
138
|
|
|
147
|
-
specify "should create a clone with a deep copy of options" do
|
|
148
|
-
clone = @dataset.clone(:from => [:other])
|
|
149
|
-
@dataset.opts[:from].should == [:items]
|
|
150
|
-
clone.opts[:from].should == [:other]
|
|
151
|
-
end
|
|
152
|
-
|
|
153
139
|
specify "should return an object with the same modules included" do
|
|
154
140
|
m = Module.new do
|
|
155
141
|
def __xyz__; "xyz"; end
|
|
@@ -161,7 +147,7 @@ end
|
|
|
161
147
|
|
|
162
148
|
describe "Dataset#==" do
|
|
163
149
|
before do
|
|
164
|
-
@db =
|
|
150
|
+
@db = Sequel.mock
|
|
165
151
|
@h = {}
|
|
166
152
|
end
|
|
167
153
|
|
|
@@ -170,7 +156,7 @@ describe "Dataset#==" do
|
|
|
170
156
|
end
|
|
171
157
|
|
|
172
158
|
specify "should be different for datasets with different dbs" do
|
|
173
|
-
@db[:t].should_not ==
|
|
159
|
+
@db[:t].should_not == Sequel.mock[:t]
|
|
174
160
|
end
|
|
175
161
|
|
|
176
162
|
specify "should be different for datasets with different opts" do
|
|
@@ -186,7 +172,7 @@ end
|
|
|
186
172
|
|
|
187
173
|
describe "Dataset#hash" do
|
|
188
174
|
before do
|
|
189
|
-
@db =
|
|
175
|
+
@db = Sequel.mock
|
|
190
176
|
@h = {}
|
|
191
177
|
end
|
|
192
178
|
|
|
@@ -197,7 +183,7 @@ describe "Dataset#hash" do
|
|
|
197
183
|
end
|
|
198
184
|
|
|
199
185
|
specify "should be different for datasets with different dbs" do
|
|
200
|
-
@db[:t].hash.should_not ==
|
|
186
|
+
@db[:t].hash.should_not == Sequel.mock[:t].hash
|
|
201
187
|
end
|
|
202
188
|
|
|
203
189
|
specify "should be different for datasets with different opts" do
|
|
@@ -228,10 +214,21 @@ describe "A simple dataset" do
|
|
|
228
214
|
@dataset.truncate_sql.should == 'TRUNCATE TABLE test'
|
|
229
215
|
end
|
|
230
216
|
|
|
217
|
+
specify "should format a truncate statement with multiple tables if supported" do
|
|
218
|
+
@dataset.meta_def(:check_truncation_allowed!){}
|
|
219
|
+
@dataset.from(:test, :test2).truncate_sql.should == 'TRUNCATE TABLE test, test2'
|
|
220
|
+
end
|
|
221
|
+
|
|
231
222
|
specify "should format an insert statement with default values" do
|
|
232
223
|
@dataset.insert_sql.should == 'INSERT INTO test DEFAULT VALUES'
|
|
233
224
|
end
|
|
234
225
|
|
|
226
|
+
specify "should use a single column with a default value when the dataset doesn't support using insert statement with default values" do
|
|
227
|
+
@dataset.meta_def(:insert_supports_empty_values?){false}
|
|
228
|
+
@dataset.meta_def(:columns){[:a, :b]}
|
|
229
|
+
@dataset.insert_sql.should == 'INSERT INTO test (b) VALUES (DEFAULT)'
|
|
230
|
+
end
|
|
231
|
+
|
|
235
232
|
specify "should format an insert statement with hash" do
|
|
236
233
|
@dataset.insert_sql(:name => 'wxyz', :price => 342).
|
|
237
234
|
should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
|
|
@@ -244,46 +241,29 @@ describe "A simple dataset" do
|
|
|
244
241
|
should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
|
|
245
242
|
end
|
|
246
243
|
|
|
247
|
-
specify "should format an insert statement with an object that respond_to? :values" do
|
|
248
|
-
dbb = Sequel::Database.new
|
|
249
|
-
|
|
250
|
-
v = Object.new
|
|
251
|
-
def v.values; {:a => 1}; end
|
|
252
|
-
|
|
253
|
-
@dataset.insert_sql(v).should == "INSERT INTO test (a) VALUES (1)"
|
|
254
|
-
|
|
255
|
-
def v.values; {}; end
|
|
256
|
-
@dataset.insert_sql(v).should == "INSERT INTO test DEFAULT VALUES"
|
|
257
|
-
end
|
|
258
|
-
|
|
259
244
|
specify "should format an insert statement with an arbitrary value" do
|
|
260
245
|
@dataset.insert_sql(123).should == "INSERT INTO test VALUES (123)"
|
|
261
246
|
end
|
|
262
247
|
|
|
263
248
|
specify "should format an insert statement with sub-query" do
|
|
264
|
-
@
|
|
265
|
-
@dataset.insert_sql(@sub).should == \
|
|
266
|
-
"INSERT INTO test SELECT * FROM something WHERE (x = 2)"
|
|
249
|
+
@dataset.insert_sql(@dataset.from(:something).filter(:x => 2)).should == "INSERT INTO test SELECT * FROM something WHERE (x = 2)"
|
|
267
250
|
end
|
|
268
251
|
|
|
269
252
|
specify "should format an insert statement with array" do
|
|
270
|
-
@dataset.insert_sql('a', 2, 6.5).should ==
|
|
271
|
-
"INSERT INTO test VALUES ('a', 2, 6.5)"
|
|
253
|
+
@dataset.insert_sql('a', 2, 6.5).should == "INSERT INTO test VALUES ('a', 2, 6.5)"
|
|
272
254
|
end
|
|
273
255
|
|
|
274
256
|
specify "should format an update statement" do
|
|
275
|
-
@dataset.update_sql(:name => 'abc').should ==
|
|
276
|
-
"UPDATE test SET name = 'abc'"
|
|
257
|
+
@dataset.update_sql(:name => 'abc').should == "UPDATE test SET name = 'abc'"
|
|
277
258
|
end
|
|
278
259
|
|
|
279
260
|
specify "should be able to return rows for arbitrary SQL" do
|
|
280
|
-
@dataset.clone(:sql => 'xxx yyy zzz').select_sql.should ==
|
|
281
|
-
"xxx yyy zzz"
|
|
261
|
+
@dataset.clone(:sql => 'xxx yyy zzz').select_sql.should == "xxx yyy zzz"
|
|
282
262
|
end
|
|
283
263
|
|
|
284
264
|
specify "should use the :sql option for all sql methods" do
|
|
285
265
|
sql = "X"
|
|
286
|
-
ds =
|
|
266
|
+
ds = @dataset.clone(:sql=>sql)
|
|
287
267
|
ds.sql.should == sql
|
|
288
268
|
ds.select_sql.should == sql
|
|
289
269
|
ds.insert_sql.should == sql
|
|
@@ -338,37 +318,37 @@ describe "Dataset#unused_table_alias" do
|
|
|
338
318
|
@ds.unused_table_alias('test').should == :test_0
|
|
339
319
|
@ds.unused_table_alias(:b__t___test).should == :test_0
|
|
340
320
|
@ds.unused_table_alias(:b__test).should == :test_0
|
|
341
|
-
@ds.unused_table_alias(
|
|
342
|
-
@ds.unused_table_alias(:b.as(:test)).should == :test_0
|
|
343
|
-
@ds.unused_table_alias(:b.as(:test
|
|
344
|
-
@ds.unused_table_alias(:b.as('test')).should == :test_0
|
|
345
|
-
@ds.unused_table_alias(:test
|
|
321
|
+
@ds.unused_table_alias(Sequel.qualify(:b, :test)).should == :test_0
|
|
322
|
+
@ds.unused_table_alias(Sequel.expr(:b).as(:test)).should == :test_0
|
|
323
|
+
@ds.unused_table_alias(Sequel.expr(:b).as(Sequel.identifier(:test))).should == :test_0
|
|
324
|
+
@ds.unused_table_alias(Sequel.expr(:b).as('test')).should == :test_0
|
|
325
|
+
@ds.unused_table_alias(Sequel.identifier(:test)).should == :test_0
|
|
346
326
|
end
|
|
347
327
|
end
|
|
348
328
|
|
|
349
329
|
describe "Dataset#exists" do
|
|
350
330
|
before do
|
|
351
|
-
@ds1 = Sequel
|
|
352
|
-
@ds2 = @ds1.filter(:price
|
|
353
|
-
@ds3 = @ds1.filter(:price
|
|
331
|
+
@ds1 = Sequel.mock[:test]
|
|
332
|
+
@ds2 = @ds1.filter(Sequel.expr(:price) < 100)
|
|
333
|
+
@ds3 = @ds1.filter(Sequel.expr(:price) > 50)
|
|
354
334
|
end
|
|
355
335
|
|
|
356
336
|
specify "should work in filters" do
|
|
357
337
|
@ds1.filter(@ds2.exists).sql.should ==
|
|
358
338
|
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
|
359
339
|
@ds1.filter(@ds2.exists & @ds3.exists).sql.should ==
|
|
360
|
-
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)) AND EXISTS (SELECT * FROM test WHERE (price > 50)))'
|
|
340
|
+
'SELECT * FROM test WHERE ((EXISTS (SELECT * FROM test WHERE (price < 100))) AND (EXISTS (SELECT * FROM test WHERE (price > 50))))'
|
|
361
341
|
end
|
|
362
342
|
|
|
363
343
|
specify "should work in select" do
|
|
364
344
|
@ds1.select(@ds2.exists.as(:a), @ds3.exists.as(:b)).sql.should ==
|
|
365
|
-
'SELECT EXISTS (SELECT * FROM test WHERE (price < 100)) AS a, EXISTS (SELECT * FROM test WHERE (price > 50)) AS b FROM test'
|
|
345
|
+
'SELECT (EXISTS (SELECT * FROM test WHERE (price < 100))) AS a, (EXISTS (SELECT * FROM test WHERE (price > 50))) AS b FROM test'
|
|
366
346
|
end
|
|
367
347
|
end
|
|
368
348
|
|
|
369
349
|
describe "Dataset#where" do
|
|
370
350
|
before do
|
|
371
|
-
@dataset = Sequel
|
|
351
|
+
@dataset = Sequel.mock[:test]
|
|
372
352
|
@d1 = @dataset.where(:region => 'Asia')
|
|
373
353
|
@d2 = @dataset.where('region = ?', 'Asia')
|
|
374
354
|
@d3 = @dataset.where("a = 1")
|
|
@@ -390,8 +370,7 @@ describe "Dataset#where" do
|
|
|
390
370
|
end
|
|
391
371
|
|
|
392
372
|
specify "should work with a string with placeholders and arguments for those placeholders" do
|
|
393
|
-
@dataset.where('price < ? AND id in ?', 100, [1, 2, 3]).select_sql.should ==
|
|
394
|
-
"SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
|
373
|
+
@dataset.where('price < ? AND id in ?', 100, [1, 2, 3]).select_sql.should == "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
|
395
374
|
end
|
|
396
375
|
|
|
397
376
|
specify "should not modify passed array with placeholders" do
|
|
@@ -418,14 +397,12 @@ describe "Dataset#where" do
|
|
|
418
397
|
b.should == a
|
|
419
398
|
end
|
|
420
399
|
|
|
421
|
-
specify "should not replace named placeholders that don't
|
|
422
|
-
@dataset.where('price < :price AND id in :ids', :price=>100).select_sql.should ==
|
|
423
|
-
"SELECT * FROM test WHERE (price < 100 AND id in :ids)"
|
|
400
|
+
specify "should not replace named placeholders that don't exist in the hash" do
|
|
401
|
+
@dataset.where('price < :price AND id in :ids', :price=>100).select_sql.should == "SELECT * FROM test WHERE (price < 100 AND id in :ids)"
|
|
424
402
|
end
|
|
425
403
|
|
|
426
404
|
specify "should handle partial names" do
|
|
427
|
-
@dataset.where('price < :price AND id = :p', :p=>2, :price=>100).select_sql.should ==
|
|
428
|
-
"SELECT * FROM test WHERE (price < 100 AND id = 2)"
|
|
405
|
+
@dataset.where('price < :price AND id = :p', :p=>2, :price=>100).select_sql.should == "SELECT * FROM test WHERE (price < 100 AND id = 2)"
|
|
429
406
|
end
|
|
430
407
|
|
|
431
408
|
specify "should affect select, delete and update statements" do
|
|
@@ -445,180 +422,182 @@ describe "Dataset#where" do
|
|
|
445
422
|
|
|
446
423
|
specify "should be composable using AND operator (for scoping)" do
|
|
447
424
|
# hashes are merged, no problem
|
|
448
|
-
@d1.where(:size => 'big').select_sql.should ==
|
|
449
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (size = 'big'))"
|
|
425
|
+
@d1.where(:size => 'big').select_sql.should == "SELECT * FROM test WHERE ((region = 'Asia') AND (size = 'big'))"
|
|
450
426
|
|
|
451
427
|
# hash and string
|
|
452
|
-
@d1.where('population > 1000').select_sql.should ==
|
|
453
|
-
|
|
454
|
-
@d1.where('(a > 1) OR (b < 2)').select_sql.should ==
|
|
455
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND ((a > 1) OR (b < 2)))"
|
|
428
|
+
@d1.where('population > 1000').select_sql.should == "SELECT * FROM test WHERE ((region = 'Asia') AND (population > 1000))"
|
|
429
|
+
@d1.where('(a > 1) OR (b < 2)').select_sql.should == "SELECT * FROM test WHERE ((region = 'Asia') AND ((a > 1) OR (b < 2)))"
|
|
456
430
|
|
|
457
431
|
# hash and array
|
|
458
|
-
@d1.where('GDP > ?', 1000).select_sql.should ==
|
|
459
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
|
432
|
+
@d1.where('GDP > ?', 1000).select_sql.should == "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
|
460
433
|
|
|
461
434
|
# array and array
|
|
462
|
-
@d2.where('GDP > ?', 1000).select_sql.should ==
|
|
463
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
|
435
|
+
@d2.where('GDP > ?', 1000).select_sql.should == "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
|
464
436
|
|
|
465
437
|
# array and hash
|
|
466
|
-
@d2.where(:name => ['Japan', 'China']).select_sql.should ==
|
|
467
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
|
|
438
|
+
@d2.where(:name => ['Japan', 'China']).select_sql.should == "SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
|
|
468
439
|
|
|
469
440
|
# array and string
|
|
470
|
-
@d2.where('GDP > ?').select_sql.should ==
|
|
471
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
|
|
441
|
+
@d2.where('GDP > ?').select_sql.should == "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
|
|
472
442
|
|
|
473
443
|
# string and string
|
|
474
|
-
@d3.where('b = 2').select_sql.should ==
|
|
475
|
-
"SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
|
|
444
|
+
@d3.where('b = 2').select_sql.should == "SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
|
|
476
445
|
|
|
477
446
|
# string and hash
|
|
478
|
-
@d3.where(:c => 3).select_sql.should ==
|
|
479
|
-
"SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
|
|
447
|
+
@d3.where(:c => 3).select_sql.should == "SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
|
|
480
448
|
|
|
481
449
|
# string and array
|
|
482
|
-
@d3.where('d = ?', 4).select_sql.should ==
|
|
483
|
-
"SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
|
|
450
|
+
@d3.where('d = ?', 4).select_sql.should == "SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
|
|
484
451
|
end
|
|
485
452
|
|
|
486
453
|
specify "should be composable using AND operator (for scoping) with block" do
|
|
487
|
-
@d3.where{
|
|
488
|
-
"SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
|
|
454
|
+
@d3.where{e < 5}.select_sql.should == "SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
|
|
489
455
|
end
|
|
490
456
|
|
|
491
457
|
specify "should accept ranges" do
|
|
492
|
-
@dataset.filter(:id => 4..7).sql.should ==
|
|
493
|
-
|
|
494
|
-
@dataset.filter(:id => 4...7).sql.should ==
|
|
495
|
-
'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
|
|
458
|
+
@dataset.filter(:id => 4..7).sql.should == 'SELECT * FROM test WHERE ((id >= 4) AND (id <= 7))'
|
|
459
|
+
@dataset.filter(:id => 4...7).sql.should == 'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
|
|
496
460
|
|
|
497
|
-
@dataset.filter(:table__id => 4..7).sql.should ==
|
|
498
|
-
|
|
499
|
-
@dataset.filter(:table__id => 4...7).sql.should ==
|
|
500
|
-
'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id < 7))'
|
|
461
|
+
@dataset.filter(:table__id => 4..7).sql.should == 'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id <= 7))'
|
|
462
|
+
@dataset.filter(:table__id => 4...7).sql.should == 'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id < 7))'
|
|
501
463
|
end
|
|
502
464
|
|
|
503
465
|
specify "should accept nil" do
|
|
504
|
-
@dataset.filter(:owner_id => nil).sql.should ==
|
|
505
|
-
'SELECT * FROM test WHERE (owner_id IS NULL)'
|
|
466
|
+
@dataset.filter(:owner_id => nil).sql.should == 'SELECT * FROM test WHERE (owner_id IS NULL)'
|
|
506
467
|
end
|
|
507
468
|
|
|
508
469
|
specify "should accept a subquery" do
|
|
509
|
-
@dataset.filter('gdp > ?', @d1.select(
|
|
510
|
-
"SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
|
470
|
+
@dataset.filter('gdp > ?', @d1.select(Sequel.function(:avg, :gdp))).sql.should == "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
|
511
471
|
end
|
|
512
472
|
|
|
473
|
+
specify "should handle all types of IN/NOT IN queries with empty arrays" do
|
|
474
|
+
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (id != id)"
|
|
475
|
+
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
476
|
+
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (id = id)"
|
|
477
|
+
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
specify "should handle all types of IN/NOT IN queries with empty arrays" do
|
|
481
|
+
begin
|
|
482
|
+
Sequel.empty_array_handle_nulls = false
|
|
483
|
+
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
484
|
+
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
485
|
+
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
486
|
+
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
487
|
+
ensure
|
|
488
|
+
Sequel.empty_array_handle_nulls = true
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
513
492
|
specify "should handle all types of IN/NOT IN queries" do
|
|
514
493
|
@dataset.filter(:id => @d1.select(:id)).sql.should == "SELECT * FROM test WHERE (id IN (SELECT id FROM test WHERE (region = 'Asia')))"
|
|
515
|
-
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (id != id)"
|
|
516
494
|
@dataset.filter(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id IN (1, 2))"
|
|
517
495
|
@dataset.filter([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
|
|
518
|
-
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1
|
|
519
|
-
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
|
|
496
|
+
@dataset.filter([:id1, :id2] => Sequel.value_list([[1, 2], [3,4]])).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
|
|
520
497
|
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
|
|
521
498
|
|
|
522
499
|
@dataset.exclude(:id => @d1.select(:id)).sql.should == "SELECT * FROM test WHERE (id NOT IN (SELECT id FROM test WHERE (region = 'Asia')))"
|
|
523
|
-
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
524
500
|
@dataset.exclude(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id NOT IN (1, 2))"
|
|
525
501
|
@dataset.exclude([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
|
|
526
|
-
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (
|
|
527
|
-
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
|
|
502
|
+
@dataset.exclude([:id1, :id2] => Sequel.value_list([[1, 2], [3,4]])).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
|
|
528
503
|
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
|
|
529
504
|
end
|
|
530
505
|
|
|
531
506
|
specify "should handle IN/NOT IN queries with multiple columns and an array where the database doesn't support it" do
|
|
532
507
|
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
533
|
-
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1
|
|
534
|
-
@dataset.
|
|
535
|
-
@dataset.
|
|
536
|
-
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]
|
|
508
|
+
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
509
|
+
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
510
|
+
@dataset.filter([:id1, :id2] => Sequel.value_list([[1, 2], [3,4]])).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
511
|
+
@dataset.exclude([:id1, :id2] => Sequel.value_list([[1, 2], [3,4]])).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
537
512
|
end
|
|
538
513
|
|
|
539
514
|
specify "should handle IN/NOT IN queries with multiple columns and a dataset where the database doesn't support it" do
|
|
540
515
|
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
@sql_used = sql
|
|
544
|
-
@columns = [:id1, :id2]
|
|
545
|
-
yield(:id1=>1, :id2=>2)
|
|
546
|
-
yield(:id1=>3, :id2=>4)
|
|
547
|
-
end
|
|
548
|
-
d1.instance_variable_get(:@sql_used).should == nil
|
|
516
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
517
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
549
518
|
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
550
|
-
|
|
551
|
-
d1.instance_variable_set(:@sql_used, nil)
|
|
519
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
552
520
|
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
553
|
-
|
|
521
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
554
522
|
end
|
|
555
523
|
|
|
556
524
|
specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it" do
|
|
557
525
|
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
@sql_used = sql
|
|
561
|
-
@columns = [:id1, :id2]
|
|
562
|
-
end
|
|
563
|
-
d1.instance_variable_get(:@sql_used).should == nil
|
|
526
|
+
db = Sequel.mock
|
|
527
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
564
528
|
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
529
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
530
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
|
|
531
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it with correct NULL handling" do
|
|
535
|
+
begin
|
|
536
|
+
Sequel.empty_array_handle_nulls = false
|
|
537
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
538
|
+
db = Sequel.mock
|
|
539
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
540
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
541
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
542
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
543
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
544
|
+
ensure
|
|
545
|
+
Sequel.empty_array_handle_nulls = true
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
specify "should handle IN/NOT IN queries for datasets with row_procs" do
|
|
550
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
551
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
552
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
553
|
+
d1.row_proc = proc{|h| Object.new}
|
|
554
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
555
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
556
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
557
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
569
558
|
end
|
|
570
559
|
|
|
571
560
|
specify "should accept a subquery for an EXISTS clause" do
|
|
572
|
-
a = @dataset.filter(:price
|
|
573
|
-
@dataset.filter(a.exists).sql.should ==
|
|
574
|
-
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
|
561
|
+
a = @dataset.filter(Sequel.expr(:price) < 100)
|
|
562
|
+
@dataset.filter(a.exists).sql.should == 'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
|
575
563
|
end
|
|
576
564
|
|
|
577
565
|
specify "should accept proc expressions" do
|
|
578
|
-
d = @d1.select(
|
|
579
|
-
@dataset.filter
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
@dataset.filter
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
@dataset.filter {(:a.sql_number >= 1) & (:b.sql_number <= 2)}.sql.should ==
|
|
586
|
-
'SELECT * FROM test WHERE ((a >= 1) AND (b <= 2))'
|
|
587
|
-
|
|
588
|
-
@dataset.filter {:c.like 'ABC%'}.sql.should ==
|
|
589
|
-
"SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
|
590
|
-
|
|
591
|
-
@dataset.filter {:c.like 'ABC%'}.sql.should ==
|
|
592
|
-
"SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
|
593
|
-
|
|
594
|
-
@dataset.filter {:c.like 'ABC%', '%XYZ'}.sql.should ==
|
|
595
|
-
"SELECT * FROM test WHERE ((c LIKE 'ABC%') OR (c LIKE '%XYZ'))"
|
|
566
|
+
d = @d1.select(Sequel.function(:avg, :gdp))
|
|
567
|
+
@dataset.filter{gdp > d}.sql.should == "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
|
568
|
+
@dataset.filter{a < 1}.sql.should == 'SELECT * FROM test WHERE (a < 1)'
|
|
569
|
+
@dataset.filter{(a >= 1) & (b <= 2)}.sql.should == 'SELECT * FROM test WHERE ((a >= 1) AND (b <= 2))'
|
|
570
|
+
@dataset.filter{c.like 'ABC%'}.sql.should == "SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
|
571
|
+
@dataset.filter{c.like 'ABC%', '%XYZ'}.sql.should == "SELECT * FROM test WHERE ((c LIKE 'ABC%') OR (c LIKE '%XYZ'))"
|
|
596
572
|
end
|
|
597
573
|
|
|
598
574
|
specify "should work for grouped datasets" do
|
|
599
|
-
@dataset.group(:a).filter(:b => 1).sql.should ==
|
|
600
|
-
'SELECT * FROM test WHERE (b = 1) GROUP BY a'
|
|
575
|
+
@dataset.group(:a).filter(:b => 1).sql.should == 'SELECT * FROM test WHERE (b = 1) GROUP BY a'
|
|
601
576
|
end
|
|
602
577
|
|
|
603
578
|
specify "should accept true and false as arguments" do
|
|
604
|
-
@dataset.filter(true).sql.should ==
|
|
605
|
-
|
|
606
|
-
@dataset.filter(false).sql.should ==
|
|
607
|
-
|
|
579
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE 't'"
|
|
580
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE 't'"
|
|
581
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
582
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
specify "should use boolean expression if dataset does not support where true/false" do
|
|
586
|
+
def @dataset.supports_where_true?() false end
|
|
587
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
588
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
589
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
590
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
608
591
|
end
|
|
609
592
|
|
|
610
593
|
specify "should allow the use of multiple arguments" do
|
|
611
|
-
@dataset.filter(:a, :b).sql.should ==
|
|
612
|
-
|
|
613
|
-
@dataset.filter(:a, :b=>1).sql.should ==
|
|
614
|
-
'SELECT * FROM test WHERE (a AND (b = 1))'
|
|
615
|
-
@dataset.filter(:a, :c.sql_number > 3, :b=>1).sql.should ==
|
|
616
|
-
'SELECT * FROM test WHERE (a AND (c > 3) AND (b = 1))'
|
|
594
|
+
@dataset.filter(:a, :b).sql.should == 'SELECT * FROM test WHERE (a AND b)'
|
|
595
|
+
@dataset.filter(:a, :b=>1).sql.should == 'SELECT * FROM test WHERE (a AND (b = 1))'
|
|
596
|
+
@dataset.filter(:a, Sequel.expr(:c) > 3, :b=>1).sql.should == 'SELECT * FROM test WHERE (a AND (c > 3) AND (b = 1))'
|
|
617
597
|
end
|
|
618
598
|
|
|
619
599
|
specify "should allow the use of blocks and arguments simultaneously" do
|
|
620
|
-
@dataset.filter(:zz
|
|
621
|
-
'SELECT * FROM test WHERE ((zz < 3) AND (yy > 3))'
|
|
600
|
+
@dataset.filter(Sequel.expr(:zz) < 3){yy > 3}.sql.should == 'SELECT * FROM test WHERE ((zz < 3) AND (yy > 3))'
|
|
622
601
|
end
|
|
623
602
|
|
|
624
603
|
specify "should yield a VirtualRow to the block" do
|
|
@@ -642,8 +621,8 @@ describe "Dataset#where" do
|
|
|
642
621
|
end
|
|
643
622
|
|
|
644
623
|
specify "should raise an error if a NumericExpression or StringExpression is used" do
|
|
645
|
-
proc{@dataset.filter(:x + 1)}.should raise_error(Sequel::Error)
|
|
646
|
-
proc{@dataset.filter(:x.sql_string)}.should raise_error(Sequel::Error)
|
|
624
|
+
proc{@dataset.filter(Sequel.expr(:x) + 1)}.should raise_error(Sequel::Error)
|
|
625
|
+
proc{@dataset.filter(Sequel.expr(:x).sql_string)}.should raise_error(Sequel::Error)
|
|
647
626
|
end
|
|
648
627
|
end
|
|
649
628
|
|
|
@@ -658,33 +637,25 @@ describe "Dataset#or" do
|
|
|
658
637
|
end
|
|
659
638
|
|
|
660
639
|
specify "should add an alternative expression to the where clause" do
|
|
661
|
-
@d1.or(:y => 2).sql.should ==
|
|
662
|
-
'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
|
640
|
+
@d1.or(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
|
663
641
|
end
|
|
664
642
|
|
|
665
643
|
specify "should accept all forms of filters" do
|
|
666
|
-
@d1.or('y > ?', 2).sql.should ==
|
|
667
|
-
|
|
668
|
-
@d1.or(:yy.sql_number > 3).sql.should ==
|
|
669
|
-
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
644
|
+
@d1.or('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
|
645
|
+
@d1.or(Sequel.expr(:yy) > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
670
646
|
end
|
|
671
647
|
|
|
672
648
|
specify "should accept blocks passed to filter" do
|
|
673
|
-
@d1.or{
|
|
674
|
-
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
649
|
+
@d1.or{yy > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
675
650
|
end
|
|
676
651
|
|
|
677
652
|
specify "should correctly add parens to give predictable results" do
|
|
678
|
-
@d1.filter(:y => 2).or(:z => 3).sql.should ==
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
@d1.or(:y => 2).filter(:z => 3).sql.should ==
|
|
682
|
-
'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
653
|
+
@d1.filter(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
654
|
+
@d1.or(:y => 2).filter(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
683
655
|
end
|
|
684
656
|
|
|
685
657
|
specify "should allow the use of blocks and arguments simultaneously" do
|
|
686
|
-
@d1.or(:zz
|
|
687
|
-
'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
|
658
|
+
@d1.or(Sequel.expr(:zz) < 3){yy > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
|
688
659
|
end
|
|
689
660
|
end
|
|
690
661
|
|
|
@@ -697,34 +668,25 @@ describe "Dataset#and" do
|
|
|
697
668
|
specify "should raise if no filter exists" do
|
|
698
669
|
proc {@dataset.and(:a => 1)}.should raise_error(Sequel::Error)
|
|
699
670
|
proc {@dataset.where(:a => 1).group(:t).and(:b => 2)}.should_not raise_error(Sequel::Error)
|
|
700
|
-
@dataset.where(:a => 1).group(:t).and(:b => 2).sql ==
|
|
701
|
-
"SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
|
|
671
|
+
@dataset.where(:a => 1).group(:t).and(:b => 2).sql.should == "SELECT * FROM test WHERE ((a = 1) AND (b = 2)) GROUP BY t"
|
|
702
672
|
end
|
|
703
673
|
|
|
704
674
|
specify "should add an alternative expression to the where clause" do
|
|
705
|
-
@d1.and(:y => 2).sql.should ==
|
|
706
|
-
'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
|
675
|
+
@d1.and(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
|
707
676
|
end
|
|
708
677
|
|
|
709
|
-
specify "should accept
|
|
710
|
-
|
|
711
|
-
@d1.and(
|
|
712
|
-
'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
|
713
|
-
@d1.and(:yy.sql_number > 3).sql.should ==
|
|
714
|
-
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
678
|
+
specify "should accept different types of filters" do
|
|
679
|
+
@d1.and('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
|
680
|
+
@d1.and(Sequel.expr(:yy) > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
715
681
|
end
|
|
716
682
|
|
|
717
683
|
specify "should accept blocks passed to filter" do
|
|
718
|
-
@d1.and
|
|
719
|
-
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
684
|
+
@d1.and{yy > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
720
685
|
end
|
|
721
686
|
|
|
722
687
|
specify "should correctly add parens to give predictable results" do
|
|
723
|
-
@d1.or(:y => 2).and(:z => 3).sql.should ==
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
@d1.and(:y => 2).or(:z => 3).sql.should ==
|
|
727
|
-
'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
688
|
+
@d1.or(:y => 2).and(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
689
|
+
@d1.and(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
728
690
|
end
|
|
729
691
|
end
|
|
730
692
|
|
|
@@ -734,8 +696,11 @@ describe "Dataset#exclude" do
|
|
|
734
696
|
end
|
|
735
697
|
|
|
736
698
|
specify "should correctly negate the expression when one condition is given" do
|
|
737
|
-
@dataset.exclude(:region=>'Asia').select_sql.should ==
|
|
738
|
-
|
|
699
|
+
@dataset.exclude(:region=>'Asia').select_sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
specify "should affect the having clause if having clause is already used" do
|
|
703
|
+
@dataset.group_and_count(:name).having{count > 2}.exclude{count > 5}.sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name HAVING ((count > 2) AND (count <= 5))"
|
|
739
704
|
end
|
|
740
705
|
|
|
741
706
|
specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
|
|
@@ -745,30 +710,46 @@ describe "Dataset#exclude" do
|
|
|
745
710
|
end
|
|
746
711
|
|
|
747
712
|
specify "should parenthesize a single string condition correctly" do
|
|
748
|
-
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should ==
|
|
749
|
-
"SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
713
|
+
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
750
714
|
end
|
|
751
715
|
|
|
752
716
|
specify "should parenthesize an array condition correctly" do
|
|
753
|
-
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should ==
|
|
754
|
-
"SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
717
|
+
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
755
718
|
end
|
|
756
719
|
|
|
757
720
|
specify "should correctly parenthesize when it is used twice" do
|
|
758
|
-
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should ==
|
|
759
|
-
"SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
|
721
|
+
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
|
760
722
|
end
|
|
761
723
|
|
|
762
724
|
specify "should support proc expressions" do
|
|
763
|
-
@dataset.exclude{
|
|
764
|
-
'SELECT * FROM test WHERE (id >= 6)'
|
|
725
|
+
@dataset.exclude{id < 6}.sql.should == 'SELECT * FROM test WHERE (id >= 6)'
|
|
765
726
|
end
|
|
766
727
|
|
|
767
728
|
specify "should allow the use of blocks and arguments simultaneously" do
|
|
768
|
-
@dataset.exclude(:id => (7..11)){
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
729
|
+
@dataset.exclude(:id => (7..11)){id < 6}.sql.should == 'SELECT * FROM test WHERE ((id < 7) OR (id > 11) OR (id >= 6))'
|
|
730
|
+
@dataset.exclude([:id, 1], [:x, 3]){id < 6}.sql.should == 'SELECT * FROM test WHERE ((id != 1) OR (x != 3) OR (id >= 6))'
|
|
731
|
+
end
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
describe "Dataset#exclude_where" do
|
|
735
|
+
before do
|
|
736
|
+
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
specify "should correctly negate the expression and add it to the where clause" do
|
|
740
|
+
@dataset.exclude_where(:region=>'Asia').sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
741
|
+
@dataset.exclude_where(:region=>'Asia').exclude_where(:region=>'NA').sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (region != 'NA'))"
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
specify "should affect the where clause even if having clause is already used" do
|
|
745
|
+
@dataset.group_and_count(:name).having{count > 2}.exclude_where(:region=>'Asia').sql.should ==
|
|
746
|
+
"SELECT name, count(*) AS count FROM test WHERE (region != 'Asia') GROUP BY name HAVING (count > 2)"
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
describe "Dataset#exclude_having" do
|
|
751
|
+
specify "should correctly negate the expression and add it to the having clause" do
|
|
752
|
+
Sequel::Dataset.new(nil).from(:test).exclude_having{count > 2}.exclude_having{count < 0}.sql.should == "SELECT * FROM test HAVING ((count <= 2) AND (count >= 0))"
|
|
772
753
|
end
|
|
773
754
|
end
|
|
774
755
|
|
|
@@ -793,10 +774,7 @@ end
|
|
|
793
774
|
describe "Dataset#having" do
|
|
794
775
|
before do
|
|
795
776
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
796
|
-
@grouped = @dataset.group(:region).select(:region,
|
|
797
|
-
@d1 = @grouped.having('sum(population) > 10')
|
|
798
|
-
@d2 = @grouped.having(:region => 'Asia')
|
|
799
|
-
@columns = "region, sum(population), avg(gdp)"
|
|
777
|
+
@grouped = @dataset.group(:region).select(:region, Sequel.function(:sum, :population), Sequel.function(:avg, :gdp))
|
|
800
778
|
end
|
|
801
779
|
|
|
802
780
|
specify "should just clone if given an empty argument" do
|
|
@@ -806,18 +784,15 @@ describe "Dataset#having" do
|
|
|
806
784
|
end
|
|
807
785
|
|
|
808
786
|
specify "should affect select statements" do
|
|
809
|
-
@
|
|
810
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
787
|
+
@grouped.having('sum(population) > 10').select_sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
811
788
|
end
|
|
812
789
|
|
|
813
790
|
specify "should support proc expressions" do
|
|
814
|
-
@grouped.having
|
|
815
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
791
|
+
@grouped.having{Sequel.function(:sum, :population) > 10}.sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
816
792
|
end
|
|
817
793
|
|
|
818
794
|
specify "should work with and on the having clause" do
|
|
819
|
-
@grouped.having(
|
|
820
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
|
|
795
|
+
@grouped.having(Sequel.expr(:a) > 1).and(Sequel.expr(:b) < 2).sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
|
|
821
796
|
end
|
|
822
797
|
end
|
|
823
798
|
|
|
@@ -848,7 +823,7 @@ describe "a grouped dataset" do
|
|
|
848
823
|
end
|
|
849
824
|
|
|
850
825
|
specify "should format the right statement for counting (as a subquery)" do
|
|
851
|
-
db =
|
|
826
|
+
db = Sequel.mock
|
|
852
827
|
db[:test].select(:name).group(:name).count
|
|
853
828
|
db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT name FROM test GROUP BY name) AS t1 LIMIT 1"]
|
|
854
829
|
end
|
|
@@ -856,7 +831,7 @@ end
|
|
|
856
831
|
|
|
857
832
|
describe "Dataset#group_by" do
|
|
858
833
|
before do
|
|
859
|
-
@dataset = Sequel
|
|
834
|
+
@dataset = Sequel.mock[:test].group_by(:type_id)
|
|
860
835
|
end
|
|
861
836
|
|
|
862
837
|
specify "should raise when trying to generate an update statement" do
|
|
@@ -868,45 +843,102 @@ describe "Dataset#group_by" do
|
|
|
868
843
|
end
|
|
869
844
|
|
|
870
845
|
specify "should specify the grouping in generated select statement" do
|
|
871
|
-
@dataset.select_sql.should ==
|
|
872
|
-
|
|
873
|
-
@dataset.group_by(:
|
|
874
|
-
"SELECT * FROM test GROUP BY a, b"
|
|
875
|
-
@dataset.group_by(:type_id=>nil).select_sql.should ==
|
|
876
|
-
"SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
846
|
+
@dataset.select_sql.should == "SELECT * FROM test GROUP BY type_id"
|
|
847
|
+
@dataset.group_by(:a, :b).select_sql.should == "SELECT * FROM test GROUP BY a, b"
|
|
848
|
+
@dataset.group_by(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
877
849
|
end
|
|
878
850
|
|
|
879
|
-
specify "should ungroup when passed nil
|
|
880
|
-
@dataset.group_by.select_sql.should ==
|
|
881
|
-
|
|
882
|
-
@dataset.group_by(nil).select_sql.should ==
|
|
883
|
-
"SELECT * FROM test"
|
|
851
|
+
specify "should ungroup when passed nil or no arguments" do
|
|
852
|
+
@dataset.group_by.select_sql.should == "SELECT * FROM test"
|
|
853
|
+
@dataset.group_by(nil).select_sql.should == "SELECT * FROM test"
|
|
884
854
|
end
|
|
885
855
|
|
|
886
856
|
specify "should undo previous grouping" do
|
|
887
|
-
@dataset.group_by(:a).group_by(:b).select_sql.should ==
|
|
888
|
-
|
|
889
|
-
@dataset.group_by(:a, :b).group_by.select_sql.should ==
|
|
890
|
-
"SELECT * FROM test"
|
|
857
|
+
@dataset.group_by(:a).group_by(:b).select_sql.should == "SELECT * FROM test GROUP BY b"
|
|
858
|
+
@dataset.group_by(:a, :b).group_by.select_sql.should == "SELECT * FROM test"
|
|
891
859
|
end
|
|
892
860
|
|
|
893
861
|
specify "should be aliased as #group" do
|
|
894
|
-
@dataset.group(:type_id=>nil).select_sql.should ==
|
|
895
|
-
|
|
862
|
+
@dataset.group(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
specify "should take a virtual row block" do
|
|
866
|
+
@dataset.group{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
867
|
+
@dataset.group_by{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
868
|
+
@dataset.group{[type_id > 1, type_id < 2]}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1), (type_id < 2)"
|
|
869
|
+
@dataset.group(:foo){type_id > 1}.sql.should == "SELECT * FROM test GROUP BY foo, (type_id > 1)"
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
specify "should support a #group_rollup method if the database supports it" do
|
|
873
|
+
@dataset.meta_def(:supports_group_rollup?){true}
|
|
874
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id)"
|
|
875
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id, b)"
|
|
876
|
+
@dataset.meta_def(:uses_with_rollup?){true}
|
|
877
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY type_id WITH ROLLUP"
|
|
878
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY type_id, b WITH ROLLUP"
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
specify "should support a #group_cube method if the database supports it" do
|
|
882
|
+
@dataset.meta_def(:supports_group_cube?){true}
|
|
883
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id)"
|
|
884
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id, b)"
|
|
885
|
+
@dataset.meta_def(:uses_with_rollup?){true}
|
|
886
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY type_id WITH CUBE"
|
|
887
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY type_id, b WITH CUBE"
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
specify "should have #group_cube and #group_rollup methods raise an Error if not supported it" do
|
|
891
|
+
proc{@dataset.group(:type_id).group_rollup}.should raise_error(Sequel::Error)
|
|
892
|
+
proc{@dataset.group(:type_id).group_cube}.should raise_error(Sequel::Error)
|
|
896
893
|
end
|
|
897
894
|
end
|
|
898
895
|
|
|
899
896
|
describe "Dataset#as" do
|
|
900
897
|
specify "should set up an alias" do
|
|
901
898
|
dataset = Sequel::Dataset.new(nil).from(:test)
|
|
902
|
-
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should ==
|
|
903
|
-
'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
|
899
|
+
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
|
904
900
|
end
|
|
905
901
|
end
|
|
906
902
|
|
|
907
903
|
describe "Dataset#literal" do
|
|
908
904
|
before do
|
|
909
|
-
@
|
|
905
|
+
@ds = Sequel::Database.new.dataset
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
specify "should convert qualified symbol notation into dot notation" do
|
|
909
|
+
@ds.literal(:abc__def).should == 'abc.def'
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
specify "should convert AS symbol notation into SQL AS notation" do
|
|
913
|
+
@ds.literal(:xyz___x).should == 'xyz AS x'
|
|
914
|
+
@ds.literal(:abc__def___x).should == 'abc.def AS x'
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
specify "should support names with digits" do
|
|
918
|
+
@ds.literal(:abc2).should == 'abc2'
|
|
919
|
+
@ds.literal(:xx__yy3).should == 'xx.yy3'
|
|
920
|
+
@ds.literal(:ab34__temp3_4ax).should == 'ab34.temp3_4ax'
|
|
921
|
+
@ds.literal(:x1___y2).should == 'x1 AS y2'
|
|
922
|
+
@ds.literal(:abc2__def3___ggg4).should == 'abc2.def3 AS ggg4'
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
specify "should support upper case and lower case" do
|
|
926
|
+
@ds.literal(:ABC).should == 'ABC'
|
|
927
|
+
@ds.literal(:Zvashtoy__aBcD).should == 'Zvashtoy.aBcD'
|
|
928
|
+
end
|
|
929
|
+
|
|
930
|
+
specify "should support spaces inside column names" do
|
|
931
|
+
@ds.quote_identifiers = true
|
|
932
|
+
@ds.literal(:"AB C").should == '"AB C"'
|
|
933
|
+
@ds.literal(:"Zvas htoy__aB cD").should == '"Zvas htoy"."aB cD"'
|
|
934
|
+
@ds.literal(:"aB cD___XX XX").should == '"aB cD" AS "XX XX"'
|
|
935
|
+
@ds.literal(:"Zva shtoy__aB cD___XX XX").should == '"Zva shtoy"."aB cD" AS "XX XX"'
|
|
936
|
+
end
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
describe "Dataset#literal" do
|
|
940
|
+
before do
|
|
941
|
+
@dataset = Sequel::Database.new.from(:test)
|
|
910
942
|
end
|
|
911
943
|
|
|
912
944
|
specify "should escape strings properly" do
|
|
@@ -914,13 +946,13 @@ describe "Dataset#literal" do
|
|
|
914
946
|
@dataset.literal('a"x"bc').should == "'a\"x\"bc'"
|
|
915
947
|
@dataset.literal("a'bc").should == "'a''bc'"
|
|
916
948
|
@dataset.literal("a''bc").should == "'a''''bc'"
|
|
917
|
-
@dataset.literal("a\\bc").should == "'a
|
|
918
|
-
@dataset.literal("a\\\\bc").should == "'a
|
|
919
|
-
@dataset.literal("a\\'bc").should == "'a
|
|
949
|
+
@dataset.literal("a\\bc").should == "'a\\bc'"
|
|
950
|
+
@dataset.literal("a\\\\bc").should == "'a\\\\bc'"
|
|
951
|
+
@dataset.literal("a\\'bc").should == "'a\\''bc'"
|
|
920
952
|
end
|
|
921
953
|
|
|
922
954
|
specify "should escape blobs as strings by default" do
|
|
923
|
-
@dataset.literal('abc'
|
|
955
|
+
@dataset.literal(Sequel.blob('abc')).should == "'abc'"
|
|
924
956
|
end
|
|
925
957
|
|
|
926
958
|
specify "should literalize numbers properly" do
|
|
@@ -944,6 +976,21 @@ describe "Dataset#literal" do
|
|
|
944
976
|
@dataset.literal(:"items__na#m$e").should == "items.na#m$e"
|
|
945
977
|
end
|
|
946
978
|
|
|
979
|
+
specify "should call sql_literal_append with dataset and sql on type if not natively supported and the object responds to it" do
|
|
980
|
+
@a = Class.new do
|
|
981
|
+
def sql_literal_append(ds, sql)
|
|
982
|
+
sql << "called #{ds.blah}"
|
|
983
|
+
end
|
|
984
|
+
def sql_literal(ds)
|
|
985
|
+
"not called #{ds.blah}"
|
|
986
|
+
end
|
|
987
|
+
end
|
|
988
|
+
def @dataset.blah
|
|
989
|
+
"ds"
|
|
990
|
+
end
|
|
991
|
+
@dataset.literal(@a.new).should == "called ds"
|
|
992
|
+
end
|
|
993
|
+
|
|
947
994
|
specify "should call sql_literal with dataset on type if not natively supported and the object responds to it" do
|
|
948
995
|
@a = Class.new do
|
|
949
996
|
def sql_literal(ds)
|
|
@@ -965,6 +1012,12 @@ describe "Dataset#literal" do
|
|
|
965
1012
|
d.literal(d).should == "(#{d.sql})"
|
|
966
1013
|
end
|
|
967
1014
|
|
|
1015
|
+
specify "should literalize Sequel::SQLTime properly" do
|
|
1016
|
+
t = Sequel::SQLTime.now
|
|
1017
|
+
s = t.strftime("'%H:%M:%S")
|
|
1018
|
+
@dataset.literal(t).should == "#{s}.#{sprintf('%06i', t.usec)}'"
|
|
1019
|
+
end
|
|
1020
|
+
|
|
968
1021
|
specify "should literalize Time properly" do
|
|
969
1022
|
t = Time.now
|
|
970
1023
|
s = t.strftime("'%Y-%m-%d %H:%M:%S")
|
|
@@ -1041,10 +1094,9 @@ describe "Dataset#literal" do
|
|
|
1041
1094
|
end
|
|
1042
1095
|
|
|
1043
1096
|
specify "should not modify literal strings" do
|
|
1044
|
-
@dataset.
|
|
1045
|
-
|
|
1046
|
-
@dataset.update_sql(
|
|
1047
|
-
'UPDATE test SET a = a + 2'
|
|
1097
|
+
@dataset.quote_identifiers = true
|
|
1098
|
+
@dataset.literal(Sequel.lit('col1 + 2')).should == 'col1 + 2'
|
|
1099
|
+
@dataset.update_sql(Sequel::SQL::Identifier.new(Sequel.lit('a')) => Sequel.lit('a + 2')).should == 'UPDATE "test" SET a = a + 2'
|
|
1048
1100
|
end
|
|
1049
1101
|
|
|
1050
1102
|
specify "should literalize BigDecimal instances correctly" do
|
|
@@ -1054,6 +1106,17 @@ describe "Dataset#literal" do
|
|
|
1054
1106
|
@dataset.literal(BigDecimal.new("-Infinity")).should == "'-Infinity'"
|
|
1055
1107
|
end
|
|
1056
1108
|
|
|
1109
|
+
specify "should literalize PlaceholderLiteralStrings correctly" do
|
|
1110
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new('? = ?', [1, 2])).should == '1 = 2'
|
|
1111
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new('? = ?', [1, 2], true)).should == '(1 = 2)'
|
|
1112
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(':a = :b', :a=>1, :b=>2)).should == '1 = 2'
|
|
1113
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(':a = :b', {:a=>1, :b=>2}, true)).should == '(1 = 2)'
|
|
1114
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = ', ''], [1, 2])).should == '1 = 2'
|
|
1115
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = ', ''], [1, 2], true)).should == '(1 = 2)'
|
|
1116
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = '], [1, 2])).should == '1 = 2'
|
|
1117
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = '], [1, 2], true)).should == '(1 = 2)'
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1057
1120
|
specify "should raise an Error if the object can't be literalized" do
|
|
1058
1121
|
proc{@dataset.literal(Object.new)}.should raise_error(Sequel::Error)
|
|
1059
1122
|
end
|
|
@@ -1069,35 +1132,36 @@ describe "Dataset#from" do
|
|
|
1069
1132
|
end
|
|
1070
1133
|
|
|
1071
1134
|
specify "should format a Dataset as a subquery if it has had options set" do
|
|
1072
|
-
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should ==
|
|
1073
|
-
"SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
|
|
1135
|
+
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should == "SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
|
|
1074
1136
|
end
|
|
1075
1137
|
|
|
1076
1138
|
specify "should automatically alias sub-queries" do
|
|
1077
|
-
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should ==
|
|
1078
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
|
|
1139
|
+
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
|
|
1079
1140
|
|
|
1080
1141
|
d1 = @dataset.from(:a).group(:b)
|
|
1081
1142
|
d2 = @dataset.from(:c).group(:d)
|
|
1082
|
-
|
|
1083
|
-
@dataset.from(d1, d2).sql.should ==
|
|
1084
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1, (SELECT * FROM c GROUP BY d) AS t2"
|
|
1143
|
+
@dataset.from(d1, d2).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1, (SELECT * FROM c GROUP BY d) AS t2"
|
|
1085
1144
|
end
|
|
1086
1145
|
|
|
1087
1146
|
specify "should accept a hash for aliasing" do
|
|
1088
|
-
@dataset.from(:a => :b).sql.should ==
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
@dataset.from(:a => 'b').sql.should ==
|
|
1092
|
-
"SELECT * FROM a AS b"
|
|
1093
|
-
|
|
1094
|
-
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should ==
|
|
1095
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
|
|
1147
|
+
@dataset.from(:a => :b).sql.should == "SELECT * FROM a AS b"
|
|
1148
|
+
@dataset.from(:a => 'b').sql.should == "SELECT * FROM a AS b"
|
|
1149
|
+
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
|
|
1096
1150
|
end
|
|
1097
1151
|
|
|
1098
1152
|
specify "should always use a subquery if given a dataset" do
|
|
1099
|
-
@dataset.from(@dataset.from(:a)).select_sql.should ==
|
|
1100
|
-
|
|
1153
|
+
@dataset.from(@dataset.from(:a)).select_sql.should == "SELECT * FROM (SELECT * FROM a) AS t1"
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
specify "should treat string arguments as identifiers" do
|
|
1157
|
+
@dataset.quote_identifiers = true
|
|
1158
|
+
@dataset.from('a').select_sql.should == "SELECT * FROM \"a\""
|
|
1159
|
+
end
|
|
1160
|
+
|
|
1161
|
+
specify "should not treat literal strings or blobs as identifiers" do
|
|
1162
|
+
@dataset.quote_identifiers = true
|
|
1163
|
+
@dataset.from(Sequel.lit('a')).select_sql.should == "SELECT * FROM a"
|
|
1164
|
+
@dataset.from(Sequel.blob('a')).select_sql.should == "SELECT * FROM 'a'"
|
|
1101
1165
|
end
|
|
1102
1166
|
|
|
1103
1167
|
specify "should remove all FROM tables if called with no arguments" do
|
|
@@ -1105,32 +1169,31 @@ describe "Dataset#from" do
|
|
|
1105
1169
|
end
|
|
1106
1170
|
|
|
1107
1171
|
specify "should accept sql functions" do
|
|
1108
|
-
@dataset.from(
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
@dataset.from(:a.sql_function(:i)).select_sql.should ==
|
|
1112
|
-
"SELECT * FROM a(i)"
|
|
1172
|
+
@dataset.from(Sequel.function(:abc, :def)).select_sql.should == "SELECT * FROM abc(def)"
|
|
1173
|
+
@dataset.from(Sequel.function(:a, :i)).select_sql.should == "SELECT * FROM a(i)"
|
|
1113
1174
|
end
|
|
1114
1175
|
|
|
1115
1176
|
specify "should accept :schema__table___alias symbol format" do
|
|
1116
|
-
@dataset.from(:abc__def).select_sql.should ==
|
|
1117
|
-
|
|
1118
|
-
@dataset.from(:
|
|
1119
|
-
|
|
1120
|
-
@dataset.from(:
|
|
1121
|
-
|
|
1122
|
-
@dataset.from(:
|
|
1123
|
-
|
|
1124
|
-
@dataset.from(:
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
@dataset.from(:
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
@dataset.
|
|
1133
|
-
|
|
1177
|
+
@dataset.from(:abc__def).select_sql.should == "SELECT * FROM abc.def"
|
|
1178
|
+
@dataset.from(:a_b__c).select_sql.should == "SELECT * FROM a_b.c"
|
|
1179
|
+
@dataset.from(:'#__#').select_sql.should == 'SELECT * FROM #.#'
|
|
1180
|
+
@dataset.from(:abc__def___d).select_sql.should == "SELECT * FROM abc.def AS d"
|
|
1181
|
+
@dataset.from(:a_b__d_e___f_g).select_sql.should == "SELECT * FROM a_b.d_e AS f_g"
|
|
1182
|
+
@dataset.from(:'#__#___#').select_sql.should == 'SELECT * FROM #.# AS #'
|
|
1183
|
+
@dataset.from(:abc___def).select_sql.should == "SELECT * FROM abc AS def"
|
|
1184
|
+
@dataset.from(:a_b___c_d).select_sql.should == "SELECT * FROM a_b AS c_d"
|
|
1185
|
+
@dataset.from(:'#___#').select_sql.should == 'SELECT * FROM # AS #'
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
specify "should not handle :foo__schema__table___alias specially" do
|
|
1189
|
+
@dataset.from(:foo__schema__table___alias).select_sql.should == "SELECT * FROM foo.schema__table AS alias"
|
|
1190
|
+
end
|
|
1191
|
+
|
|
1192
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
1193
|
+
@dataset.meta_def(:supports_cte?){true}
|
|
1194
|
+
@dataset.meta_def(:supports_cte_in_subselect?){false}
|
|
1195
|
+
@dataset.from(@dataset.from(:a).with(:a, @dataset.from(:b))).sql.should == 'WITH a AS (SELECT * FROM b) SELECT * FROM (SELECT * FROM a) AS t1'
|
|
1196
|
+
@dataset.from(@dataset.from(:a).with(:a, @dataset.from(:b)), @dataset.from(:c).with(:c, @dataset.from(:d))).sql.should == 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a) AS t1, (SELECT * FROM c) AS t2'
|
|
1134
1197
|
end
|
|
1135
1198
|
end
|
|
1136
1199
|
|
|
@@ -1145,41 +1208,41 @@ describe "Dataset#select" do
|
|
|
1145
1208
|
end
|
|
1146
1209
|
|
|
1147
1210
|
specify "should accept symbols and literal strings" do
|
|
1148
|
-
@d.select('aaa'
|
|
1149
|
-
@d.select(:a, 'b'
|
|
1150
|
-
@d.select(:test__cc, 'test.d AS e'
|
|
1151
|
-
|
|
1152
|
-
@d.select(
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
@d.select(:test
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
@d.select(:
|
|
1161
|
-
'SELECT test.name AS n FROM test'
|
|
1211
|
+
@d.select(Sequel.lit('aaa')).sql.should == 'SELECT aaa FROM test'
|
|
1212
|
+
@d.select(:a, Sequel.lit('b')).sql.should == 'SELECT a, b FROM test'
|
|
1213
|
+
@d.select(:test__cc, Sequel.lit('test.d AS e')).sql.should == 'SELECT test.cc, test.d AS e FROM test'
|
|
1214
|
+
@d.select(Sequel.lit('test.d AS e'), :test__cc).sql.should == 'SELECT test.d AS e, test.cc FROM test'
|
|
1215
|
+
@d.select(:test__name___n).sql.should == 'SELECT test.name AS n FROM test'
|
|
1216
|
+
end
|
|
1217
|
+
|
|
1218
|
+
specify "should accept ColumnAlls" do
|
|
1219
|
+
@d.select(Sequel::SQL::ColumnAll.new(:test)).sql.should == 'SELECT test.* FROM test'
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
specify "should accept QualifiedIdentifiers" do
|
|
1223
|
+
@d.select(Sequel.expr(:test__name).as(:n)).sql.should == 'SELECT test.name AS n FROM test'
|
|
1162
1224
|
end
|
|
1163
1225
|
|
|
1164
1226
|
specify "should use the wildcard if no arguments are given" do
|
|
1165
1227
|
@d.select.sql.should == 'SELECT * FROM test'
|
|
1166
1228
|
end
|
|
1167
1229
|
|
|
1230
|
+
specify "should handle array condition specifiers that are aliased" do
|
|
1231
|
+
@d.select(Sequel.as([[:b, :c]], :n)).sql.should == 'SELECT (b = c) AS n FROM test'
|
|
1232
|
+
end
|
|
1233
|
+
|
|
1168
1234
|
specify "should accept a hash for AS values" do
|
|
1169
|
-
@d.select(:name => 'n', :__ggh => 'age').sql.should =~
|
|
1170
|
-
/SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
|
1235
|
+
@d.select(:name => 'n', :__ggh => 'age').sql.should =~ /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
|
1171
1236
|
end
|
|
1172
1237
|
|
|
1173
|
-
specify "should
|
|
1238
|
+
specify "should override the previous select option" do
|
|
1174
1239
|
@d.select!(:a, :b, :c).select.sql.should == 'SELECT * FROM test'
|
|
1175
1240
|
@d.select!(:price).select(:name).sql.should == 'SELECT name FROM test'
|
|
1176
1241
|
end
|
|
1177
1242
|
|
|
1178
1243
|
specify "should accept arbitrary objects and literalize them correctly" do
|
|
1179
1244
|
@d.select(1, :a, 't').sql.should == "SELECT 1, a, 't' FROM test"
|
|
1180
|
-
|
|
1181
|
-
@d.select(nil, :sum.sql_function(:t), :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
|
|
1182
|
-
|
|
1245
|
+
@d.select(nil, Sequel.function(:sum, :t), :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
|
|
1183
1246
|
@d.select(nil, 1, :x => :y).sql.should == "SELECT NULL, 1, x AS y FROM test"
|
|
1184
1247
|
end
|
|
1185
1248
|
|
|
@@ -1198,6 +1261,27 @@ describe "Dataset#select" do
|
|
|
1198
1261
|
end
|
|
1199
1262
|
end
|
|
1200
1263
|
|
|
1264
|
+
describe "Dataset#select_group" do
|
|
1265
|
+
before do
|
|
1266
|
+
@d = Sequel::Dataset.new(nil).from(:test)
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
specify "should set both SELECT and GROUP" do
|
|
1270
|
+
@d.select_group(:name).sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1271
|
+
@d.select_group(:a, :b__c, :d___e).sql.should == 'SELECT a, b.c, d AS e FROM test GROUP BY a, b.c, d'
|
|
1272
|
+
end
|
|
1273
|
+
|
|
1274
|
+
specify "should remove from both SELECT and GROUP if no arguments" do
|
|
1275
|
+
@d.select_group(:name).select_group.sql.should == 'SELECT * FROM test'
|
|
1276
|
+
end
|
|
1277
|
+
|
|
1278
|
+
specify "should accept virtual row blocks" do
|
|
1279
|
+
@d.select_group{name}.sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1280
|
+
@d.select_group{[name, f(v).as(a)]}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1281
|
+
@d.select_group(:name){f(v).as(a)}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1282
|
+
end
|
|
1283
|
+
end
|
|
1284
|
+
|
|
1201
1285
|
describe "Dataset#select_all" do
|
|
1202
1286
|
before do
|
|
1203
1287
|
@d = Sequel::Dataset.new(nil).from(:test)
|
|
@@ -1207,9 +1291,43 @@ describe "Dataset#select_all" do
|
|
|
1207
1291
|
@d.select_all.sql.should == 'SELECT * FROM test'
|
|
1208
1292
|
end
|
|
1209
1293
|
|
|
1210
|
-
specify "should
|
|
1294
|
+
specify "should override the previous select option" do
|
|
1211
1295
|
@d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
|
|
1212
1296
|
end
|
|
1297
|
+
|
|
1298
|
+
specify "should select all columns in a table if given an argument" do
|
|
1299
|
+
@d.select_all(:test).sql.should == 'SELECT test.* FROM test'
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
specify "should select all columns all tables if given a multiple arguments" do
|
|
1303
|
+
@d.select_all(:test, :foo).sql.should == 'SELECT test.*, foo.* FROM test'
|
|
1304
|
+
end
|
|
1305
|
+
|
|
1306
|
+
specify "should work correctly with qualified symbols" do
|
|
1307
|
+
@d.select_all(:sch__test).sql.should == 'SELECT sch.test.* FROM test'
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
specify "should work correctly with aliased symbols" do
|
|
1311
|
+
@d.select_all(:test___al).sql.should == 'SELECT al.* FROM test'
|
|
1312
|
+
@d.select_all(:sch__test___al).sql.should == 'SELECT al.* FROM test'
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
specify "should work correctly with SQL::Identifiers" do
|
|
1316
|
+
@d.select_all(Sequel.identifier(:test)).sql.should == 'SELECT test.* FROM test'
|
|
1317
|
+
end
|
|
1318
|
+
|
|
1319
|
+
specify "should work correctly with SQL::QualifiedIdentifier" do
|
|
1320
|
+
@d.select_all(Sequel.qualify(:sch, :test)).sql.should == 'SELECT sch.test.* FROM test'
|
|
1321
|
+
end
|
|
1322
|
+
|
|
1323
|
+
specify "should work correctly with SQL::AliasedExpressions" do
|
|
1324
|
+
@d.select_all(Sequel.expr(:test).as(:al)).sql.should == 'SELECT al.* FROM test'
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1327
|
+
specify "should work correctly with SQL::JoinClauses" do
|
|
1328
|
+
d = @d.cross_join(:foo).cross_join(:test___al)
|
|
1329
|
+
@d.select_all(*d.opts[:join]).sql.should == 'SELECT foo.*, al.* FROM test'
|
|
1330
|
+
end
|
|
1213
1331
|
end
|
|
1214
1332
|
|
|
1215
1333
|
describe "Dataset#select_more" do
|
|
@@ -1225,12 +1343,12 @@ describe "Dataset#select_more" do
|
|
|
1225
1343
|
|
|
1226
1344
|
specify "should add to the currently selected columns" do
|
|
1227
1345
|
@d.select(:a).select_more(:b).sql.should == 'SELECT a, b FROM test'
|
|
1228
|
-
@d.select(:a
|
|
1346
|
+
@d.select(Sequel::SQL::ColumnAll.new(:a)).select_more(Sequel::SQL::ColumnAll.new(:b)).sql.should == 'SELECT a.*, b.* FROM test'
|
|
1229
1347
|
end
|
|
1230
1348
|
|
|
1231
1349
|
specify "should accept a block that yields a virtual row" do
|
|
1232
1350
|
@d.select(:a).select_more{|o| o.b}.sql.should == 'SELECT a, b FROM test'
|
|
1233
|
-
@d.select(:a
|
|
1351
|
+
@d.select(Sequel::SQL::ColumnAll.new(:a)).select_more(Sequel::SQL::ColumnAll.new(:b)){b(1)}.sql.should == 'SELECT a.*, b.*, b(1) FROM test'
|
|
1234
1352
|
end
|
|
1235
1353
|
end
|
|
1236
1354
|
|
|
@@ -1247,12 +1365,20 @@ describe "Dataset#select_append" do
|
|
|
1247
1365
|
|
|
1248
1366
|
specify "should add to the currently selected columns" do
|
|
1249
1367
|
@d.select(:a).select_append(:b).sql.should == 'SELECT a, b FROM test'
|
|
1250
|
-
@d.select(:a
|
|
1368
|
+
@d.select(Sequel::SQL::ColumnAll.new(:a)).select_append(Sequel::SQL::ColumnAll.new(:b)).sql.should == 'SELECT a.*, b.* FROM test'
|
|
1251
1369
|
end
|
|
1252
1370
|
|
|
1253
1371
|
specify "should accept a block that yields a virtual row" do
|
|
1254
1372
|
@d.select(:a).select_append{|o| o.b}.sql.should == 'SELECT a, b FROM test'
|
|
1255
|
-
@d.select(:a
|
|
1373
|
+
@d.select(Sequel::SQL::ColumnAll.new(:a)).select_append(Sequel::SQL::ColumnAll.new(:b)){b(1)}.sql.should == 'SELECT a.*, b.*, b(1) FROM test'
|
|
1374
|
+
end
|
|
1375
|
+
|
|
1376
|
+
specify "should select from all from and join tables if SELECT *, column not supported" do
|
|
1377
|
+
@d.meta_def(:supports_select_all_and_column?){false}
|
|
1378
|
+
@d.select_append(:b).sql.should == 'SELECT test.*, b FROM test'
|
|
1379
|
+
@d.from(:test, :c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test, c'
|
|
1380
|
+
@d.cross_join(:c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test CROSS JOIN c'
|
|
1381
|
+
@d.cross_join(:c).cross_join(:d).select_append(:b).sql.should == 'SELECT test.*, c.*, d.*, b FROM test CROSS JOIN c CROSS JOIN d'
|
|
1256
1382
|
end
|
|
1257
1383
|
end
|
|
1258
1384
|
|
|
@@ -1262,38 +1388,31 @@ describe "Dataset#order" do
|
|
|
1262
1388
|
end
|
|
1263
1389
|
|
|
1264
1390
|
specify "should include an ORDER BY clause in the select statement" do
|
|
1265
|
-
@dataset.order(:name).sql.should ==
|
|
1266
|
-
'SELECT * FROM test ORDER BY name'
|
|
1391
|
+
@dataset.order(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1267
1392
|
end
|
|
1268
1393
|
|
|
1269
1394
|
specify "should accept multiple arguments" do
|
|
1270
|
-
@dataset.order(:name, :price
|
|
1271
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1395
|
+
@dataset.order(:name, Sequel.desc(:price)).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1272
1396
|
end
|
|
1273
1397
|
|
|
1274
1398
|
specify "should accept :nulls options for asc and desc" do
|
|
1275
|
-
@dataset.order(
|
|
1276
|
-
'SELECT * FROM test ORDER BY name ASC NULLS LAST, price DESC NULLS FIRST'
|
|
1399
|
+
@dataset.order(Sequel.asc(:name, :nulls=>:last), Sequel.desc(:price, :nulls=>:first)).sql.should == 'SELECT * FROM test ORDER BY name ASC NULLS LAST, price DESC NULLS FIRST'
|
|
1277
1400
|
end
|
|
1278
1401
|
|
|
1279
|
-
specify "should
|
|
1280
|
-
@dataset.order(:name).order(:stamp).sql.should ==
|
|
1281
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1402
|
+
specify "should override a previous ordering" do
|
|
1403
|
+
@dataset.order(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1282
1404
|
end
|
|
1283
1405
|
|
|
1284
1406
|
specify "should accept a literal string" do
|
|
1285
|
-
@dataset.order('dada ASC'
|
|
1286
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1407
|
+
@dataset.order(Sequel.lit('dada ASC')).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1287
1408
|
end
|
|
1288
1409
|
|
|
1289
1410
|
specify "should accept a hash as an expression" do
|
|
1290
|
-
@dataset.order(:name=>nil).sql.should ==
|
|
1291
|
-
'SELECT * FROM test ORDER BY (name IS NULL)'
|
|
1411
|
+
@dataset.order(:name=>nil).sql.should == 'SELECT * FROM test ORDER BY (name IS NULL)'
|
|
1292
1412
|
end
|
|
1293
1413
|
|
|
1294
1414
|
specify "should accept a nil to remove ordering" do
|
|
1295
|
-
@dataset.order(:bah).order(nil).sql.should ==
|
|
1296
|
-
'SELECT * FROM test'
|
|
1415
|
+
@dataset.order(:bah).order(nil).sql.should == 'SELECT * FROM test'
|
|
1297
1416
|
end
|
|
1298
1417
|
|
|
1299
1418
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1355,6 +1474,13 @@ describe "Dataset#with_sql" do
|
|
|
1355
1474
|
specify "should keep row_proc" do
|
|
1356
1475
|
@dataset.with_sql('SELECT 1 FROM test').row_proc.should == @dataset.row_proc
|
|
1357
1476
|
end
|
|
1477
|
+
|
|
1478
|
+
specify "should work with method symbols and arguments" do
|
|
1479
|
+
@dataset.with_sql(:delete_sql).sql.should == 'DELETE FROM test'
|
|
1480
|
+
@dataset.with_sql(:insert_sql, :b=>1).sql.should == 'INSERT INTO test (b) VALUES (1)'
|
|
1481
|
+
@dataset.with_sql(:update_sql, :b=>1).sql.should == 'UPDATE test SET b = 1'
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1358
1484
|
end
|
|
1359
1485
|
|
|
1360
1486
|
describe "Dataset#order_by" do
|
|
@@ -1363,28 +1489,23 @@ describe "Dataset#order_by" do
|
|
|
1363
1489
|
end
|
|
1364
1490
|
|
|
1365
1491
|
specify "should include an ORDER BY clause in the select statement" do
|
|
1366
|
-
@dataset.order_by(:name).sql.should ==
|
|
1367
|
-
'SELECT * FROM test ORDER BY name'
|
|
1492
|
+
@dataset.order_by(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1368
1493
|
end
|
|
1369
1494
|
|
|
1370
1495
|
specify "should accept multiple arguments" do
|
|
1371
|
-
@dataset.order_by(:name, :price
|
|
1372
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1496
|
+
@dataset.order_by(:name, Sequel.desc(:price)).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1373
1497
|
end
|
|
1374
1498
|
|
|
1375
|
-
specify "should
|
|
1376
|
-
@dataset.order_by(:name).order(:stamp).sql.should ==
|
|
1377
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1499
|
+
specify "should override a previous ordering" do
|
|
1500
|
+
@dataset.order_by(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1378
1501
|
end
|
|
1379
1502
|
|
|
1380
1503
|
specify "should accept a string" do
|
|
1381
|
-
@dataset.order_by('dada ASC'
|
|
1382
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1504
|
+
@dataset.order_by(Sequel.lit('dada ASC')).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1383
1505
|
end
|
|
1384
1506
|
|
|
1385
1507
|
specify "should accept a nil to remove ordering" do
|
|
1386
|
-
@dataset.order_by(:bah).order_by(nil).sql.should ==
|
|
1387
|
-
'SELECT * FROM test'
|
|
1508
|
+
@dataset.order_by(:bah).order_by(nil).sql.should == 'SELECT * FROM test'
|
|
1388
1509
|
end
|
|
1389
1510
|
end
|
|
1390
1511
|
|
|
@@ -1399,8 +1520,8 @@ describe "Dataset#order_more and order_append" do
|
|
|
1399
1520
|
end
|
|
1400
1521
|
|
|
1401
1522
|
specify "should add to the end of a previous ordering" do
|
|
1402
|
-
@dataset.order(:name).order_more(:stamp
|
|
1403
|
-
@dataset.order(:name).order_append(:stamp
|
|
1523
|
+
@dataset.order(:name).order_more(Sequel.desc(:stamp)).sql.should == 'SELECT * FROM test ORDER BY name, stamp DESC'
|
|
1524
|
+
@dataset.order(:name).order_append(Sequel.desc(:stamp)).sql.should == 'SELECT * FROM test ORDER BY name, stamp DESC'
|
|
1404
1525
|
end
|
|
1405
1526
|
|
|
1406
1527
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1417,13 +1538,11 @@ describe "Dataset#order_prepend" do
|
|
|
1417
1538
|
end
|
|
1418
1539
|
|
|
1419
1540
|
specify "should include an ORDER BY clause in the select statement" do
|
|
1420
|
-
@dataset.order_prepend(:name).sql.should ==
|
|
1421
|
-
'SELECT * FROM test ORDER BY name'
|
|
1541
|
+
@dataset.order_prepend(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1422
1542
|
end
|
|
1423
1543
|
|
|
1424
1544
|
specify "should add to the beginning of a previous ordering" do
|
|
1425
|
-
@dataset.order(:name).order_prepend(:stamp
|
|
1426
|
-
'SELECT * FROM test ORDER BY stamp DESC, name'
|
|
1545
|
+
@dataset.order(:name).order_prepend(Sequel.desc(:stamp)).sql.should == 'SELECT * FROM test ORDER BY stamp DESC, name'
|
|
1427
1546
|
end
|
|
1428
1547
|
|
|
1429
1548
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1438,45 +1557,45 @@ describe "Dataset#reverse_order" do
|
|
|
1438
1557
|
end
|
|
1439
1558
|
|
|
1440
1559
|
specify "should use DESC as default order" do
|
|
1441
|
-
@dataset.reverse_order(:name).sql.should ==
|
|
1442
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1560
|
+
@dataset.reverse_order(:name).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1443
1561
|
end
|
|
1444
1562
|
|
|
1445
1563
|
specify "should invert the order given" do
|
|
1446
|
-
@dataset.reverse_order(:name
|
|
1447
|
-
'SELECT * FROM test ORDER BY name ASC'
|
|
1564
|
+
@dataset.reverse_order(Sequel.desc(:name)).sql.should == 'SELECT * FROM test ORDER BY name ASC'
|
|
1448
1565
|
end
|
|
1449
1566
|
|
|
1450
1567
|
specify "should invert the order for ASC expressions" do
|
|
1451
|
-
@dataset.reverse_order(:name
|
|
1452
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1568
|
+
@dataset.reverse_order(Sequel.asc(:name)).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1453
1569
|
end
|
|
1454
1570
|
|
|
1455
1571
|
specify "should accept multiple arguments" do
|
|
1456
|
-
@dataset.reverse_order(:name, :price
|
|
1457
|
-
'SELECT * FROM test ORDER BY name DESC, price ASC'
|
|
1572
|
+
@dataset.reverse_order(:name, Sequel.desc(:price)).sql.should == 'SELECT * FROM test ORDER BY name DESC, price ASC'
|
|
1458
1573
|
end
|
|
1459
1574
|
|
|
1460
1575
|
specify "should handles NULLS ordering correctly when reversing" do
|
|
1461
|
-
@dataset.reverse_order(
|
|
1462
|
-
'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
|
|
1576
|
+
@dataset.reverse_order(Sequel.asc(:name, :nulls=>:first), Sequel.desc(:price, :nulls=>:last)).sql.should == 'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
|
|
1463
1577
|
end
|
|
1464
1578
|
|
|
1465
1579
|
specify "should reverse a previous ordering if no arguments are given" do
|
|
1466
|
-
@dataset.order(:name).reverse_order.sql.should ==
|
|
1467
|
-
|
|
1468
|
-
@dataset.order(:clumsy.desc, :fool).reverse_order.sql.should ==
|
|
1469
|
-
'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
|
|
1580
|
+
@dataset.order(:name).reverse_order.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1581
|
+
@dataset.order(Sequel.desc(:clumsy), :fool).reverse_order.sql.should == 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
|
|
1470
1582
|
end
|
|
1471
1583
|
|
|
1472
1584
|
specify "should return an unordered dataset for a dataset with no order" do
|
|
1473
|
-
@dataset.unordered.reverse_order.sql.should ==
|
|
1474
|
-
'SELECT * FROM test'
|
|
1585
|
+
@dataset.unordered.reverse_order.sql.should == 'SELECT * FROM test'
|
|
1475
1586
|
end
|
|
1476
1587
|
|
|
1477
1588
|
specify "should have #reverse alias" do
|
|
1478
|
-
@dataset.order(:name).reverse.sql.should ==
|
|
1479
|
-
|
|
1589
|
+
@dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1592
|
+
specify "should accept a block" do
|
|
1593
|
+
@dataset.reverse{name}.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1594
|
+
@dataset.reverse_order{name}.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1595
|
+
@dataset.reverse(:foo){name}.sql.should == 'SELECT * FROM test ORDER BY foo DESC, name DESC'
|
|
1596
|
+
@dataset.reverse_order(:foo){name}.sql.should == 'SELECT * FROM test ORDER BY foo DESC, name DESC'
|
|
1597
|
+
@dataset.reverse(Sequel.desc(:foo)){name}.sql.should == 'SELECT * FROM test ORDER BY foo ASC, name DESC'
|
|
1598
|
+
@dataset.reverse_order(Sequel.desc(:foo)){name}.sql.should == 'SELECT * FROM test ORDER BY foo ASC, name DESC'
|
|
1480
1599
|
end
|
|
1481
1600
|
end
|
|
1482
1601
|
|
|
@@ -1486,42 +1605,39 @@ describe "Dataset#limit" do
|
|
|
1486
1605
|
end
|
|
1487
1606
|
|
|
1488
1607
|
specify "should include a LIMIT clause in the select statement" do
|
|
1489
|
-
@dataset.limit(10).sql.should ==
|
|
1490
|
-
'SELECT * FROM test LIMIT 10'
|
|
1608
|
+
@dataset.limit(10).sql.should == 'SELECT * FROM test LIMIT 10'
|
|
1491
1609
|
end
|
|
1492
1610
|
|
|
1493
1611
|
specify "should accept ranges" do
|
|
1494
|
-
@dataset.limit(3..7).sql.should ==
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
@dataset.limit(3...7).sql.should ==
|
|
1498
|
-
'SELECT * FROM test LIMIT 4 OFFSET 3'
|
|
1612
|
+
@dataset.limit(3..7).sql.should == 'SELECT * FROM test LIMIT 5 OFFSET 3'
|
|
1613
|
+
@dataset.limit(3...7).sql.should == 'SELECT * FROM test LIMIT 4 OFFSET 3'
|
|
1499
1614
|
end
|
|
1500
1615
|
|
|
1501
1616
|
specify "should include an offset if a second argument is given" do
|
|
1502
|
-
@dataset.limit(6, 10).sql.should ==
|
|
1503
|
-
|
|
1504
|
-
end
|
|
1617
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 10'
|
|
1618
|
+
end
|
|
1505
1619
|
|
|
1506
1620
|
specify "should convert regular strings to integers" do
|
|
1507
|
-
@dataset.limit('6', 'a() - 1').sql.should ==
|
|
1508
|
-
'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1621
|
+
@dataset.limit('6', 'a() - 1').sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1509
1622
|
end
|
|
1510
1623
|
|
|
1511
1624
|
specify "should not convert literal strings to integers" do
|
|
1512
|
-
@dataset.limit('6'.lit
|
|
1513
|
-
'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1625
|
+
@dataset.limit(Sequel.lit('6'), Sequel.lit('a() - 1')).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1514
1626
|
end
|
|
1515
1627
|
|
|
1516
1628
|
specify "should not convert other objects" do
|
|
1517
|
-
@dataset.limit(6, :a
|
|
1518
|
-
|
|
1629
|
+
@dataset.limit(6, Sequel.function(:a) - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
specify "should be able to reset limit and offset with nil values" do
|
|
1633
|
+
@dataset.limit(6).limit(nil).sql.should == 'SELECT * FROM test'
|
|
1634
|
+
@dataset.limit(6, 1).limit(nil).sql.should == 'SELECT * FROM test OFFSET 1'
|
|
1635
|
+
@dataset.limit(6, 1).limit(nil, nil).sql.should == 'SELECT * FROM test'
|
|
1519
1636
|
end
|
|
1520
1637
|
|
|
1521
1638
|
specify "should work with fixed sql datasets" do
|
|
1522
1639
|
@dataset.opts[:sql] = 'select * from cccc'
|
|
1523
|
-
@dataset.limit(6, 10).sql.should ==
|
|
1524
|
-
'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
|
1640
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
|
1525
1641
|
end
|
|
1526
1642
|
|
|
1527
1643
|
specify "should raise an error if an invalid limit or offset is used" do
|
|
@@ -1535,15 +1651,20 @@ describe "Dataset#limit" do
|
|
|
1535
1651
|
end
|
|
1536
1652
|
|
|
1537
1653
|
describe "Dataset#naked" do
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1654
|
+
specify "should returned clone dataset without row_proc" do
|
|
1655
|
+
d = Sequel::Dataset.new(nil)
|
|
1656
|
+
d.row_proc = Proc.new{|r| r}
|
|
1657
|
+
d.naked.row_proc.should be_nil
|
|
1658
|
+
d.row_proc.should_not be_nil
|
|
1542
1659
|
end
|
|
1543
|
-
|
|
1660
|
+
end
|
|
1661
|
+
|
|
1662
|
+
describe "Dataset#naked!" do
|
|
1544
1663
|
specify "should remove any existing row_proc" do
|
|
1545
|
-
|
|
1546
|
-
|
|
1664
|
+
d = Sequel::Dataset.new(nil)
|
|
1665
|
+
d.row_proc = Proc.new{|r| r}
|
|
1666
|
+
d.naked!.row_proc.should be_nil
|
|
1667
|
+
d.row_proc.should be_nil
|
|
1547
1668
|
end
|
|
1548
1669
|
end
|
|
1549
1670
|
|
|
@@ -1555,7 +1676,7 @@ describe "Dataset#qualified_column_name" do
|
|
|
1555
1676
|
specify "should return the literal value if not given a symbol" do
|
|
1556
1677
|
@dataset.literal(@dataset.send(:qualified_column_name, 'ccc__b', :items)).should == "'ccc__b'"
|
|
1557
1678
|
@dataset.literal(@dataset.send(:qualified_column_name, 3, :items)).should == '3'
|
|
1558
|
-
@dataset.literal(@dataset.send(:qualified_column_name, 'a'
|
|
1679
|
+
@dataset.literal(@dataset.send(:qualified_column_name, Sequel.lit('a'), :items)).should == 'a'
|
|
1559
1680
|
end
|
|
1560
1681
|
|
|
1561
1682
|
specify "should qualify the column with the supplied table name if given an unqualified symbol" do
|
|
@@ -1567,42 +1688,46 @@ describe "Dataset#qualified_column_name" do
|
|
|
1567
1688
|
end
|
|
1568
1689
|
|
|
1569
1690
|
specify "should handle an aliased identifier" do
|
|
1570
|
-
@dataset.literal(@dataset.send(:qualified_column_name, :ccc, :items.as(:i))).should == 'i.ccc'
|
|
1571
|
-
end
|
|
1572
|
-
end
|
|
1573
|
-
|
|
1574
|
-
class DummyDataset < Sequel::Dataset
|
|
1575
|
-
VALUES = [
|
|
1576
|
-
{:a => 1, :b => 2},
|
|
1577
|
-
{:a => 3, :b => 4},
|
|
1578
|
-
{:a => 5, :b => 6}
|
|
1579
|
-
]
|
|
1580
|
-
def fetch_rows(sql, &block)
|
|
1581
|
-
VALUES.each(&block)
|
|
1691
|
+
@dataset.literal(@dataset.send(:qualified_column_name, :ccc, Sequel.expr(:items).as(:i))).should == 'i.ccc'
|
|
1582
1692
|
end
|
|
1583
1693
|
end
|
|
1584
1694
|
|
|
1585
1695
|
describe "Dataset#map" do
|
|
1586
1696
|
before do
|
|
1587
|
-
@d =
|
|
1697
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1588
1698
|
end
|
|
1589
1699
|
|
|
1590
1700
|
specify "should provide the usual functionality if no argument is given" do
|
|
1591
|
-
@d.map
|
|
1701
|
+
@d.map{|n| n[:a] + n[:b]}.should == [3, 7, 11]
|
|
1592
1702
|
end
|
|
1593
1703
|
|
|
1594
1704
|
specify "should map using #[column name] if column name is given" do
|
|
1595
1705
|
@d.map(:a).should == [1, 3, 5]
|
|
1596
1706
|
end
|
|
1597
1707
|
|
|
1708
|
+
specify "should support multiple column names if an array of column names is given" do
|
|
1709
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1710
|
+
end
|
|
1711
|
+
|
|
1712
|
+
specify "should not call the row_proc if an argument is given" do
|
|
1713
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1714
|
+
@d.map(:a).should == [1, 3, 5]
|
|
1715
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1716
|
+
end
|
|
1717
|
+
|
|
1718
|
+
specify "should call the row_proc if no argument is given" do
|
|
1719
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1720
|
+
@d.map{|n| n[:a] + n[:b]}.should == [6, 14, 22]
|
|
1721
|
+
end
|
|
1722
|
+
|
|
1598
1723
|
specify "should return the complete dataset values if nothing is given" do
|
|
1599
|
-
@d.map.to_a.should ==
|
|
1724
|
+
@d.map.to_a.should == [{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}]
|
|
1600
1725
|
end
|
|
1601
1726
|
end
|
|
1602
1727
|
|
|
1603
1728
|
describe "Dataset#to_hash" do
|
|
1604
1729
|
before do
|
|
1605
|
-
@d =
|
|
1730
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1606
1731
|
end
|
|
1607
1732
|
|
|
1608
1733
|
specify "should provide a hash with the first column as key and the second as value" do
|
|
@@ -1614,11 +1739,73 @@ describe "Dataset#to_hash" do
|
|
|
1614
1739
|
@d.to_hash(:a).should == {1 => {:a => 1, :b => 2}, 3 => {:a => 3, :b => 4}, 5 => {:a => 5, :b => 6}}
|
|
1615
1740
|
@d.to_hash(:b).should == {2 => {:a => 1, :b => 2}, 4 => {:a => 3, :b => 4}, 6 => {:a => 5, :b => 6}}
|
|
1616
1741
|
end
|
|
1742
|
+
|
|
1743
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1744
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1745
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1746
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1747
|
+
@d.to_hash([:a, :b]).should == {[1, 2] => {:a => 1, :b => 2}, [3, 4] => {:a => 3, :b => 4}, [5, 6] => {:a => 5, :b => 6}}
|
|
1748
|
+
end
|
|
1749
|
+
|
|
1750
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1751
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1752
|
+
@d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
|
|
1753
|
+
@d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
|
|
1754
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1755
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1756
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1757
|
+
end
|
|
1758
|
+
|
|
1759
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1760
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1761
|
+
@d.to_hash(:a).should == {2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12}}
|
|
1762
|
+
@d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
|
|
1763
|
+
@d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
|
|
1764
|
+
end
|
|
1765
|
+
end
|
|
1766
|
+
|
|
1767
|
+
describe "Dataset#to_hash_groups" do
|
|
1768
|
+
before do
|
|
1769
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 1, :b => 6}, {:a => 7, :b => 4}])[:items]
|
|
1770
|
+
end
|
|
1771
|
+
|
|
1772
|
+
specify "should provide a hash with the first column as key and the second as value" do
|
|
1773
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1774
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1775
|
+
end
|
|
1776
|
+
|
|
1777
|
+
specify "should provide a hash with the first column as key and the entire hash as value if the value column is blank or nil" do
|
|
1778
|
+
@d.to_hash_groups(:a).should == {1 => [{:a => 1, :b => 2}, {:a => 1, :b => 6}], 3 => [{:a => 3, :b => 4}], 7 => [{:a => 7, :b => 4}]}
|
|
1779
|
+
@d.to_hash_groups(:b).should == {2 => [{:a => 1, :b => 2}], 4 => [{:a => 3, :b => 4}, {:a => 7, :b => 4}], 6 => [{:a => 1, :b => 6}]}
|
|
1780
|
+
end
|
|
1781
|
+
|
|
1782
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1783
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1784
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1785
|
+
@d.to_hash_groups([:b, :a], [:a, :b]).should == {[2, 1] => [[1, 2]], [4, 3] => [[3, 4]], [6, 1] => [[1, 6]], [4, 7]=>[[7, 4]]}
|
|
1786
|
+
@d.to_hash_groups([:a, :b]).should == {[1, 2] => [{:a => 1, :b => 2}], [3, 4] => [{:a => 3, :b => 4}], [1, 6] => [{:a => 1, :b => 6}], [7, 4] => [{:a => 7, :b => 4}]}
|
|
1787
|
+
end
|
|
1788
|
+
|
|
1789
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1790
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1791
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1792
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1793
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1794
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1795
|
+
@d.to_hash_groups([:b, :a], [:a, :b]).should == {[2, 1] => [[1, 2]], [4, 3] => [[3, 4]], [6, 1] => [[1, 6]], [4, 7]=>[[7, 4]]}
|
|
1796
|
+
end
|
|
1797
|
+
|
|
1798
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1799
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1800
|
+
@d.to_hash_groups(:a).should == {2 => [{:a => 2, :b => 4}, {:a => 2, :b => 12}], 6 => [{:a => 6, :b => 8}], 14 => [{:a => 14, :b => 8}]}
|
|
1801
|
+
@d.to_hash_groups(:b).should == {4 => [{:a => 2, :b => 4}], 8 => [{:a => 6, :b => 8}, {:a => 14, :b => 8}], 12 => [{:a => 2, :b => 12}]}
|
|
1802
|
+
@d.to_hash_groups([:a, :b]).should == {[2, 4] => [{:a => 2, :b => 4}], [6, 8] => [{:a => 6, :b => 8}], [2, 12] => [{:a => 2, :b => 12}], [14, 8] => [{:a => 14, :b => 8}]}
|
|
1803
|
+
end
|
|
1617
1804
|
end
|
|
1618
1805
|
|
|
1619
1806
|
describe "Dataset#distinct" do
|
|
1620
1807
|
before do
|
|
1621
|
-
@db =
|
|
1808
|
+
@db = Sequel.mock
|
|
1622
1809
|
@dataset = @db[:test].select(:name)
|
|
1623
1810
|
end
|
|
1624
1811
|
|
|
@@ -1634,7 +1821,7 @@ describe "Dataset#distinct" do
|
|
|
1634
1821
|
specify "should use DISTINCT ON if columns are given and DISTINCT ON is supported" do
|
|
1635
1822
|
@dataset.meta_def(:supports_distinct_on?){true}
|
|
1636
1823
|
@dataset.distinct(:a, :b).sql.should == 'SELECT DISTINCT ON (a, b) name FROM test'
|
|
1637
|
-
@dataset.distinct(
|
|
1824
|
+
@dataset.distinct(Sequel.cast(:stamp, :integer), :node_id=>nil).sql.should == 'SELECT DISTINCT ON (CAST(stamp AS integer), (node_id IS NULL)) name FROM test'
|
|
1638
1825
|
end
|
|
1639
1826
|
|
|
1640
1827
|
specify "should do a subselect for count" do
|
|
@@ -1645,132 +1832,119 @@ end
|
|
|
1645
1832
|
|
|
1646
1833
|
describe "Dataset#count" do
|
|
1647
1834
|
before do
|
|
1648
|
-
@
|
|
1649
|
-
|
|
1650
|
-
@@sql
|
|
1651
|
-
end
|
|
1652
|
-
|
|
1653
|
-
def fetch_rows(sql)
|
|
1654
|
-
@columns = [sql =~ /SELECT COUNT/i ? :count : :a]
|
|
1655
|
-
@@sql = sql
|
|
1656
|
-
yield({@columns.first=>1})
|
|
1657
|
-
end
|
|
1658
|
-
end
|
|
1659
|
-
@dataset = @c.new(nil).from(:test)
|
|
1835
|
+
@db = Sequel.mock(:fetch=>{:count=>1})
|
|
1836
|
+
@dataset = @db.from(:test).columns(:count)
|
|
1660
1837
|
end
|
|
1661
1838
|
|
|
1662
1839
|
specify "should format SQL properly" do
|
|
1663
1840
|
@dataset.count.should == 1
|
|
1664
|
-
@
|
|
1841
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
|
|
1842
|
+
end
|
|
1843
|
+
|
|
1844
|
+
specify "should accept an argument" do
|
|
1845
|
+
@dataset.count(:foo).should == 1
|
|
1846
|
+
@db.sqls.should == ['SELECT COUNT(foo) AS count FROM test LIMIT 1']
|
|
1847
|
+
end
|
|
1848
|
+
|
|
1849
|
+
specify "should work with a nil argument" do
|
|
1850
|
+
@dataset.count(nil).should == 1
|
|
1851
|
+
@db.sqls.should == ['SELECT COUNT(NULL) AS count FROM test LIMIT 1']
|
|
1852
|
+
end
|
|
1853
|
+
|
|
1854
|
+
specify "should accept a virtual row block" do
|
|
1855
|
+
@dataset.count{foo(bar)}.should == 1
|
|
1856
|
+
@db.sqls.should == ['SELECT COUNT(foo(bar)) AS count FROM test LIMIT 1']
|
|
1857
|
+
end
|
|
1858
|
+
|
|
1859
|
+
specify "should raise an Error if given an argument and a block" do
|
|
1860
|
+
proc{@dataset.count(:foo){foo(bar)}}.should raise_error(Sequel::Error)
|
|
1665
1861
|
end
|
|
1666
1862
|
|
|
1667
1863
|
specify "should include the where clause if it's there" do
|
|
1668
|
-
@dataset.filter(:abc
|
|
1669
|
-
@
|
|
1864
|
+
@dataset.filter(Sequel.expr(:abc) < 30).count.should == 1
|
|
1865
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
|
|
1670
1866
|
end
|
|
1671
1867
|
|
|
1672
1868
|
specify "should count properly for datasets with fixed sql" do
|
|
1673
1869
|
@dataset.opts[:sql] = "select abc from xyz"
|
|
1674
1870
|
@dataset.count.should == 1
|
|
1675
|
-
@
|
|
1871
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
|
|
1676
1872
|
end
|
|
1677
1873
|
|
|
1678
1874
|
specify "should count properly when using UNION, INTERSECT, or EXCEPT" do
|
|
1679
1875
|
@dataset.union(@dataset).count.should == 1
|
|
1680
|
-
@
|
|
1876
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1681
1877
|
@dataset.intersect(@dataset).count.should == 1
|
|
1682
|
-
@
|
|
1878
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1683
1879
|
@dataset.except(@dataset).count.should == 1
|
|
1684
|
-
@
|
|
1880
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1685
1881
|
end
|
|
1686
1882
|
|
|
1687
1883
|
specify "should return limit if count is greater than it" do
|
|
1688
1884
|
@dataset.limit(5).count.should == 1
|
|
1689
|
-
@
|
|
1885
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"]
|
|
1690
1886
|
end
|
|
1691
1887
|
|
|
1692
1888
|
it "should work on a graphed_dataset" do
|
|
1693
1889
|
@dataset.should_receive(:columns).twice.and_return([:a])
|
|
1694
1890
|
@dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
|
|
1695
|
-
@
|
|
1891
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
1696
1892
|
end
|
|
1697
1893
|
|
|
1698
1894
|
specify "should not cache the columns value" do
|
|
1699
|
-
ds = @dataset.from(:blah)
|
|
1895
|
+
ds = @dataset.from(:blah).columns(:a)
|
|
1700
1896
|
ds.columns.should == [:a]
|
|
1701
1897
|
ds.count.should == 1
|
|
1702
|
-
@
|
|
1898
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM blah LIMIT 1']
|
|
1703
1899
|
ds.columns.should == [:a]
|
|
1704
1900
|
end
|
|
1705
1901
|
end
|
|
1706
1902
|
|
|
1707
|
-
|
|
1708
1903
|
describe "Dataset#group_and_count" do
|
|
1709
1904
|
before do
|
|
1710
|
-
@
|
|
1711
|
-
def self.sql
|
|
1712
|
-
@@sql
|
|
1713
|
-
end
|
|
1714
|
-
|
|
1715
|
-
def fetch_rows(sql)
|
|
1716
|
-
@@sql = sql
|
|
1717
|
-
yield({1 => 1})
|
|
1718
|
-
end
|
|
1719
|
-
end
|
|
1720
|
-
@ds = @c.new(nil).from(:test)
|
|
1905
|
+
@ds = Sequel::Dataset.new(nil).from(:test)
|
|
1721
1906
|
end
|
|
1722
1907
|
|
|
1723
1908
|
specify "should format SQL properly" do
|
|
1724
|
-
@ds.group_and_count(:name).sql.should ==
|
|
1725
|
-
"SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1909
|
+
@ds.group_and_count(:name).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1726
1910
|
end
|
|
1727
1911
|
|
|
1728
1912
|
specify "should accept multiple columns for grouping" do
|
|
1729
|
-
@ds.group_and_count(:a, :b).sql.should ==
|
|
1730
|
-
"SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
|
|
1913
|
+
@ds.group_and_count(:a, :b).sql.should == "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
|
|
1731
1914
|
end
|
|
1732
1915
|
|
|
1733
1916
|
specify "should format column aliases in the select clause but not in the group clause" do
|
|
1734
|
-
@ds.group_and_count(:name___n).sql.should ==
|
|
1735
|
-
|
|
1736
|
-
@ds.group_and_count(:name__n).sql.should ==
|
|
1737
|
-
"SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
|
1917
|
+
@ds.group_and_count(:name___n).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1918
|
+
@ds.group_and_count(:name__n).sql.should == "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
|
1738
1919
|
end
|
|
1739
1920
|
|
|
1740
1921
|
specify "should handle identifiers" do
|
|
1741
|
-
@ds.group_and_count(:name___n
|
|
1742
|
-
"SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1922
|
+
@ds.group_and_count(Sequel.identifier(:name___n)).sql.should == "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1743
1923
|
end
|
|
1744
1924
|
|
|
1745
1925
|
specify "should handle literal strings" do
|
|
1746
|
-
@ds.group_and_count("name"
|
|
1747
|
-
"SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1926
|
+
@ds.group_and_count(Sequel.lit("name")).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1748
1927
|
end
|
|
1749
1928
|
|
|
1750
1929
|
specify "should handle aliased expressions" do
|
|
1751
|
-
@ds.group_and_count(:name.as(:n)).sql.should ==
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1930
|
+
@ds.group_and_count(Sequel.expr(:name).as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1931
|
+
@ds.group_and_count(Sequel.identifier(:name).as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
specify "should take a virtual row block" do
|
|
1935
|
+
@ds.group_and_count{(type_id > 1).as(t)}.sql.should == "SELECT (type_id > 1) AS t, count(*) AS count FROM test GROUP BY (type_id > 1)"
|
|
1936
|
+
@ds.group_and_count{[(type_id > 1).as(t), type_id < 2]}.sql.should == "SELECT (type_id > 1) AS t, (type_id < 2), count(*) AS count FROM test GROUP BY (type_id > 1), (type_id < 2)"
|
|
1937
|
+
@ds.group_and_count(:foo){type_id > 1}.sql.should == "SELECT foo, (type_id > 1), count(*) AS count FROM test GROUP BY foo, (type_id > 1)"
|
|
1755
1938
|
end
|
|
1756
1939
|
end
|
|
1757
1940
|
|
|
1758
1941
|
describe "Dataset#empty?" do
|
|
1759
1942
|
specify "should return true if records exist in the dataset" do
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
def fetch_rows(sql)
|
|
1766
|
-
@@sql = sql
|
|
1767
|
-
yield({1 => 1}) unless sql =~ /WHERE 'f'/
|
|
1768
|
-
end
|
|
1769
|
-
end
|
|
1770
|
-
@c.new(nil).from(:test).should_not be_empty
|
|
1771
|
-
@c.sql.should == 'SELECT 1 FROM test LIMIT 1'
|
|
1772
|
-
@c.new(nil).from(:test).filter(false).should be_empty
|
|
1773
|
-
@c.sql.should == "SELECT 1 FROM test WHERE 'f' LIMIT 1"
|
|
1943
|
+
db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
|
|
1944
|
+
db.from(:test).should_not be_empty
|
|
1945
|
+
db.sqls.should == ['SELECT 1 AS one FROM test LIMIT 1']
|
|
1946
|
+
db.from(:test).filter(false).should be_empty
|
|
1947
|
+
db.sqls.should == ["SELECT 1 AS one FROM test WHERE 'f' LIMIT 1"]
|
|
1774
1948
|
end
|
|
1775
1949
|
end
|
|
1776
1950
|
|
|
@@ -1781,22 +1955,22 @@ describe "Dataset#first_source_alias" do
|
|
|
1781
1955
|
|
|
1782
1956
|
specify "should be the entire first source if not aliased" do
|
|
1783
1957
|
@ds.from(:t).first_source_alias.should == :t
|
|
1784
|
-
@ds.from(:t__a
|
|
1958
|
+
@ds.from(Sequel.identifier(:t__a)).first_source_alias.should == Sequel.identifier(:t__a)
|
|
1785
1959
|
@ds.from(:s__t).first_source_alias.should == :s__t
|
|
1786
|
-
@ds.from(
|
|
1960
|
+
@ds.from(Sequel.qualify(:s, :t)).first_source_alias.should == Sequel.qualify(:s, :t)
|
|
1787
1961
|
end
|
|
1788
1962
|
|
|
1789
1963
|
specify "should be the alias if aliased" do
|
|
1790
1964
|
@ds.from(:t___a).first_source_alias.should == :a
|
|
1791
1965
|
@ds.from(:s__t___a).first_source_alias.should == :a
|
|
1792
|
-
@ds.from(:t.as(:a)).first_source_alias.should == :a
|
|
1966
|
+
@ds.from(Sequel.expr(:t).as(:a)).first_source_alias.should == :a
|
|
1793
1967
|
end
|
|
1794
1968
|
|
|
1795
1969
|
specify "should be aliased as first_source" do
|
|
1796
1970
|
@ds.from(:t).first_source.should == :t
|
|
1797
|
-
@ds.from(:t__a
|
|
1971
|
+
@ds.from(Sequel.identifier(:t__a)).first_source.should == Sequel.identifier(:t__a)
|
|
1798
1972
|
@ds.from(:s__t___a).first_source.should == :a
|
|
1799
|
-
@ds.from(:t.as(:a)).first_source.should == :a
|
|
1973
|
+
@ds.from(Sequel.expr(:t).as(:a)).first_source.should == :a
|
|
1800
1974
|
end
|
|
1801
1975
|
|
|
1802
1976
|
specify "should raise exception if table doesn't have a source" do
|
|
@@ -1811,15 +1985,15 @@ describe "Dataset#first_source_table" do
|
|
|
1811
1985
|
|
|
1812
1986
|
specify "should be the entire first source if not aliased" do
|
|
1813
1987
|
@ds.from(:t).first_source_table.should == :t
|
|
1814
|
-
@ds.from(:t__a
|
|
1988
|
+
@ds.from(Sequel.identifier(:t__a)).first_source_table.should == Sequel.identifier(:t__a)
|
|
1815
1989
|
@ds.from(:s__t).first_source_table.should == :s__t
|
|
1816
|
-
@ds.from(
|
|
1990
|
+
@ds.from(Sequel.qualify(:s, :t)).first_source_table.should == Sequel.qualify(:s, :t)
|
|
1817
1991
|
end
|
|
1818
1992
|
|
|
1819
1993
|
specify "should be the unaliased part if aliased" do
|
|
1820
|
-
@ds.from(:t___a).first_source_table.should ==
|
|
1821
|
-
@ds.from(:s__t___a).first_source_table.should ==
|
|
1822
|
-
@ds.from(:t.as(:a)).first_source_table.should ==
|
|
1994
|
+
@ds.literal(@ds.from(:t___a).first_source_table).should == "t"
|
|
1995
|
+
@ds.literal(@ds.from(:s__t___a).first_source_table).should == "s.t"
|
|
1996
|
+
@ds.literal(@ds.from(Sequel.expr(:t).as(:a)).first_source_table).should == "t"
|
|
1823
1997
|
end
|
|
1824
1998
|
|
|
1825
1999
|
specify "should raise exception if table doesn't have a source" do
|
|
@@ -1849,73 +2023,64 @@ describe "Dataset#from_self" do
|
|
|
1849
2023
|
'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
|
|
1850
2024
|
end
|
|
1851
2025
|
|
|
1852
|
-
specify "should not options such as server" do
|
|
2026
|
+
specify "should not remove non-SQL options such as :server" do
|
|
1853
2027
|
@ds.server(:blah).from_self(:alias=>:some_name).opts[:server].should == :blah
|
|
1854
2028
|
end
|
|
1855
2029
|
|
|
2030
|
+
specify "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
|
|
2031
|
+
ds = Sequel::Dataset.new(nil)
|
|
2032
|
+
ds.meta_def(:supports_cte?){true}
|
|
2033
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2034
|
+
ds.from(:a).with(:a, ds.from(:b)).from_self.sql.should == 'WITH a AS (SELECT * FROM b) SELECT * FROM (SELECT * FROM a) AS t1'
|
|
2035
|
+
ds.from(:a, :c).with(:a, ds.from(:b)).with(:c, ds.from(:d)).from_self.sql.should == 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a, c) AS t1'
|
|
2036
|
+
end
|
|
1856
2037
|
end
|
|
1857
2038
|
|
|
1858
2039
|
describe "Dataset#join_table" do
|
|
1859
2040
|
before do
|
|
1860
|
-
@d =
|
|
2041
|
+
@d = Sequel::Dataset.new(nil).from(:items)
|
|
1861
2042
|
@d.quote_identifiers = true
|
|
1862
2043
|
end
|
|
1863
2044
|
|
|
1864
2045
|
specify "should format the JOIN clause properly" do
|
|
1865
|
-
@d.join_table(:left_outer, :categories, :category_id => :id).sql.should ==
|
|
1866
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2046
|
+
@d.join_table(:left_outer, :categories, :category_id => :id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1867
2047
|
end
|
|
1868
2048
|
|
|
1869
2049
|
specify "should handle multiple conditions on the same join table column" do
|
|
1870
|
-
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
|
2050
|
+
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
|
1871
2051
|
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND ("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100))'
|
|
1872
2052
|
end
|
|
1873
2053
|
|
|
1874
2054
|
specify "should include WHERE clause if applicable" do
|
|
1875
|
-
@d.filter(:price
|
|
2055
|
+
@d.filter(Sequel.expr(:price) < 100).join_table(:right_outer, :categories, :category_id => :id).sql.should ==
|
|
1876
2056
|
'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") WHERE ("price" < 100)'
|
|
1877
2057
|
end
|
|
1878
2058
|
|
|
1879
2059
|
specify "should include ORDER BY clause if applicable" do
|
|
1880
|
-
@d.order(:stamp).join_table(:full_outer, :categories, :category_id => :id).sql.should ==
|
|
1881
|
-
'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") ORDER BY "stamp"'
|
|
2060
|
+
@d.order(:stamp).join_table(:full_outer, :categories, :category_id => :id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") ORDER BY "stamp"'
|
|
1882
2061
|
end
|
|
1883
2062
|
|
|
1884
2063
|
specify "should support multiple joins" do
|
|
1885
|
-
@d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.should ==
|
|
1886
|
-
'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
|
|
2064
|
+
@d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.should == 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
|
|
1887
2065
|
end
|
|
1888
2066
|
|
|
1889
2067
|
specify "should support arbitrary join types" do
|
|
1890
|
-
@d.join_table(:magic, :categories, :category_id=>:id).sql.should ==
|
|
1891
|
-
'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2068
|
+
@d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1892
2069
|
end
|
|
1893
2070
|
|
|
1894
2071
|
specify "should support many join methods" do
|
|
1895
|
-
@d.left_outer_join(:categories, :category_id=>:id).sql.should ==
|
|
1896
|
-
|
|
1897
|
-
@d.
|
|
1898
|
-
|
|
1899
|
-
@d.
|
|
1900
|
-
|
|
1901
|
-
@d.
|
|
1902
|
-
|
|
1903
|
-
@d.
|
|
1904
|
-
|
|
1905
|
-
@d.
|
|
1906
|
-
|
|
1907
|
-
@d.full_join(:categories, :category_id=>:id).sql.should ==
|
|
1908
|
-
'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1909
|
-
@d.natural_join(:categories).sql.should ==
|
|
1910
|
-
'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
1911
|
-
@d.natural_left_join(:categories).sql.should ==
|
|
1912
|
-
'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
|
|
1913
|
-
@d.natural_right_join(:categories).sql.should ==
|
|
1914
|
-
'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
|
|
1915
|
-
@d.natural_full_join(:categories).sql.should ==
|
|
1916
|
-
'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
|
|
1917
|
-
@d.cross_join(:categories).sql.should ==
|
|
1918
|
-
'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2072
|
+
@d.left_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2073
|
+
@d.right_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2074
|
+
@d.full_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2075
|
+
@d.inner_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2076
|
+
@d.left_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2077
|
+
@d.right_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2078
|
+
@d.full_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2079
|
+
@d.natural_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2080
|
+
@d.natural_left_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
|
|
2081
|
+
@d.natural_right_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
|
|
2082
|
+
@d.natural_full_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
|
|
2083
|
+
@d.cross_join(:categories).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
1919
2084
|
end
|
|
1920
2085
|
|
|
1921
2086
|
specify "should raise an error if additional arguments are provided to join methods that don't take conditions" do
|
|
@@ -1935,95 +2100,76 @@ describe "Dataset#join_table" do
|
|
|
1935
2100
|
end
|
|
1936
2101
|
|
|
1937
2102
|
specify "should default to a plain join if nil is used for the type" do
|
|
1938
|
-
@d.join_table(nil, :categories, :category_id=>:id).sql.should ==
|
|
1939
|
-
'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2103
|
+
@d.join_table(nil, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1940
2104
|
end
|
|
1941
2105
|
|
|
1942
2106
|
specify "should use an inner join for Dataset#join" do
|
|
1943
|
-
@d.join(:categories, :category_id=>:id).sql.should ==
|
|
1944
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2107
|
+
@d.join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1945
2108
|
end
|
|
1946
2109
|
|
|
1947
2110
|
specify "should support aliased tables using the deprecated argument" do
|
|
1948
|
-
@d.from('stats').join('players', {:id => :player_id}, 'p').sql.should ==
|
|
1949
|
-
'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
|
2111
|
+
@d.from('stats').join('players', {:id => :player_id}, 'p').sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
|
1950
2112
|
end
|
|
1951
2113
|
|
|
1952
2114
|
specify "should support aliased tables using the :table_alias option" do
|
|
1953
|
-
@d.from('stats').join('players', {:id => :player_id}, :table_alias=>:p).sql.should ==
|
|
1954
|
-
'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
|
2115
|
+
@d.from('stats').join('players', {:id => :player_id}, :table_alias=>:p).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
|
1955
2116
|
end
|
|
1956
2117
|
|
|
1957
2118
|
specify "should support aliased tables using an implicit alias" do
|
|
1958
|
-
@d.from('stats').join(:players.as(:p), {:id => :player_id}).sql.should ==
|
|
1959
|
-
'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
|
2119
|
+
@d.from('stats').join(Sequel.expr(:players).as(:p), {:id => :player_id}).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
|
1960
2120
|
end
|
|
1961
2121
|
|
|
1962
2122
|
specify "should support using an alias for the FROM when doing the first join with unqualified condition columns" do
|
|
1963
|
-
|
|
1964
|
-
ds.quote_identifiers = true
|
|
1965
|
-
ds.join_table(:inner, :bar, :id => :bar_id).sql.should ==
|
|
1966
|
-
'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
|
2123
|
+
@d.from(:foo=>:f).join_table(:inner, :bar, :id => :bar_id).sql.should == 'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
|
1967
2124
|
end
|
|
1968
2125
|
|
|
1969
2126
|
specify "should support implicit schemas in from table symbols" do
|
|
1970
|
-
@d.from(:s__t).join(:u__v, {:id => :player_id}).sql.should ==
|
|
1971
|
-
'SELECT * FROM "s"."t" INNER JOIN "u"."v" ON ("u"."v"."id" = "s"."t"."player_id")'
|
|
2127
|
+
@d.from(:s__t).join(:u__v, {:id => :player_id}).sql.should == 'SELECT * FROM "s"."t" INNER JOIN "u"."v" ON ("u"."v"."id" = "s"."t"."player_id")'
|
|
1972
2128
|
end
|
|
1973
2129
|
|
|
1974
2130
|
specify "should support implicit aliases in from table symbols" do
|
|
1975
|
-
@d.from(:t___z).join(:v___y, {:id => :player_id}).sql.should ==
|
|
1976
|
-
|
|
1977
|
-
@d.from(:s__t___z).join(:u__v___y, {:id => :player_id}).sql.should ==
|
|
1978
|
-
'SELECT * FROM "s"."t" AS "z" INNER JOIN "u"."v" AS "y" ON ("y"."id" = "z"."player_id")'
|
|
2131
|
+
@d.from(:t___z).join(:v___y, {:id => :player_id}).sql.should == 'SELECT * FROM "t" AS "z" INNER JOIN "v" AS "y" ON ("y"."id" = "z"."player_id")'
|
|
2132
|
+
@d.from(:s__t___z).join(:u__v___y, {:id => :player_id}).sql.should == 'SELECT * FROM "s"."t" AS "z" INNER JOIN "u"."v" AS "y" ON ("y"."id" = "z"."player_id")'
|
|
1979
2133
|
end
|
|
1980
2134
|
|
|
1981
2135
|
specify "should support AliasedExpressions" do
|
|
1982
|
-
@d.from(:s.as(:t)).join(:u.as(:v), {:id => :player_id}).sql.should ==
|
|
1983
|
-
'SELECT * FROM "s" AS "t" INNER JOIN "u" AS "v" ON ("v"."id" = "t"."player_id")'
|
|
2136
|
+
@d.from(Sequel.expr(:s).as(:t)).join(Sequel.expr(:u).as(:v), {:id => :player_id}).sql.should == 'SELECT * FROM "s" AS "t" INNER JOIN "u" AS "v" ON ("v"."id" = "t"."player_id")'
|
|
1984
2137
|
end
|
|
1985
2138
|
|
|
1986
2139
|
specify "should support the :implicit_qualifier option" do
|
|
1987
|
-
@d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should ==
|
|
1988
|
-
|
|
2140
|
+
@d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON ("players"."id" = "p"."player_id")'
|
|
2141
|
+
end
|
|
2142
|
+
|
|
2143
|
+
specify "should not qualify if :qualify=>false option is given" do
|
|
2144
|
+
@d.from('stats').join(:players, {:id => :player_id}, :qualify=>false).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON ("id" = "player_id")'
|
|
2145
|
+
end
|
|
2146
|
+
|
|
2147
|
+
specify "should do deep qualification if :qualify=>:deep option is given" do
|
|
2148
|
+
@d.from('stats').join(:players, {Sequel.function(:f, :id) => Sequel.subscript(:player_id, 0)}, :qualify=>:deep).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON (f("players"."id") = "stats"."player_id"[0])'
|
|
1989
2149
|
end
|
|
1990
2150
|
|
|
1991
2151
|
specify "should allow for arbitrary conditions in the JOIN clause" do
|
|
1992
|
-
@d.join_table(:left_outer, :categories, :status => 0).sql.should ==
|
|
1993
|
-
|
|
1994
|
-
@d.join_table(:left_outer, :categories, :
|
|
1995
|
-
|
|
1996
|
-
@d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should ==
|
|
1997
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
|
1998
|
-
@d.join_table(:left_outer, :categories, :status => [1, 2, 3]).sql.should ==
|
|
1999
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" IN (1, 2, 3))'
|
|
2152
|
+
@d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
|
2153
|
+
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
|
2154
|
+
@d.join_table(:left_outer, :categories, :timestamp => Sequel::CURRENT_TIMESTAMP).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
|
2155
|
+
@d.join_table(:left_outer, :categories, :status => [1, 2, 3]).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" IN (1, 2, 3))'
|
|
2000
2156
|
end
|
|
2001
2157
|
|
|
2002
2158
|
specify "should raise error for a table without a source" do
|
|
2003
|
-
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.
|
|
2004
|
-
should raise_error(Sequel::Error)
|
|
2159
|
+
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.should raise_error(Sequel::Error)
|
|
2005
2160
|
end
|
|
2006
2161
|
|
|
2007
2162
|
specify "should support joining datasets" do
|
|
2008
2163
|
ds = Sequel::Dataset.new(nil).from(:categories)
|
|
2009
|
-
|
|
2010
|
-
@d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
|
|
2011
|
-
'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id")'
|
|
2012
|
-
|
|
2164
|
+
@d.join_table(:left_outer, ds, :item_id => :id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id")'
|
|
2013
2165
|
ds.filter!(:active => true)
|
|
2014
|
-
|
|
2015
|
-
@d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
|
|
2016
|
-
'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t1" ON ("t1"."item_id" = "items"."id")'
|
|
2017
|
-
|
|
2018
|
-
@d.from_self.join_table(:left_outer, ds, :item_id => :id).sql.should ==
|
|
2019
|
-
'SELECT * FROM (SELECT * FROM "items") AS "t1" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t2" ON ("t2"."item_id" = "t1"."id")'
|
|
2166
|
+
@d.join_table(:left_outer, ds, :item_id => :id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t1" ON ("t1"."item_id" = "items"."id")'
|
|
2167
|
+
@d.from_self.join_table(:left_outer, ds, :item_id => :id).sql.should == 'SELECT * FROM (SELECT * FROM "items") AS "t1" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t2" ON ("t2"."item_id" = "t1"."id")'
|
|
2020
2168
|
end
|
|
2021
2169
|
|
|
2022
2170
|
specify "should support joining datasets and aliasing the join" do
|
|
2023
2171
|
ds = Sequel::Dataset.new(nil).from(:categories)
|
|
2024
|
-
|
|
2025
|
-
@d.join_table(:left_outer, ds, {:ds__item_id => :id}, :ds).sql.should ==
|
|
2026
|
-
'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
|
|
2172
|
+
@d.join_table(:left_outer, ds, {:ds__item_id => :id}, :ds).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
|
|
2027
2173
|
end
|
|
2028
2174
|
|
|
2029
2175
|
specify "should support joining multiple datasets" do
|
|
@@ -2037,43 +2183,27 @@ describe "Dataset#join_table" do
|
|
|
2037
2183
|
'RIGHT OUTER JOIN (SELECT * FROM attributes WHERE (name = \'blah\')) AS "t3" ON ("t3"."attribute_id" = "t2"."id")'
|
|
2038
2184
|
end
|
|
2039
2185
|
|
|
2040
|
-
specify "should support
|
|
2041
|
-
|
|
2042
|
-
def ds.table_name; :categories end
|
|
2043
|
-
|
|
2044
|
-
@d.join(ds, :item_id => :id).sql.should ==
|
|
2045
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
|
|
2186
|
+
specify "should support using an SQL String as the join condition" do
|
|
2187
|
+
@d.join(:categories, "c.item_id = items.id", :c).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
|
2046
2188
|
end
|
|
2047
2189
|
|
|
2048
|
-
specify "should support using a
|
|
2049
|
-
@d.join(:categories,
|
|
2050
|
-
'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
|
2051
|
-
end
|
|
2052
|
-
|
|
2053
|
-
specify "should support using a boolean column as the join condition" do
|
|
2054
|
-
@d.join(:categories, :active).sql.should ==
|
|
2055
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
|
2190
|
+
specify "should support using a boolean column as the join condition" do
|
|
2191
|
+
@d.join(:categories, :active).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
|
2056
2192
|
end
|
|
2057
2193
|
|
|
2058
2194
|
specify "should support using an expression as the join condition" do
|
|
2059
|
-
@d.join(:categories, :number
|
|
2060
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2195
|
+
@d.join(:categories, Sequel.expr(:number) > 10).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2061
2196
|
end
|
|
2062
2197
|
|
|
2063
|
-
specify "should support natural and cross joins
|
|
2064
|
-
@d.join_table(:natural, :categories).sql.should ==
|
|
2065
|
-
|
|
2066
|
-
@d.join_table(:
|
|
2067
|
-
'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2068
|
-
@d.join_table(:natural, :categories, nil, :c).sql.should ==
|
|
2069
|
-
'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
|
2198
|
+
specify "should support natural and cross joins" do
|
|
2199
|
+
@d.join_table(:natural, :categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2200
|
+
@d.join_table(:cross, :categories, nil).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2201
|
+
@d.join_table(:natural, :categories, nil, :c).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
|
2070
2202
|
end
|
|
2071
2203
|
|
|
2072
2204
|
specify "should support joins with a USING clause if an array of symbols is used" do
|
|
2073
|
-
@d.join(:categories, [:id]).sql.should ==
|
|
2074
|
-
|
|
2075
|
-
@d.join(:categories, [:id1, :id2]).sql.should ==
|
|
2076
|
-
'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
|
2205
|
+
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
|
|
2206
|
+
@d.join(:categories, [:id1, :id2]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
|
2077
2207
|
end
|
|
2078
2208
|
|
|
2079
2209
|
specify "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
|
|
@@ -2081,6 +2211,12 @@ describe "Dataset#join_table" do
|
|
|
2081
2211
|
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."id" = "items"."id")'
|
|
2082
2212
|
end
|
|
2083
2213
|
|
|
2214
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
2215
|
+
@d.meta_def(:supports_cte?){true}
|
|
2216
|
+
@d.meta_def(:supports_cte_in_subselect?){false}
|
|
2217
|
+
@d.join(Sequel::Dataset.new(nil).from(:categories).with(:a, Sequel::Dataset.new(nil).from(:b)), [:id]).sql.should == 'WITH "a" AS (SELECT * FROM b) SELECT * FROM "items" INNER JOIN (SELECT * FROM categories) AS "t1" USING ("id")'
|
|
2218
|
+
end
|
|
2219
|
+
|
|
2084
2220
|
specify "should raise an error if using an array of symbols with a block" do
|
|
2085
2221
|
proc{@d.join(:categories, [:id]){|j,lj,js|}}.should raise_error(Sequel::Error)
|
|
2086
2222
|
end
|
|
@@ -2135,27 +2271,21 @@ describe "Dataset#join_table" do
|
|
|
2135
2271
|
end
|
|
2136
2272
|
|
|
2137
2273
|
specify "should use the block result as the only condition if no condition is given" do
|
|
2138
|
-
@d.join(:categories){|j,lj,js| {
|
|
2139
|
-
|
|
2140
|
-
@d.join(:categories){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should ==
|
|
2141
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" > "items"."c")'
|
|
2274
|
+
@d.join(:categories){|j,lj,js| {Sequel.qualify(j, :b)=>Sequel.qualify(lj, :c)}}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" = "items"."c")'
|
|
2275
|
+
@d.join(:categories){|j,lj,js| Sequel.qualify(j, :b) > Sequel.qualify(lj, :c)}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" > "items"."c")'
|
|
2142
2276
|
end
|
|
2143
2277
|
|
|
2144
2278
|
specify "should combine the block conditions and argument conditions if both given" do
|
|
2145
|
-
@d.join(:categories, :a=>:d){|j,lj,js| {
|
|
2146
|
-
|
|
2147
|
-
@d.join(:categories, :a=>:d){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should ==
|
|
2148
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" > "items"."c"))'
|
|
2279
|
+
@d.join(:categories, :a=>:d){|j,lj,js| {Sequel.qualify(j, :b)=>Sequel.qualify(lj, :c)}}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" = "items"."c"))'
|
|
2280
|
+
@d.join(:categories, :a=>:d){|j,lj,js| Sequel.qualify(j, :b) > Sequel.qualify(lj, :c)}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" > "items"."c"))'
|
|
2149
2281
|
end
|
|
2150
2282
|
|
|
2151
2283
|
specify "should prefer explicit aliases over implicit" do
|
|
2152
|
-
@d.from(:items___i).join(:categories___c, {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
|
|
2153
|
-
|
|
2154
|
-
@d.from(:items.as(:i)).join(:categories.as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
|
|
2284
|
+
@d.from(:items___i).join(:categories___c, {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should == 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2285
|
+
@d.from(Sequel.expr(:items).as(:i)).join(Sequel.expr(:categories).as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
|
|
2155
2286
|
'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2156
2287
|
end
|
|
2157
2288
|
|
|
2158
|
-
|
|
2159
2289
|
specify "should not allow insert, update, delete, or truncate" do
|
|
2160
2290
|
proc{@d.join(:categories, :a=>:d).insert_sql}.should raise_error(Sequel::InvalidOperation)
|
|
2161
2291
|
proc{@d.join(:categories, :a=>:d).update_sql(:a=>1)}.should raise_error(Sequel::InvalidOperation)
|
|
@@ -2165,86 +2295,64 @@ describe "Dataset#join_table" do
|
|
|
2165
2295
|
|
|
2166
2296
|
specify "should raise an error if an invalid option is passed" do
|
|
2167
2297
|
proc{@d.join(:c, [:id], nil)}.should raise_error(Sequel::Error)
|
|
2168
|
-
proc{@d.join(:c, [:id],
|
|
2298
|
+
proc{@d.join(:c, [:id], Sequel.qualify(:d, :c))}.should raise_error(Sequel::Error)
|
|
2169
2299
|
end
|
|
2170
2300
|
end
|
|
2171
2301
|
|
|
2172
2302
|
describe "Dataset#[]=" do
|
|
2173
|
-
before do
|
|
2174
|
-
c = Class.new(Sequel::Dataset) do
|
|
2175
|
-
def last_sql
|
|
2176
|
-
@@last_sql
|
|
2177
|
-
end
|
|
2178
|
-
|
|
2179
|
-
def update(*args)
|
|
2180
|
-
@@last_sql = update_sql(*args)
|
|
2181
|
-
end
|
|
2182
|
-
end
|
|
2183
|
-
|
|
2184
|
-
@d = c.new(nil).from(:items)
|
|
2185
|
-
end
|
|
2186
|
-
|
|
2187
2303
|
specify "should perform an update on the specified filter" do
|
|
2188
|
-
|
|
2189
|
-
|
|
2304
|
+
db = Sequel.mock
|
|
2305
|
+
ds = db[:items]
|
|
2306
|
+
ds[:a => 1] = {:x => 3}
|
|
2307
|
+
db.sqls.should == ['UPDATE items SET x = 3 WHERE (a = 1)']
|
|
2190
2308
|
end
|
|
2191
2309
|
end
|
|
2192
2310
|
|
|
2193
2311
|
describe "Dataset#set" do
|
|
2194
|
-
before do
|
|
2195
|
-
c = Class.new(Sequel::Dataset) do
|
|
2196
|
-
def last_sql
|
|
2197
|
-
@@last_sql
|
|
2198
|
-
end
|
|
2199
|
-
|
|
2200
|
-
def update(*args, &block)
|
|
2201
|
-
@@last_sql = update_sql(*args, &block)
|
|
2202
|
-
end
|
|
2203
|
-
end
|
|
2204
|
-
|
|
2205
|
-
@d = c.new(nil).from(:items)
|
|
2206
|
-
end
|
|
2207
|
-
|
|
2208
2312
|
specify "should act as alias to #update" do
|
|
2209
|
-
|
|
2210
|
-
|
|
2313
|
+
db = Sequel.mock
|
|
2314
|
+
ds = db[:items]
|
|
2315
|
+
ds.set({:x => 3})
|
|
2316
|
+
db.sqls.should == ['UPDATE items SET x = 3']
|
|
2211
2317
|
end
|
|
2212
2318
|
end
|
|
2213
2319
|
|
|
2214
|
-
|
|
2215
2320
|
describe "Dataset#insert_multiple" do
|
|
2216
2321
|
before do
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
def insert(arg)
|
|
2220
|
-
@inserts ||= []
|
|
2221
|
-
@inserts << arg
|
|
2222
|
-
end
|
|
2223
|
-
end
|
|
2224
|
-
|
|
2225
|
-
@d = c.new(nil)
|
|
2322
|
+
@db = Sequel.mock(:autoid=>2)
|
|
2323
|
+
@ds = @db[:items]
|
|
2226
2324
|
end
|
|
2227
2325
|
|
|
2228
2326
|
specify "should insert all items in the supplied array" do
|
|
2229
|
-
@
|
|
2230
|
-
@
|
|
2327
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}])
|
|
2328
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('aa')",
|
|
2329
|
+
"INSERT INTO items VALUES (5)",
|
|
2330
|
+
"INSERT INTO items VALUES (3)",
|
|
2331
|
+
"INSERT INTO items (a) VALUES (2)"]
|
|
2231
2332
|
end
|
|
2232
2333
|
|
|
2233
2334
|
specify "should pass array items through the supplied block if given" do
|
|
2234
|
-
|
|
2235
|
-
@
|
|
2236
|
-
|
|
2335
|
+
@ds.insert_multiple(["inevitable", "hello", "the ticking clock"]){|i| i.gsub('l', 'r')}
|
|
2336
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('inevitabre')",
|
|
2337
|
+
"INSERT INTO items VALUES ('herro')",
|
|
2338
|
+
"INSERT INTO items VALUES ('the ticking crock')"]
|
|
2339
|
+
end
|
|
2340
|
+
|
|
2341
|
+
specify "should return array of inserted ids" do
|
|
2342
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}]).should == [2, 3, 4, 5]
|
|
2343
|
+
end
|
|
2344
|
+
|
|
2345
|
+
specify "should work exactly like in metioned in the example" do
|
|
2346
|
+
@ds.insert_multiple([{:x=>1}, {:x=>2}]){|row| row[:y] = row[:x] * 2 ; row }
|
|
2347
|
+
sqls = @db.sqls
|
|
2348
|
+
["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls[0])
|
|
2349
|
+
["INSERT INTO items (x, y) VALUES (2, 4)", "INSERT INTO items (y, x) VALUES (4, 2)"].should include(sqls[1])
|
|
2237
2350
|
end
|
|
2238
2351
|
end
|
|
2239
2352
|
|
|
2240
2353
|
describe "Dataset aggregate methods" do
|
|
2241
2354
|
before do
|
|
2242
|
-
|
|
2243
|
-
def fetch_rows(sql)
|
|
2244
|
-
yield({1 => sql})
|
|
2245
|
-
end
|
|
2246
|
-
end
|
|
2247
|
-
@d = c.new(nil).from(:test)
|
|
2355
|
+
@d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
|
|
2248
2356
|
end
|
|
2249
2357
|
|
|
2250
2358
|
specify "should include min" do
|
|
@@ -2278,116 +2386,88 @@ end
|
|
|
2278
2386
|
|
|
2279
2387
|
describe "Dataset#range" do
|
|
2280
2388
|
before do
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
def last_sql; self.class.send(:class_variable_get, :@@sql); end
|
|
2285
|
-
|
|
2286
|
-
def fetch_rows(sql)
|
|
2287
|
-
self.class.send(:class_variable_set, :@@sql, sql)
|
|
2288
|
-
yield(:v1 => 1, :v2 => 10)
|
|
2289
|
-
end
|
|
2290
|
-
end
|
|
2291
|
-
@d = c.new(nil).from(:test)
|
|
2389
|
+
@db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
|
|
2390
|
+
@ds = @db[:test]
|
|
2292
2391
|
end
|
|
2293
2392
|
|
|
2294
2393
|
specify "should generate a correct SQL statement" do
|
|
2295
|
-
@
|
|
2296
|
-
@
|
|
2394
|
+
@ds.range(:stamp)
|
|
2395
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
|
|
2297
2396
|
|
|
2298
|
-
@
|
|
2299
|
-
@
|
|
2397
|
+
@ds.filter(Sequel.expr(:price) > 100).range(:stamp)
|
|
2398
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
|
|
2300
2399
|
end
|
|
2301
2400
|
|
|
2302
2401
|
specify "should return a range object" do
|
|
2303
|
-
@
|
|
2402
|
+
@ds.range(:tryme).should == (1..10)
|
|
2304
2403
|
end
|
|
2305
2404
|
|
|
2306
2405
|
specify "should use a subselect for the same conditions as count" do
|
|
2307
|
-
@
|
|
2308
|
-
@
|
|
2406
|
+
@ds.order(:stamp).limit(5).range(:stamp).should == (1..10)
|
|
2407
|
+
@db.sqls.should == ['SELECT min(stamp) AS v1, max(stamp) AS v2 FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
|
|
2309
2408
|
end
|
|
2310
2409
|
end
|
|
2311
2410
|
|
|
2312
2411
|
describe "Dataset#interval" do
|
|
2313
2412
|
before do
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
def last_sql; self.class.send(:class_variable_get, :@@sql); end
|
|
2318
|
-
|
|
2319
|
-
def fetch_rows(sql)
|
|
2320
|
-
self.class.send(:class_variable_set, :@@sql, sql)
|
|
2321
|
-
yield(:v => 1234)
|
|
2322
|
-
end
|
|
2323
|
-
end
|
|
2324
|
-
@d = c.new(nil).from(:test)
|
|
2413
|
+
@db = Sequel.mock(:fetch=>{:v => 1234})
|
|
2414
|
+
@ds = @db[:test]
|
|
2325
2415
|
end
|
|
2326
2416
|
|
|
2327
|
-
specify "should generate
|
|
2328
|
-
@
|
|
2329
|
-
@
|
|
2417
|
+
specify "should generate the correct SQL statement" do
|
|
2418
|
+
@ds.interval(:stamp)
|
|
2419
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"]
|
|
2330
2420
|
|
|
2331
|
-
@
|
|
2332
|
-
@
|
|
2333
|
-
end
|
|
2334
|
-
|
|
2335
|
-
specify "should return an integer" do
|
|
2336
|
-
@d.interval(:tryme).should == 1234
|
|
2421
|
+
@ds.filter(Sequel.expr(:price) > 100).interval(:stamp)
|
|
2422
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"]
|
|
2337
2423
|
end
|
|
2338
2424
|
|
|
2339
2425
|
specify "should use a subselect for the same conditions as count" do
|
|
2340
|
-
@
|
|
2341
|
-
@
|
|
2426
|
+
@ds.order(:stamp).limit(5).interval(:stamp).should == 1234
|
|
2427
|
+
@db.sqls.should == ['SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
|
|
2342
2428
|
end
|
|
2343
2429
|
end
|
|
2344
2430
|
|
|
2345
2431
|
describe "Dataset #first and #last" do
|
|
2346
2432
|
before do
|
|
2347
|
-
@
|
|
2348
|
-
|
|
2349
|
-
s = select_sql
|
|
2350
|
-
x = [:a,1,:b,2,s]
|
|
2351
|
-
i = /LIMIT (\d+)/.match(s)[1].to_i.times{yield x}
|
|
2352
|
-
end
|
|
2353
|
-
end
|
|
2354
|
-
@d = @c.new(nil).from(:test)
|
|
2433
|
+
@db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
|
|
2434
|
+
@d = @db[:test]
|
|
2355
2435
|
end
|
|
2356
2436
|
|
|
2357
2437
|
specify "should return a single record if no argument is given" do
|
|
2358
|
-
@d.order(:a).first.should ==
|
|
2359
|
-
@d.order(:a).last.should ==
|
|
2438
|
+
@d.order(:a).first.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
|
|
2439
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2360
2440
|
end
|
|
2361
2441
|
|
|
2362
2442
|
specify "should return the first/last matching record if argument is not an Integer" do
|
|
2363
|
-
@d.order(:a).first(:z => 26).should ==
|
|
2364
|
-
@d.order(:a).first('z = ?', 15).should ==
|
|
2365
|
-
@d.order(:a).last(:z => 26).should ==
|
|
2366
|
-
@d.order(:a).last('z = ?', 15).should ==
|
|
2443
|
+
@d.order(:a).first(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
|
|
2444
|
+
@d.order(:a).first('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
|
|
2445
|
+
@d.order(:a).last(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1'}
|
|
2446
|
+
@d.order(:a).last('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1'}
|
|
2367
2447
|
end
|
|
2368
2448
|
|
|
2369
2449
|
specify "should set the limit and return an array of records if the given number is > 1" do
|
|
2370
2450
|
i = rand(10) + 10
|
|
2371
|
-
r = @d.order(:a).first(i).should == [
|
|
2451
|
+
r = @d.order(:a).first(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
|
|
2372
2452
|
i = rand(10) + 10
|
|
2373
|
-
r = @d.order(:a).last(i).should == [
|
|
2453
|
+
r = @d.order(:a).last(i).should == [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
|
|
2374
2454
|
end
|
|
2375
2455
|
|
|
2376
2456
|
specify "should return the first matching record if a block is given without an argument" do
|
|
2377
|
-
@d.first{
|
|
2378
|
-
@d.order(:name).last{
|
|
2457
|
+
@d.first{z > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
|
|
2458
|
+
@d.order(:name).last{z > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1'}
|
|
2379
2459
|
end
|
|
2380
2460
|
|
|
2381
2461
|
specify "should combine block and standard argument filters if argument is not an Integer" do
|
|
2382
|
-
@d.first(:y=>25){
|
|
2383
|
-
@d.order(:name).last('y = ?', 16){
|
|
2462
|
+
@d.first(:y=>25){z > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
|
|
2463
|
+
@d.order(:name).last('y = ?', 16){z > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 16)) ORDER BY name DESC LIMIT 1'}
|
|
2384
2464
|
end
|
|
2385
2465
|
|
|
2386
2466
|
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
|
2387
2467
|
i = rand(10) + 10
|
|
2388
|
-
r = @d.order(:a).first(i){
|
|
2468
|
+
r = @d.order(:a).first(i){z > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
|
|
2389
2469
|
i = rand(10) + 10
|
|
2390
|
-
r = @d.order(:a).last(i){
|
|
2470
|
+
r = @d.order(:a).last(i){z > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"}]
|
|
2391
2471
|
end
|
|
2392
2472
|
|
|
2393
2473
|
specify "#last should raise if no order is given" do
|
|
@@ -2398,10 +2478,10 @@ describe "Dataset #first and #last" do
|
|
|
2398
2478
|
end
|
|
2399
2479
|
|
|
2400
2480
|
specify "#last should invert the order" do
|
|
2401
|
-
@d.order(:a).last.
|
|
2402
|
-
@d.order(:b
|
|
2403
|
-
@d.order(:c, :d).last.
|
|
2404
|
-
@d.order(:e
|
|
2481
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2482
|
+
@d.order(Sequel.desc(:b)).last.should == {:s=>'SELECT * FROM test ORDER BY b ASC LIMIT 1'}
|
|
2483
|
+
@d.order(:c, :d).last.should == {:s=>'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'}
|
|
2484
|
+
@d.order(Sequel.desc(:e), :f).last.should == {:s=>'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'}
|
|
2405
2485
|
end
|
|
2406
2486
|
end
|
|
2407
2487
|
|
|
@@ -2412,55 +2492,37 @@ describe "Dataset compound operations" do
|
|
|
2412
2492
|
end
|
|
2413
2493
|
|
|
2414
2494
|
specify "should support UNION and UNION ALL" do
|
|
2415
|
-
@a.union(@b).sql.should ==
|
|
2416
|
-
|
|
2417
|
-
@b.union(@a, true).sql.should ==
|
|
2418
|
-
"SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2419
|
-
@b.union(@a, :all=>true).sql.should == \
|
|
2420
|
-
"SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2495
|
+
@a.union(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2496
|
+
@b.union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2497
|
+
@b.union(@a, :all=>true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2421
2498
|
end
|
|
2422
2499
|
|
|
2423
2500
|
specify "should support INTERSECT and INTERSECT ALL" do
|
|
2424
|
-
@a.intersect(@b).sql.should ==
|
|
2425
|
-
|
|
2426
|
-
@b.intersect(@a, true).sql.should ==
|
|
2427
|
-
"SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2428
|
-
@b.intersect(@a, :all=>true).sql.should == \
|
|
2429
|
-
"SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2501
|
+
@a.intersect(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2502
|
+
@b.intersect(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2503
|
+
@b.intersect(@a, :all=>true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2430
2504
|
end
|
|
2431
2505
|
|
|
2432
2506
|
specify "should support EXCEPT and EXCEPT ALL" do
|
|
2433
|
-
@a.except(@b).sql.should ==
|
|
2434
|
-
|
|
2435
|
-
@b.except(@a, true).sql.should ==
|
|
2436
|
-
"SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2437
|
-
@b.except(@a, :all=>true).sql.should == \
|
|
2438
|
-
"SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2507
|
+
@a.except(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2508
|
+
@b.except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2509
|
+
@b.except(@a, :all=>true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2439
2510
|
end
|
|
2440
2511
|
|
|
2441
2512
|
specify "should support :alias option for specifying identifier" do
|
|
2442
|
-
@a.union(@b, :alias=>:xx).sql.should ==
|
|
2443
|
-
|
|
2444
|
-
@a.
|
|
2445
|
-
"SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2446
|
-
@a.except(@b, :alias=>:xx).sql.should == \
|
|
2447
|
-
"SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2513
|
+
@a.union(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2514
|
+
@a.intersect(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2515
|
+
@a.except(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2448
2516
|
end
|
|
2449
2517
|
|
|
2450
2518
|
specify "should support :from_self=>false option to not wrap the compound in a SELECT * FROM (...)" do
|
|
2451
|
-
@b.union(@a, :from_self=>false).sql.should ==
|
|
2452
|
-
|
|
2453
|
-
@b.
|
|
2454
|
-
"SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
|
|
2455
|
-
@b.except(@a, :from_self=>false).sql.should == \
|
|
2456
|
-
"SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
|
|
2519
|
+
@b.union(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
|
|
2520
|
+
@b.intersect(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
|
|
2521
|
+
@b.except(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
|
|
2457
2522
|
|
|
2458
|
-
@b.union(@a, :from_self=>false, :all=>true).sql.should ==
|
|
2459
|
-
|
|
2460
|
-
@b.
|
|
2461
|
-
"SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2462
|
-
@b.except(@a, :from_self=>false, :all=>true).sql.should == \
|
|
2463
|
-
"SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2523
|
+
@b.union(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
|
|
2524
|
+
@b.intersect(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2525
|
+
@b.except(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2464
2526
|
end
|
|
2465
2527
|
|
|
2466
2528
|
specify "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
|
|
@@ -2480,141 +2542,105 @@ describe "Dataset compound operations" do
|
|
|
2480
2542
|
end
|
|
2481
2543
|
|
|
2482
2544
|
specify "should handle chained compound operations" do
|
|
2483
|
-
@a.union(@b).union(@a, true).sql.should ==
|
|
2484
|
-
|
|
2485
|
-
@a.
|
|
2486
|
-
"SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM b WHERE (z = 2)) AS t1 INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2487
|
-
@a.except(@b).except(@a, true).sql.should == \
|
|
2488
|
-
"SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1 EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2545
|
+
@a.union(@b).union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1 UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2546
|
+
@a.intersect(@b, true).intersect(@a).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM b WHERE (z = 2)) AS t1 INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2547
|
+
@a.except(@b).except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1 EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2489
2548
|
end
|
|
2490
2549
|
|
|
2491
2550
|
specify "should use a subselect when using a compound operation with a dataset that already has a compound operation" do
|
|
2492
|
-
@a.union(@b.union(@a, true)).sql.should ==
|
|
2493
|
-
|
|
2494
|
-
@a.
|
|
2495
|
-
"SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
|
|
2496
|
-
@a.except(@b.except(@a, true)).sql.should == \
|
|
2497
|
-
"SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
|
|
2551
|
+
@a.union(@b.union(@a, true)).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
|
|
2552
|
+
@a.intersect(@b.intersect(@a), true).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT ALL SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
|
|
2553
|
+
@a.except(@b.except(@a, true)).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1) AS t1"
|
|
2498
2554
|
end
|
|
2499
2555
|
|
|
2500
2556
|
specify "should order and limit properly when using UNION, INTERSECT, or EXCEPT" do
|
|
2501
2557
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
2502
|
-
@dataset.union(@dataset).limit(2).sql.should ==
|
|
2503
|
-
|
|
2504
|
-
@dataset.limit(2)
|
|
2505
|
-
|
|
2506
|
-
@dataset.
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
@dataset.union(@dataset).order(:num).sql.should ==
|
|
2510
|
-
"SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
|
|
2511
|
-
@dataset.order(:num).intersect(@dataset).sql.should ==
|
|
2512
|
-
"SELECT * FROM (SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2513
|
-
@dataset.except(@dataset.order(:num)).sql.should ==
|
|
2514
|
-
"SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1) AS t1"
|
|
2558
|
+
@dataset.union(@dataset).limit(2).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
|
|
2559
|
+
@dataset.limit(2).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2560
|
+
@dataset.except(@dataset.limit(2)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
|
|
2561
|
+
|
|
2562
|
+
@dataset.union(@dataset).order(:num).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
|
|
2563
|
+
@dataset.order(:num).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2564
|
+
@dataset.except(@dataset.order(:num)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test ORDER BY num) AS t1) AS t1"
|
|
2515
2565
|
|
|
2516
2566
|
@dataset.limit(2).order(:a).union(@dataset.limit(3).order(:b)).order(:c).limit(4).sql.should ==
|
|
2517
2567
|
"SELECT * FROM (SELECT * FROM (SELECT * FROM test ORDER BY a LIMIT 2) AS t1 UNION SELECT * FROM (SELECT * FROM test ORDER BY b LIMIT 3) AS t1) AS t1 ORDER BY c LIMIT 4"
|
|
2518
2568
|
end
|
|
2519
2569
|
|
|
2570
|
+
specify "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
|
|
2571
|
+
ds = Sequel::Dataset.new(nil)
|
|
2572
|
+
ds.meta_def(:supports_cte?){true}
|
|
2573
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2574
|
+
ds.from(:a).union(ds.from(:c).with(:c, ds.from(:d)), :from_self=>false).sql.should == 'WITH c AS (SELECT * FROM d) SELECT * FROM a UNION SELECT * FROM c'
|
|
2575
|
+
ds.from(:a).except(ds.from(:c).with(:c, ds.from(:d))).sql.should == 'WITH c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a EXCEPT SELECT * FROM c) AS t1'
|
|
2576
|
+
ds.from(:a).with(:a, ds.from(:b)).intersect(ds.from(:c).with(:c, ds.from(:d)), :from_self=>false).sql.should == 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM a INTERSECT SELECT * FROM c'
|
|
2577
|
+
end
|
|
2520
2578
|
end
|
|
2521
2579
|
|
|
2522
2580
|
describe "Dataset#[]" do
|
|
2523
2581
|
before do
|
|
2524
|
-
@
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
def self.last_dataset
|
|
2528
|
-
class_variable_get(:@@last_dataset)
|
|
2529
|
-
end
|
|
2530
|
-
|
|
2531
|
-
def single_record
|
|
2532
|
-
self.class.send(:class_variable_set, :@@last_dataset, opts ? clone(opts) : self)
|
|
2533
|
-
{1 => 2, 3 => 4}
|
|
2534
|
-
end
|
|
2535
|
-
end
|
|
2536
|
-
@d = @c.new(nil).from(:test)
|
|
2582
|
+
@db = Sequel.mock(:fetch=>{1 => 2, 3 => 4})
|
|
2583
|
+
@d = @db[:items]
|
|
2537
2584
|
end
|
|
2538
2585
|
|
|
2539
2586
|
specify "should return a single record filtered according to the given conditions" do
|
|
2540
2587
|
@d[:name => 'didi'].should == {1 => 2, 3 => 4}
|
|
2541
|
-
@
|
|
2588
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (name = 'didi') LIMIT 1"]
|
|
2542
2589
|
|
|
2543
2590
|
@d[:id => 5..45].should == {1 => 2, 3 => 4}
|
|
2544
|
-
@
|
|
2591
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((id >= 5) AND (id <= 45)) LIMIT 1"]
|
|
2545
2592
|
end
|
|
2546
2593
|
end
|
|
2547
2594
|
|
|
2548
2595
|
describe "Dataset#single_record" do
|
|
2549
2596
|
before do
|
|
2550
|
-
@
|
|
2551
|
-
def fetch_rows(sql)
|
|
2552
|
-
yield sql
|
|
2553
|
-
end
|
|
2554
|
-
end
|
|
2555
|
-
@cc = Class.new(@c) do
|
|
2556
|
-
def fetch_rows(sql); end
|
|
2557
|
-
end
|
|
2558
|
-
|
|
2559
|
-
@d = @c.new(nil).from(:test)
|
|
2560
|
-
@e = @cc.new(nil).from(:test)
|
|
2597
|
+
@db = Sequel.mock
|
|
2561
2598
|
end
|
|
2562
2599
|
|
|
2563
2600
|
specify "should call each with a limit of 1 and return the record" do
|
|
2564
|
-
@
|
|
2601
|
+
@db.fetch = {:a=>1}
|
|
2602
|
+
@db[:test].single_record.should == {:a=>1}
|
|
2603
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2565
2604
|
end
|
|
2566
2605
|
|
|
2567
2606
|
specify "should return nil if no record is present" do
|
|
2568
|
-
@
|
|
2607
|
+
@db[:test].single_record.should be_nil
|
|
2608
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2569
2609
|
end
|
|
2570
2610
|
end
|
|
2571
2611
|
|
|
2572
2612
|
describe "Dataset#single_value" do
|
|
2573
2613
|
before do
|
|
2574
|
-
@
|
|
2575
|
-
def fetch_rows(sql)
|
|
2576
|
-
yield({1 => sql})
|
|
2577
|
-
end
|
|
2578
|
-
end
|
|
2579
|
-
@cc = Class.new(@c) do
|
|
2580
|
-
def fetch_rows(sql); end
|
|
2581
|
-
end
|
|
2582
|
-
|
|
2583
|
-
@d = @c.new(nil).from(:test)
|
|
2584
|
-
@e = @cc.new(nil).from(:test)
|
|
2614
|
+
@db = Sequel.mock
|
|
2585
2615
|
end
|
|
2586
2616
|
|
|
2587
2617
|
specify "should call each and return the first value of the first record" do
|
|
2588
|
-
@
|
|
2618
|
+
@db.fetch = {:a=>1}
|
|
2619
|
+
@db[:test].single_value.should == 1
|
|
2620
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2589
2621
|
end
|
|
2590
2622
|
|
|
2591
2623
|
specify "should return nil if no records" do
|
|
2592
|
-
@
|
|
2624
|
+
@db[:test].single_value.should be_nil
|
|
2625
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2593
2626
|
end
|
|
2594
2627
|
|
|
2595
2628
|
it "should work on a graphed_dataset" do
|
|
2596
|
-
@
|
|
2597
|
-
@
|
|
2629
|
+
@db.fetch = {:a=>1}
|
|
2630
|
+
ds = @db[:test].columns(:a)
|
|
2631
|
+
ds.graph(ds, [:a], :table_alias=>:test2).single_value.should == 1
|
|
2632
|
+
@db.sqls.should == ['SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
2598
2633
|
end
|
|
2599
2634
|
end
|
|
2600
2635
|
|
|
2601
2636
|
describe "Dataset#get" do
|
|
2602
2637
|
before do
|
|
2603
|
-
@
|
|
2604
|
-
attr_reader :last_sql
|
|
2605
|
-
|
|
2606
|
-
def fetch_rows(sql)
|
|
2607
|
-
@last_sql = sql
|
|
2608
|
-
yield(:name => sql)
|
|
2609
|
-
end
|
|
2610
|
-
end
|
|
2611
|
-
|
|
2612
|
-
@d = @c.new(nil).from(:test)
|
|
2638
|
+
@d = Sequel.mock(:fetch=>proc{|s| {:name=>s}})[:test]
|
|
2613
2639
|
end
|
|
2614
2640
|
|
|
2615
2641
|
specify "should select the specified column and fetch its value" do
|
|
2616
2642
|
@d.get(:name).should == "SELECT name FROM test LIMIT 1"
|
|
2617
|
-
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2643
|
+
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2618
2644
|
end
|
|
2619
2645
|
|
|
2620
2646
|
specify "should work with filters" do
|
|
@@ -2622,7 +2648,7 @@ describe "Dataset#get" do
|
|
|
2622
2648
|
end
|
|
2623
2649
|
|
|
2624
2650
|
specify "should work with aliased fields" do
|
|
2625
|
-
@d.get(:x__b.as(:name)).should == "SELECT x.b AS name FROM test LIMIT 1"
|
|
2651
|
+
@d.get(Sequel.expr(:x__b).as(:name)).should == "SELECT x.b AS name FROM test LIMIT 1"
|
|
2626
2652
|
end
|
|
2627
2653
|
|
|
2628
2654
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -2633,243 +2659,253 @@ describe "Dataset#get" do
|
|
|
2633
2659
|
specify "should raise an error if both a regular argument and block argument are used" do
|
|
2634
2660
|
proc{@d.get(:name){|o| o.x__b.as(:name)}}.should raise_error(Sequel::Error)
|
|
2635
2661
|
end
|
|
2662
|
+
|
|
2663
|
+
specify "should support false and nil values" do
|
|
2664
|
+
@d.get(false).should == "SELECT 'f' FROM test LIMIT 1"
|
|
2665
|
+
@d.get(nil).should == "SELECT NULL FROM test LIMIT 1"
|
|
2666
|
+
end
|
|
2636
2667
|
end
|
|
2637
2668
|
|
|
2638
2669
|
describe "Dataset#set_row_proc" do
|
|
2639
2670
|
before do
|
|
2640
|
-
@
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
(1..10).each {|i| block.call({:kind => i[0]})}
|
|
2644
|
-
end
|
|
2645
|
-
end
|
|
2646
|
-
@dataset = @c.new(nil).from(:items)
|
|
2671
|
+
@db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
|
|
2672
|
+
@dataset = @db[:items]
|
|
2673
|
+
@dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
|
|
2647
2674
|
end
|
|
2648
2675
|
|
|
2649
2676
|
specify "should cause dataset to pass all rows through the filter" do
|
|
2650
|
-
@dataset.row_proc = proc{|h| h[:der] = h[:kind] + 2; h}
|
|
2651
|
-
|
|
2652
2677
|
rows = @dataset.all
|
|
2653
|
-
rows.
|
|
2654
|
-
|
|
2655
|
-
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
|
2678
|
+
rows.map{|h| h[:der]}.should == [3, 4]
|
|
2679
|
+
@db.sqls.should == ['SELECT * FROM items']
|
|
2656
2680
|
end
|
|
2657
2681
|
|
|
2658
2682
|
specify "should be copied over when dataset is cloned" do
|
|
2659
|
-
@dataset.
|
|
2660
|
-
|
|
2661
|
-
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
|
2683
|
+
@dataset.filter(:a => 1).all.should == [{:a=>1, :der=>3}, {:a=>2, :der=>4}]
|
|
2662
2684
|
end
|
|
2663
2685
|
end
|
|
2664
2686
|
|
|
2665
2687
|
describe "Dataset#<<" do
|
|
2666
2688
|
before do
|
|
2667
|
-
@
|
|
2668
|
-
@d.meta_def(:insert) do |*args|
|
|
2669
|
-
1234567890
|
|
2670
|
-
end
|
|
2689
|
+
@db = Sequel.mock
|
|
2671
2690
|
end
|
|
2672
|
-
|
|
2691
|
+
|
|
2673
2692
|
specify "should call #insert" do
|
|
2674
|
-
|
|
2693
|
+
@db[:items] << {:name => 1}
|
|
2694
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)']
|
|
2695
|
+
end
|
|
2696
|
+
|
|
2697
|
+
specify "should be chainable" do
|
|
2698
|
+
@db[:items] << {:name => 1} << @db[:old_items].select(:name)
|
|
2699
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)', 'INSERT INTO items SELECT name FROM old_items']
|
|
2675
2700
|
end
|
|
2676
2701
|
end
|
|
2677
2702
|
|
|
2678
2703
|
describe "Dataset#columns" do
|
|
2679
2704
|
before do
|
|
2680
|
-
@dataset =
|
|
2681
|
-
@dataset.meta_def(:columns=) {|c| @columns = c}
|
|
2682
|
-
i = 'a'
|
|
2683
|
-
@dataset.meta_def(:each){@columns = select_sql + i; i = i.next}
|
|
2705
|
+
@dataset = Sequel.mock[:items]
|
|
2684
2706
|
end
|
|
2685
2707
|
|
|
2686
2708
|
specify "should return the value of @columns if @columns is not nil" do
|
|
2687
|
-
@dataset.columns
|
|
2688
|
-
@dataset.
|
|
2709
|
+
@dataset.columns(:a, :b, :c).columns.should == [:a, :b, :c]
|
|
2710
|
+
@dataset.db.sqls.should == []
|
|
2689
2711
|
end
|
|
2690
2712
|
|
|
2691
2713
|
specify "should attempt to get a single record and return @columns if @columns is nil" do
|
|
2692
|
-
@dataset.columns =
|
|
2693
|
-
@dataset.columns.should ==
|
|
2694
|
-
@dataset.
|
|
2695
|
-
|
|
2714
|
+
@dataset.db.columns = [:a]
|
|
2715
|
+
@dataset.columns.should == [:a]
|
|
2716
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2717
|
+
end
|
|
2718
|
+
|
|
2719
|
+
specify "should be cleared if you change the selected columns" do
|
|
2720
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2721
|
+
@dataset.columns.should == [:a]
|
|
2722
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2723
|
+
@dataset.columns.should == [:a]
|
|
2724
|
+
@dataset.db.sqls.should == []
|
|
2725
|
+
ds = @dataset.select{foo{}}
|
|
2726
|
+
ds.columns.should == [:b]
|
|
2727
|
+
@dataset.db.sqls.should == ['SELECT foo() FROM items LIMIT 1']
|
|
2728
|
+
end
|
|
2729
|
+
|
|
2730
|
+
specify "should be cleared if you change the FROM table" do
|
|
2731
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2732
|
+
@dataset.columns.should == [:a]
|
|
2733
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2734
|
+
ds = @dataset.from(:foo)
|
|
2735
|
+
ds.columns.should == [:b]
|
|
2736
|
+
@dataset.db.sqls.should == ['SELECT * FROM foo LIMIT 1']
|
|
2737
|
+
end
|
|
2738
|
+
|
|
2739
|
+
specify "should be cleared if you join a table to the dataset" do
|
|
2740
|
+
@dataset.db.columns = [[:a], [:a, :b]]
|
|
2741
|
+
@dataset.columns.should == [:a]
|
|
2742
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2743
|
+
ds = @dataset.cross_join(:foo)
|
|
2744
|
+
ds.columns.should == [:a, :b]
|
|
2745
|
+
@dataset.db.sqls.should == ['SELECT * FROM items CROSS JOIN foo LIMIT 1']
|
|
2746
|
+
end
|
|
2747
|
+
|
|
2748
|
+
specify "should be cleared if you set custom SQL for the dataset" do
|
|
2749
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2750
|
+
@dataset.columns.should == [:a]
|
|
2751
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2752
|
+
ds = @dataset.with_sql('SELECT b FROM foo')
|
|
2753
|
+
ds.columns.should == [:b]
|
|
2754
|
+
@dataset.db.sqls.should == ['SELECT b FROM foo']
|
|
2696
2755
|
end
|
|
2697
2756
|
|
|
2698
2757
|
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
|
2758
|
+
@dataset.db.columns = [:a]
|
|
2699
2759
|
@dataset.filter!(:b=>100).order!(:b).distinct!
|
|
2700
|
-
@dataset.columns
|
|
2701
|
-
@dataset.
|
|
2760
|
+
@dataset.columns.should == [:a]
|
|
2761
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2702
2762
|
end
|
|
2703
2763
|
end
|
|
2704
2764
|
|
|
2705
2765
|
describe "Dataset#columns!" do
|
|
2706
|
-
before do
|
|
2707
|
-
@dataset = DummyDataset.new(nil).from(:items)
|
|
2708
|
-
i = 'a'
|
|
2709
|
-
@dataset.meta_def(:each){@columns = select_sql + i; i = i.next}
|
|
2710
|
-
end
|
|
2711
|
-
|
|
2712
2766
|
specify "should always attempt to get a record and return @columns" do
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2767
|
+
ds = Sequel.mock(:columns=>[[:a, :b, :c], [:d, :e, :f]])[:items]
|
|
2768
|
+
ds.columns!.should == [:a, :b, :c]
|
|
2769
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2770
|
+
ds.columns!.should == [:d, :e, :f]
|
|
2771
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2717
2772
|
end
|
|
2718
2773
|
end
|
|
2719
2774
|
|
|
2720
2775
|
describe "Dataset#import" do
|
|
2721
2776
|
before do
|
|
2722
|
-
@
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
def execute(sql, opts={})
|
|
2726
|
-
@sqls ||= []
|
|
2727
|
-
@sqls << sql
|
|
2728
|
-
end
|
|
2729
|
-
alias execute_dui execute
|
|
2730
|
-
|
|
2731
|
-
def transaction(opts={})
|
|
2732
|
-
@sqls ||= []
|
|
2733
|
-
@sqls << 'BEGIN'
|
|
2734
|
-
yield
|
|
2735
|
-
@sqls << 'COMMIT'
|
|
2736
|
-
end
|
|
2737
|
-
end
|
|
2738
|
-
@db = @dbc.new
|
|
2739
|
-
|
|
2740
|
-
@ds = Sequel::Dataset.new(@db).from(:items)
|
|
2741
|
-
|
|
2742
|
-
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
|
2777
|
+
@db = Sequel.mock
|
|
2778
|
+
@ds = @db[:items]
|
|
2743
2779
|
end
|
|
2744
2780
|
|
|
2781
|
+
specify "should return nil without a query if no values" do
|
|
2782
|
+
@ds.import(['x', 'y'], []).should == nil
|
|
2783
|
+
@db.sqls.should == []
|
|
2784
|
+
end
|
|
2785
|
+
|
|
2745
2786
|
specify "should accept string keys as column names" do
|
|
2746
2787
|
@ds.import(['x', 'y'], [[1, 2], [3, 4]])
|
|
2747
|
-
@db.sqls.should == [
|
|
2748
|
-
'BEGIN',
|
|
2788
|
+
@db.sqls.should == ['BEGIN',
|
|
2749
2789
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2750
2790
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2751
|
-
'COMMIT'
|
|
2752
|
-
]
|
|
2791
|
+
'COMMIT']
|
|
2753
2792
|
end
|
|
2754
2793
|
|
|
2755
2794
|
specify "should accept a columns array and a values array" do
|
|
2756
2795
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
2757
|
-
@db.sqls.should == [
|
|
2758
|
-
'BEGIN',
|
|
2796
|
+
@db.sqls.should == ['BEGIN',
|
|
2759
2797
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2760
2798
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2761
|
-
'COMMIT'
|
|
2762
|
-
]
|
|
2799
|
+
'COMMIT']
|
|
2763
2800
|
end
|
|
2764
2801
|
|
|
2765
2802
|
specify "should accept a columns array and a dataset" do
|
|
2766
|
-
@ds2 =
|
|
2803
|
+
@ds2 = @ds.from(:cats).filter(:purr => true).select(:a, :b)
|
|
2767
2804
|
|
|
2768
2805
|
@ds.import([:x, :y], @ds2)
|
|
2769
|
-
@db.sqls.should == [
|
|
2770
|
-
'BEGIN',
|
|
2806
|
+
@db.sqls.should == ['BEGIN',
|
|
2771
2807
|
"INSERT INTO items (x, y) SELECT a, b FROM cats WHERE (purr IS TRUE)",
|
|
2772
|
-
'COMMIT'
|
|
2773
|
-
]
|
|
2808
|
+
'COMMIT']
|
|
2774
2809
|
end
|
|
2775
2810
|
|
|
2776
2811
|
specify "should accept a columns array and a values array with :commit_every option" do
|
|
2777
2812
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 3)
|
|
2778
|
-
@db.sqls.should == [
|
|
2779
|
-
'BEGIN',
|
|
2813
|
+
@db.sqls.should == ['BEGIN',
|
|
2780
2814
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2781
2815
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2782
2816
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2783
|
-
'COMMIT'
|
|
2784
|
-
]
|
|
2817
|
+
'COMMIT']
|
|
2785
2818
|
end
|
|
2786
|
-
specify "should accept a columns array and a values array with slice option" do
|
|
2819
|
+
specify "should accept a columns array and a values array with :slice option" do
|
|
2787
2820
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
|
2788
|
-
@db.sqls.should == [
|
|
2789
|
-
'BEGIN',
|
|
2821
|
+
@db.sqls.should == ['BEGIN',
|
|
2790
2822
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2791
2823
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2792
2824
|
'COMMIT',
|
|
2793
2825
|
'BEGIN',
|
|
2794
2826
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2795
|
-
'COMMIT'
|
|
2796
|
-
]
|
|
2827
|
+
'COMMIT']
|
|
2797
2828
|
end
|
|
2798
2829
|
end
|
|
2799
2830
|
|
|
2800
2831
|
describe "Dataset#multi_insert" do
|
|
2801
2832
|
before do
|
|
2802
|
-
@
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
def execute(sql, opts={})
|
|
2806
|
-
@sqls ||= []
|
|
2807
|
-
@sqls << sql
|
|
2808
|
-
end
|
|
2809
|
-
alias execute_dui execute
|
|
2810
|
-
|
|
2811
|
-
def transaction(opts={})
|
|
2812
|
-
@sqls ||= []
|
|
2813
|
-
@sqls << 'BEGIN'
|
|
2814
|
-
yield
|
|
2815
|
-
@sqls << 'COMMIT'
|
|
2816
|
-
end
|
|
2817
|
-
end
|
|
2818
|
-
@db = @dbc.new
|
|
2819
|
-
|
|
2820
|
-
@ds = Sequel::Dataset.new(@db).from(:items)
|
|
2821
|
-
|
|
2833
|
+
@db = Sequel.mock(:servers=>{:s1=>{}})
|
|
2834
|
+
@ds = @db[:items]
|
|
2822
2835
|
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
|
2823
2836
|
end
|
|
2824
2837
|
|
|
2838
|
+
specify "should return nil without a query if no values" do
|
|
2839
|
+
@ds.multi_insert([]).should == nil
|
|
2840
|
+
@db.sqls.should == []
|
|
2841
|
+
end
|
|
2842
|
+
|
|
2825
2843
|
specify "should issue multiple insert statements inside a transaction" do
|
|
2826
2844
|
@ds.multi_insert(@list)
|
|
2827
|
-
@db.sqls.should == [
|
|
2828
|
-
'
|
|
2845
|
+
@db.sqls.should == ['BEGIN',
|
|
2846
|
+
"INSERT INTO items (name) VALUES ('abc')",
|
|
2847
|
+
"INSERT INTO items (name) VALUES ('def')",
|
|
2848
|
+
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2849
|
+
'COMMIT']
|
|
2850
|
+
end
|
|
2851
|
+
|
|
2852
|
+
specify "should respect :server option" do
|
|
2853
|
+
@ds.multi_insert(@list, :server=>:s1)
|
|
2854
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2855
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2856
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2857
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2858
|
+
'COMMIT -- s1']
|
|
2859
|
+
end
|
|
2860
|
+
|
|
2861
|
+
specify "should respect existing :server option on dataset" do
|
|
2862
|
+
@ds.server(:s1).multi_insert(@list)
|
|
2863
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2864
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2865
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2866
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2867
|
+
'COMMIT -- s1']
|
|
2868
|
+
end
|
|
2869
|
+
|
|
2870
|
+
specify "should respect :return=>:primary_key option" do
|
|
2871
|
+
@db.autoid = 1
|
|
2872
|
+
@ds.multi_insert(@list, :return=>:primary_key).should == [1, 2, 3]
|
|
2873
|
+
@db.sqls.should == ['BEGIN',
|
|
2829
2874
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2830
2875
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2831
2876
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2832
|
-
'COMMIT'
|
|
2833
|
-
]
|
|
2877
|
+
'COMMIT']
|
|
2834
2878
|
end
|
|
2835
2879
|
|
|
2836
2880
|
specify "should handle different formats for tables" do
|
|
2837
2881
|
@ds = @ds.from(:sch__tab)
|
|
2838
2882
|
@ds.multi_insert(@list)
|
|
2839
|
-
@db.sqls.should == [
|
|
2840
|
-
'BEGIN',
|
|
2883
|
+
@db.sqls.should == ['BEGIN',
|
|
2841
2884
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2842
2885
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2843
2886
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2844
|
-
'COMMIT'
|
|
2845
|
-
]
|
|
2846
|
-
@db.sqls.clear
|
|
2887
|
+
'COMMIT']
|
|
2847
2888
|
|
|
2848
|
-
@ds = @ds.from(
|
|
2889
|
+
@ds = @ds.from(Sequel.qualify(:sch, :tab))
|
|
2849
2890
|
@ds.multi_insert(@list)
|
|
2850
|
-
@db.sqls.should == [
|
|
2851
|
-
'BEGIN',
|
|
2891
|
+
@db.sqls.should == ['BEGIN',
|
|
2852
2892
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2853
2893
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2854
2894
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2855
|
-
'COMMIT'
|
|
2856
|
-
|
|
2857
|
-
@
|
|
2858
|
-
@ds = @ds.from(:sch__tab.identifier)
|
|
2895
|
+
'COMMIT']
|
|
2896
|
+
|
|
2897
|
+
@ds = @ds.from(Sequel.identifier(:sch__tab))
|
|
2859
2898
|
@ds.multi_insert(@list)
|
|
2860
|
-
@db.sqls.should == [
|
|
2861
|
-
'BEGIN',
|
|
2899
|
+
@db.sqls.should == ['BEGIN',
|
|
2862
2900
|
"INSERT INTO sch__tab (name) VALUES ('abc')",
|
|
2863
2901
|
"INSERT INTO sch__tab (name) VALUES ('def')",
|
|
2864
2902
|
"INSERT INTO sch__tab (name) VALUES ('ghi')",
|
|
2865
|
-
'COMMIT'
|
|
2866
|
-
]
|
|
2903
|
+
'COMMIT']
|
|
2867
2904
|
end
|
|
2868
2905
|
|
|
2869
2906
|
specify "should accept the :commit_every option for committing every x records" do
|
|
2870
2907
|
@ds.multi_insert(@list, :commit_every => 1)
|
|
2871
|
-
@db.sqls.should == [
|
|
2872
|
-
'BEGIN',
|
|
2908
|
+
@db.sqls.should == ['BEGIN',
|
|
2873
2909
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2874
2910
|
'COMMIT',
|
|
2875
2911
|
'BEGIN',
|
|
@@ -2877,36 +2913,31 @@ describe "Dataset#multi_insert" do
|
|
|
2877
2913
|
'COMMIT',
|
|
2878
2914
|
'BEGIN',
|
|
2879
2915
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2880
|
-
'COMMIT'
|
|
2881
|
-
]
|
|
2916
|
+
'COMMIT']
|
|
2882
2917
|
end
|
|
2883
2918
|
|
|
2884
2919
|
specify "should accept the :slice option for committing every x records" do
|
|
2885
2920
|
@ds.multi_insert(@list, :slice => 2)
|
|
2886
|
-
@db.sqls.should == [
|
|
2887
|
-
'BEGIN',
|
|
2921
|
+
@db.sqls.should == ['BEGIN',
|
|
2888
2922
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2889
2923
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2890
2924
|
'COMMIT',
|
|
2891
2925
|
'BEGIN',
|
|
2892
2926
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2893
|
-
'COMMIT'
|
|
2894
|
-
]
|
|
2927
|
+
'COMMIT']
|
|
2895
2928
|
end
|
|
2896
2929
|
|
|
2897
2930
|
specify "should accept string keys as column names" do
|
|
2898
2931
|
@ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
|
|
2899
|
-
@db.sqls
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
'COMMIT'
|
|
2904
|
-
]
|
|
2932
|
+
sqls = @db.sqls
|
|
2933
|
+
["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls.slice!(1))
|
|
2934
|
+
["INSERT INTO items (x, y) VALUES (3, 4)", "INSERT INTO items (y, x) VALUES (4, 3)"].should include(sqls.slice!(1))
|
|
2935
|
+
sqls.should == ['BEGIN', 'COMMIT']
|
|
2905
2936
|
end
|
|
2906
2937
|
|
|
2907
2938
|
specify "should not do anything if no hashes are provided" do
|
|
2908
2939
|
@ds.multi_insert([])
|
|
2909
|
-
@db.sqls.should
|
|
2940
|
+
@db.sqls.should == []
|
|
2910
2941
|
end
|
|
2911
2942
|
end
|
|
2912
2943
|
|
|
@@ -2936,7 +2967,7 @@ describe "Dataset" do
|
|
|
2936
2967
|
end
|
|
2937
2968
|
|
|
2938
2969
|
specify "should support self-changing filter! with block" do
|
|
2939
|
-
@d.filter!{
|
|
2970
|
+
@d.filter!{y < 2}
|
|
2940
2971
|
@d.sql.should == "SELECT * FROM x WHERE (y < 2)"
|
|
2941
2972
|
end
|
|
2942
2973
|
|
|
@@ -2951,41 +2982,21 @@ describe "Dataset" do
|
|
|
2951
2982
|
end
|
|
2952
2983
|
|
|
2953
2984
|
specify "should support chaining of bang methods" do
|
|
2954
|
-
@d.order!(:y)
|
|
2955
|
-
@d.filter!(:y => 1)
|
|
2956
|
-
@d.sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
|
2985
|
+
@d.order!(:y).filter!(:y => 1).sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
|
2957
2986
|
end
|
|
2958
2987
|
end
|
|
2959
2988
|
|
|
2960
2989
|
describe "Dataset#to_csv" do
|
|
2961
2990
|
before do
|
|
2962
|
-
@
|
|
2963
|
-
attr_accessor :data
|
|
2964
|
-
attr_accessor :columns
|
|
2965
|
-
|
|
2966
|
-
def fetch_rows(sql, &block)
|
|
2967
|
-
@data.each(&block)
|
|
2968
|
-
end
|
|
2969
|
-
|
|
2970
|
-
# naked should return self here because to_csv wants a naked result set.
|
|
2971
|
-
def naked
|
|
2972
|
-
self
|
|
2973
|
-
end
|
|
2974
|
-
end
|
|
2975
|
-
|
|
2976
|
-
@ds = @c.new(nil).from(:items)
|
|
2977
|
-
@ds.columns = [:a, :b, :c]
|
|
2978
|
-
@ds.data = [ {:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}, {:a=>7, :b=>8, :c=>9} ]
|
|
2991
|
+
@ds = Sequel.mock(:fetch=>[{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}, {:a=>7, :b=>8, :c=>9}])[:items].columns(:a, :b, :c)
|
|
2979
2992
|
end
|
|
2980
2993
|
|
|
2981
2994
|
specify "should format a CSV representation of the records" do
|
|
2982
|
-
@ds.to_csv.should ==
|
|
2983
|
-
"a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2995
|
+
@ds.to_csv.should == "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2984
2996
|
end
|
|
2985
2997
|
|
|
2986
2998
|
specify "should exclude column titles if so specified" do
|
|
2987
|
-
@ds.to_csv(false).should ==
|
|
2988
|
-
"1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2999
|
+
@ds.to_csv(false).should == "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2989
3000
|
end
|
|
2990
3001
|
end
|
|
2991
3002
|
|
|
@@ -3007,7 +3018,7 @@ describe "Dataset#update_sql" do
|
|
|
3007
3018
|
end
|
|
3008
3019
|
|
|
3009
3020
|
specify "should accept array subscript references" do
|
|
3010
|
-
@ds.update_sql((:day
|
|
3021
|
+
@ds.update_sql((Sequel.subscript(:day, 1)) => 'd').should == "UPDATE items SET day[1] = 'd'"
|
|
3011
3022
|
end
|
|
3012
3023
|
end
|
|
3013
3024
|
|
|
@@ -3024,8 +3035,13 @@ describe "Dataset#insert_sql" do
|
|
|
3024
3035
|
@ds.insert_sql('c' => 'd').should == "INSERT INTO items (c) VALUES ('d')"
|
|
3025
3036
|
end
|
|
3026
3037
|
|
|
3038
|
+
specify "should quote string keys" do
|
|
3039
|
+
@ds.quote_identifiers = true
|
|
3040
|
+
@ds.insert_sql('c' => 'd').should == "INSERT INTO \"items\" (\"c\") VALUES ('d')"
|
|
3041
|
+
end
|
|
3042
|
+
|
|
3027
3043
|
specify "should accept array subscript references" do
|
|
3028
|
-
@ds.insert_sql((:day
|
|
3044
|
+
@ds.insert_sql((Sequel.subscript(:day, 1)) => 'd').should == "INSERT INTO items (day[1]) VALUES ('d')"
|
|
3029
3045
|
end
|
|
3030
3046
|
|
|
3031
3047
|
specify "should raise an Error if the dataset has no sources" do
|
|
@@ -3063,164 +3079,117 @@ describe "Dataset#insert_sql" do
|
|
|
3063
3079
|
end
|
|
3064
3080
|
|
|
3065
3081
|
specify "should accept a single LiteralString" do
|
|
3066
|
-
@ds.insert_sql('VALUES (1, 2, 3)'
|
|
3082
|
+
@ds.insert_sql(Sequel.lit('VALUES (1, 2, 3)')).should == "INSERT INTO items VALUES (1, 2, 3)"
|
|
3067
3083
|
end
|
|
3068
3084
|
|
|
3069
3085
|
specify "should accept an array of columns and an LiteralString" do
|
|
3070
|
-
@ds.insert_sql([:a, :b, :c], 'VALUES (1, 2, 3)'
|
|
3071
|
-
end
|
|
3072
|
-
|
|
3073
|
-
specify "should accept an object that responds to values and returns a hash by using that hash as the columns and values" do
|
|
3074
|
-
o = Object.new
|
|
3075
|
-
def o.values; {:c=>'d'}; end
|
|
3076
|
-
@ds.insert_sql(o).should == "INSERT INTO items (c) VALUES ('d')"
|
|
3077
|
-
end
|
|
3078
|
-
|
|
3079
|
-
specify "should accept an object that responds to values and returns something other than a hash by using the object itself as a single value" do
|
|
3080
|
-
o = Date.civil(2000, 1, 1)
|
|
3081
|
-
def o.values; self; end
|
|
3082
|
-
@ds.insert_sql(o).should == "INSERT INTO items VALUES ('2000-01-01')"
|
|
3086
|
+
@ds.insert_sql([:a, :b, :c], Sequel.lit('VALUES (1, 2, 3)')).should == "INSERT INTO items (a, b, c) VALUES (1, 2, 3)"
|
|
3083
3087
|
end
|
|
3084
3088
|
end
|
|
3085
3089
|
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
true
|
|
3090
|
+
describe "Dataset#inspect" do
|
|
3091
|
+
before do
|
|
3092
|
+
class ::InspectDataset < Sequel::Dataset; end
|
|
3090
3093
|
end
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
class DummyMummyDatabase < Sequel::Database
|
|
3094
|
-
attr_reader :sqls
|
|
3095
|
-
|
|
3096
|
-
def execute(sql)
|
|
3097
|
-
@sqls ||= []
|
|
3098
|
-
@sqls << sql
|
|
3094
|
+
after do
|
|
3095
|
+
Object.send(:remove_const, :InspectDataset) if defined?(::InspectDataset)
|
|
3099
3096
|
end
|
|
3100
|
-
|
|
3101
|
-
def transaction; yield; end
|
|
3102
3097
|
|
|
3103
|
-
|
|
3104
|
-
|
|
3098
|
+
specify "should include the class name and the corresponding SQL statement" do
|
|
3099
|
+
Sequel::Dataset.new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
3100
|
+
InspectDataset.new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3105
3101
|
end
|
|
3106
|
-
end
|
|
3107
3102
|
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
end
|
|
3112
|
-
|
|
3113
|
-
specify "should include the class name and the corresponding SQL statement" do
|
|
3114
|
-
@ds.inspect.should == '#<%s: %s>' % [@ds.class.to_s, @ds.sql.inspect]
|
|
3103
|
+
specify "should skip anonymous classes" do
|
|
3104
|
+
Class.new(Class.new(Sequel::Dataset)).new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
3105
|
+
Class.new(InspectDataset).new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3115
3106
|
end
|
|
3116
3107
|
end
|
|
3117
3108
|
|
|
3118
3109
|
describe "Dataset#all" do
|
|
3119
3110
|
before do
|
|
3120
|
-
@
|
|
3121
|
-
def fetch_rows(sql, &block)
|
|
3122
|
-
block.call({:x => 1, :y => 2})
|
|
3123
|
-
block.call({:x => 3, :y => 4})
|
|
3124
|
-
block.call(sql)
|
|
3125
|
-
end
|
|
3126
|
-
end
|
|
3127
|
-
@dataset = @c.new(nil).from(:items)
|
|
3111
|
+
@dataset = Sequel.mock(:fetch=>[{:x => 1, :y => 2}, {:x => 3, :y => 4}])[:items]
|
|
3128
3112
|
end
|
|
3129
3113
|
|
|
3130
3114
|
specify "should return an array with all records" do
|
|
3131
|
-
@dataset.all.should == [
|
|
3132
|
-
|
|
3133
|
-
{:x => 3, :y => 4},
|
|
3134
|
-
"SELECT * FROM items"
|
|
3135
|
-
]
|
|
3115
|
+
@dataset.all.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3116
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3136
3117
|
end
|
|
3137
3118
|
|
|
3138
3119
|
specify "should iterate over the array if a block is given" do
|
|
3139
3120
|
a = []
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
end
|
|
3144
|
-
|
|
3145
|
-
a.should == [1, 3, "SELECT * FROM items"]
|
|
3121
|
+
@dataset.all{|r| a << r.values_at(:x, :y)}.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3122
|
+
a.should == [[1, 2], [3, 4]]
|
|
3123
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3146
3124
|
end
|
|
3147
3125
|
end
|
|
3148
3126
|
|
|
3149
3127
|
describe "Dataset#grep" do
|
|
3150
3128
|
before do
|
|
3151
|
-
@ds = Sequel
|
|
3129
|
+
@ds = Sequel.mock[:posts]
|
|
3152
3130
|
end
|
|
3153
3131
|
|
|
3154
3132
|
specify "should format a SQL filter correctly" do
|
|
3155
|
-
@ds.grep(:title, 'ruby').sql.should ==
|
|
3156
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3133
|
+
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3157
3134
|
end
|
|
3158
3135
|
|
|
3159
3136
|
specify "should support multiple columns" do
|
|
3160
|
-
@ds.grep([:title, :body], 'ruby').sql.should ==
|
|
3161
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
|
3137
|
+
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
|
3162
3138
|
end
|
|
3163
3139
|
|
|
3164
3140
|
specify "should support multiple search terms" do
|
|
3165
|
-
@ds.grep(:title, ['abc', 'def']).sql.should ==
|
|
3166
|
-
"SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
|
3141
|
+
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
|
3167
3142
|
end
|
|
3168
3143
|
|
|
3169
3144
|
specify "should support multiple columns and search terms" do
|
|
3170
|
-
@ds.grep([:title, :body], ['abc', 'def']).sql.should ==
|
|
3171
|
-
"SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
|
|
3145
|
+
@ds.grep([:title, :body], ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
|
|
3172
3146
|
end
|
|
3173
3147
|
|
|
3174
3148
|
specify "should support the :all_patterns option" do
|
|
3175
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true).sql.should ==
|
|
3176
|
-
"SELECT * FROM posts WHERE (((title LIKE 'abc') OR (body LIKE 'abc')) AND ((title LIKE 'def') OR (body LIKE 'def')))"
|
|
3149
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (body LIKE 'abc')) AND ((title LIKE 'def') OR (body LIKE 'def')))"
|
|
3177
3150
|
end
|
|
3178
3151
|
|
|
3179
3152
|
specify "should support the :all_columns option" do
|
|
3180
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true).sql.should ==
|
|
3181
|
-
"SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')) AND ((body LIKE 'abc') OR (body LIKE 'def')))"
|
|
3153
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')) AND ((body LIKE 'abc') OR (body LIKE 'def')))"
|
|
3182
3154
|
end
|
|
3183
3155
|
|
|
3184
3156
|
specify "should support the :case_insensitive option" do
|
|
3185
|
-
@ds.grep([:title, :body], ['abc', 'def'], :case_insensitive=>true).sql.should ==
|
|
3186
|
-
"SELECT * FROM posts WHERE ((title ILIKE 'abc') OR (title ILIKE 'def') OR (body ILIKE 'abc') OR (body ILIKE 'def'))"
|
|
3157
|
+
@ds.grep([:title, :body], ['abc', 'def'], :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((title ILIKE 'abc') OR (title ILIKE 'def') OR (body ILIKE 'abc') OR (body ILIKE 'def'))"
|
|
3187
3158
|
end
|
|
3188
3159
|
|
|
3189
3160
|
specify "should support the :all_patterns and :all_columns options together" do
|
|
3190
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true).sql.should ==
|
|
3191
|
-
"SELECT * FROM posts WHERE ((title LIKE 'abc') AND (body LIKE 'abc') AND (title LIKE 'def') AND (body LIKE 'def'))"
|
|
3161
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') AND (body LIKE 'abc') AND (title LIKE 'def') AND (body LIKE 'def'))"
|
|
3192
3162
|
end
|
|
3193
3163
|
|
|
3194
3164
|
specify "should support the :all_patterns and :case_insensitive options together" do
|
|
3195
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :case_insensitive=>true).sql.should ==
|
|
3196
|
-
"SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (body ILIKE 'abc')) AND ((title ILIKE 'def') OR (body ILIKE 'def')))"
|
|
3165
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (body ILIKE 'abc')) AND ((title ILIKE 'def') OR (body ILIKE 'def')))"
|
|
3197
3166
|
end
|
|
3198
3167
|
|
|
3199
3168
|
specify "should support the :all_columns and :case_insensitive options together" do
|
|
3200
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true, :case_insensitive=>true).sql.should ==
|
|
3201
|
-
"SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (title ILIKE 'def')) AND ((body ILIKE 'abc') OR (body ILIKE 'def')))"
|
|
3169
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((title ILIKE 'abc') OR (title ILIKE 'def')) AND ((body ILIKE 'abc') OR (body ILIKE 'def')))"
|
|
3202
3170
|
end
|
|
3203
3171
|
|
|
3204
3172
|
specify "should support the :all_patterns, :all_columns, and :case_insensitive options together" do
|
|
3205
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true, :case_insensitive=>true).sql.should ==
|
|
3206
|
-
"SELECT * FROM posts WHERE ((title ILIKE 'abc') AND (body ILIKE 'abc') AND (title ILIKE 'def') AND (body ILIKE 'def'))"
|
|
3173
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((title ILIKE 'abc') AND (body ILIKE 'abc') AND (title ILIKE 'def') AND (body ILIKE 'def'))"
|
|
3207
3174
|
end
|
|
3208
3175
|
|
|
3209
|
-
specify "should support regexps
|
|
3210
|
-
@ds.grep(:title, /ruby/).sql.should
|
|
3211
|
-
|
|
3176
|
+
specify "should not support regexps if the database doesn't supports it" do
|
|
3177
|
+
proc{@ds.grep(:title, /ruby/).sql}.should raise_error(Sequel::InvalidOperation)
|
|
3178
|
+
proc{@ds.grep(:title, [/^ruby/, 'ruby']).sql}.should raise_error(Sequel::InvalidOperation)
|
|
3179
|
+
end
|
|
3212
3180
|
|
|
3213
|
-
|
|
3214
|
-
|
|
3181
|
+
specify "should support regexps if the database supports it" do
|
|
3182
|
+
def @ds.supports_regexp?; true end
|
|
3183
|
+
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
|
3184
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
|
3215
3185
|
end
|
|
3216
3186
|
|
|
3217
3187
|
specify "should support searching against other columns" do
|
|
3218
|
-
@ds.grep(:title, :body).sql.should ==
|
|
3219
|
-
"SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3188
|
+
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3220
3189
|
end
|
|
3221
3190
|
end
|
|
3222
3191
|
|
|
3223
|
-
describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #execute" do
|
|
3192
|
+
describe "Dataset default #fetch_rows, #insert, #update, #delete, #with_sql_delete, #truncate, #execute" do
|
|
3224
3193
|
before do
|
|
3225
3194
|
@db = Sequel::Database.new
|
|
3226
3195
|
@ds = @db[:items]
|
|
@@ -3237,6 +3206,14 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3237
3206
|
@ds.delete
|
|
3238
3207
|
end
|
|
3239
3208
|
|
|
3209
|
+
specify "#with_sql_delete should execute delete SQL" do
|
|
3210
|
+
sql = 'DELETE FROM foo'
|
|
3211
|
+
@db.should_receive(:execute).once.with(sql, :server=>:default)
|
|
3212
|
+
@ds.with_sql_delete(sql)
|
|
3213
|
+
@db.should_receive(:execute_dui).once.with(sql, :server=>:default)
|
|
3214
|
+
@ds.with_sql_delete(sql)
|
|
3215
|
+
end
|
|
3216
|
+
|
|
3240
3217
|
specify "#insert should execute insert SQL" do
|
|
3241
3218
|
@db.should_receive(:execute).once.with('INSERT INTO items DEFAULT VALUES', :server=>:default)
|
|
3242
3219
|
@ds.insert([])
|
|
@@ -3260,6 +3237,7 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3260
3237
|
|
|
3261
3238
|
specify "#truncate should raise an InvalidOperation exception if the dataset is filtered" do
|
|
3262
3239
|
proc{@ds.filter(:a=>1).truncate}.should raise_error(Sequel::InvalidOperation)
|
|
3240
|
+
proc{@ds.having(:a=>1).truncate}.should raise_error(Sequel::InvalidOperation)
|
|
3263
3241
|
end
|
|
3264
3242
|
|
|
3265
3243
|
specify "#execute should execute the SQL on the database" do
|
|
@@ -3270,58 +3248,80 @@ end
|
|
|
3270
3248
|
|
|
3271
3249
|
describe "Dataset prepared statements and bound variables " do
|
|
3272
3250
|
before do
|
|
3273
|
-
@db = Sequel
|
|
3274
|
-
@db.meta_def(:sqls){@sqls||=[]}
|
|
3275
|
-
def @db.execute(sql, opts={})
|
|
3276
|
-
sqls << sql
|
|
3277
|
-
end
|
|
3278
|
-
def @db.dataset
|
|
3279
|
-
ds = super()
|
|
3280
|
-
def ds.fetch_rows(sql, &block)
|
|
3281
|
-
execute(sql)
|
|
3282
|
-
end
|
|
3283
|
-
ds
|
|
3284
|
-
end
|
|
3251
|
+
@db = Sequel.mock
|
|
3285
3252
|
@ds = @db[:items]
|
|
3253
|
+
@ds.meta_def(:insert_sql){|*v| "#{super(*v)}#{' RETURNING *' if opts.has_key?(:returning)}" }
|
|
3286
3254
|
end
|
|
3287
3255
|
|
|
3288
3256
|
specify "#call should take a type and bind hash and interpolate it" do
|
|
3257
|
+
@ds.filter(:num=>:$n).call(:each, :n=>1)
|
|
3289
3258
|
@ds.filter(:num=>:$n).call(:select, :n=>1)
|
|
3259
|
+
@ds.filter(:num=>:$n).call([:map, :a], :n=>1)
|
|
3260
|
+
@ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
|
|
3261
|
+
@ds.filter(:num=>:$n).call([:to_hash_groups, :a, :b], :n=>1)
|
|
3290
3262
|
@ds.filter(:num=>:$n).call(:first, :n=>1)
|
|
3291
3263
|
@ds.filter(:num=>:$n).call(:delete, :n=>1)
|
|
3292
3264
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
|
3293
3265
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
|
3294
|
-
@
|
|
3266
|
+
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
|
3267
|
+
@db.sqls.should == [
|
|
3268
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3269
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3270
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3271
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3272
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3295
3273
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3296
3274
|
'DELETE FROM items WHERE (num = 1)',
|
|
3297
3275
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3298
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3276
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3277
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3299
3278
|
end
|
|
3300
3279
|
|
|
3301
3280
|
specify "#prepare should take a type and name and store it in the database for later use with call" do
|
|
3302
3281
|
pss = []
|
|
3282
|
+
pss << @ds.filter(:num=>:$n).prepare(:each, :en)
|
|
3303
3283
|
pss << @ds.filter(:num=>:$n).prepare(:select, :sn)
|
|
3284
|
+
pss << @ds.filter(:num=>:$n).prepare([:map, :a], :sm)
|
|
3285
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
|
|
3286
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash_groups, :a, :b], :shg)
|
|
3304
3287
|
pss << @ds.filter(:num=>:$n).prepare(:first, :fn)
|
|
3305
3288
|
pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
|
|
3306
3289
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
|
3307
3290
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
|
3308
|
-
@
|
|
3309
|
-
[:
|
|
3291
|
+
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
|
3292
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :en, :fn, :in, :ins, :sh, :shg, :sm, :sn, :un]
|
|
3293
|
+
[:en, :sn, :sm, :sh, :shg, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3294
|
+
@db.call(:en, :n=>1){}
|
|
3310
3295
|
@db.call(:sn, :n=>1)
|
|
3296
|
+
@db.call(:sm, :n=>1)
|
|
3297
|
+
@db.call(:sh, :n=>1)
|
|
3298
|
+
@db.call(:shg, :n=>1)
|
|
3311
3299
|
@db.call(:fn, :n=>1)
|
|
3312
3300
|
@db.call(:dn, :n=>1)
|
|
3313
3301
|
@db.call(:un, :n=>1, :n2=>2)
|
|
3314
3302
|
@db.call(:in, :n=>1)
|
|
3315
|
-
@db.
|
|
3303
|
+
@db.call(:ins, :n=>1)
|
|
3304
|
+
@db.sqls.should == [
|
|
3305
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3306
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3307
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3308
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3309
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3316
3310
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3317
3311
|
'DELETE FROM items WHERE (num = 1)',
|
|
3318
3312
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3319
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3313
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3314
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3320
3315
|
end
|
|
3321
3316
|
|
|
3317
|
+
specify "#call should default to using :all if an invalid type is given" do
|
|
3318
|
+
@ds.filter(:num=>:$n).call(:select_all, :n=>1)
|
|
3319
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3320
|
+
end
|
|
3321
|
+
|
|
3322
3322
|
specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
|
|
3323
3323
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
|
3324
|
-
'<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3324
|
+
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3325
3325
|
end
|
|
3326
3326
|
|
|
3327
3327
|
specify "should handle literal strings" do
|
|
@@ -3329,6 +3329,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3329
3329
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3330
3330
|
end
|
|
3331
3331
|
|
|
3332
|
+
specify "should handle columns on prepared statements correctly" do
|
|
3333
|
+
@db.columns = [:num]
|
|
3334
|
+
@ds.meta_def(:select_where_sql){|sql| super(sql); sql << " OR #{columns.first} = 1" if opts[:where]}
|
|
3335
|
+
@ds.filter(:num=>:$n).prepare(:select, :sn).sql.should == 'SELECT * FROM items WHERE (num = $n) OR num = 1'
|
|
3336
|
+
@db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
3337
|
+
end
|
|
3338
|
+
|
|
3332
3339
|
specify "should handle datasets using static sql and placeholders" do
|
|
3333
3340
|
@db["SELECT * FROM items WHERE (num = ?)", :$n].call(:select, :n=>1)
|
|
3334
3341
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
@@ -3357,23 +3364,16 @@ end
|
|
|
3357
3364
|
|
|
3358
3365
|
describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3359
3366
|
before do
|
|
3360
|
-
@db = Sequel
|
|
3361
|
-
@db.meta_def(:sqls){@sqls||=[]}
|
|
3362
|
-
def @db.execute(sql, opts={})
|
|
3363
|
-
sqls << [sql, *opts[:arguments]]
|
|
3364
|
-
end
|
|
3367
|
+
@db = Sequel.mock
|
|
3365
3368
|
@ds = @db[:items].filter(:num=>:$n)
|
|
3366
|
-
def @ds.fetch_rows(sql, &block)
|
|
3367
|
-
execute(sql)
|
|
3368
|
-
end
|
|
3369
3369
|
def @ds.execute(sql, opts={}, &block)
|
|
3370
|
-
|
|
3370
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3371
3371
|
end
|
|
3372
|
-
def @ds.execute_dui(
|
|
3373
|
-
|
|
3372
|
+
def @ds.execute_dui(sql, opts={}, &block)
|
|
3373
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3374
3374
|
end
|
|
3375
|
-
def @ds.execute_insert(
|
|
3376
|
-
|
|
3375
|
+
def @ds.execute_insert(sql, opts={}, &block)
|
|
3376
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3377
3377
|
end
|
|
3378
3378
|
@ps = []
|
|
3379
3379
|
@ps << @ds.prepare(:select, :s)
|
|
@@ -3386,64 +3386,51 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
|
3386
3386
|
end
|
|
3387
3387
|
|
|
3388
3388
|
specify "#inspect should show the actual SQL submitted to the database" do
|
|
3389
|
-
@ps.first.inspect.should == '<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
|
3389
|
+
@ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
|
3390
3390
|
end
|
|
3391
3391
|
|
|
3392
|
-
specify "should
|
|
3392
|
+
specify "should submit the SQL to the database with placeholders and bind variables" do
|
|
3393
3393
|
@ps.each{|p| p.prepared_sql; p.call(:n=>1)}
|
|
3394
|
-
@db.sqls.should == [
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3394
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3395
|
+
"SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3396
|
+
"SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
|
|
3397
|
+
"DELETE FROM items WHERE (num = ?) -- args: [1]",
|
|
3398
|
+
"INSERT INTO items (num) VALUES (?) -- args: [1]",
|
|
3399
|
+
"UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
|
|
3400
|
+
end
|
|
3401
|
+
|
|
3402
|
+
specify "should handle unrecognized statement types as :all" do
|
|
3403
|
+
ps = @ds.prepare(:select_all, :s)
|
|
3404
|
+
ps.extend(Sequel::Dataset::UnnumberedArgumentMapper)
|
|
3405
|
+
ps.prepared_sql
|
|
3406
|
+
ps.call(:n=>1)
|
|
3407
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]"]
|
|
3401
3408
|
end
|
|
3402
3409
|
end
|
|
3403
3410
|
|
|
3404
3411
|
describe "Sequel::Dataset#server" do
|
|
3405
3412
|
specify "should set the server to use for the dataset" do
|
|
3406
|
-
@db = Sequel
|
|
3413
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}, :d=>{}, :u=>{}})
|
|
3407
3414
|
@ds = @db[:items].server(:s)
|
|
3408
|
-
sqls = []
|
|
3409
|
-
@db.meta_def(:execute) do |sql, opts|
|
|
3410
|
-
sqls << [sql, opts[:server]]
|
|
3411
|
-
end
|
|
3412
|
-
def @ds.fetch_rows(sql, &block)
|
|
3413
|
-
execute(sql)
|
|
3414
|
-
end
|
|
3415
3415
|
@ds.all
|
|
3416
3416
|
@ds.server(:i).insert(:a=>1)
|
|
3417
3417
|
@ds.server(:d).delete
|
|
3418
|
-
@ds.server(:u).update(:a
|
|
3419
|
-
sqls.should == [
|
|
3420
|
-
['INSERT INTO items (a) VALUES (1)', :i],
|
|
3421
|
-
['DELETE FROM items', :d],
|
|
3422
|
-
['UPDATE items SET a = (a + 1)', :u]]
|
|
3418
|
+
@ds.server(:u).update(:a=>Sequel.expr(:a)+1)
|
|
3419
|
+
@db.sqls.should == ['SELECT * FROM items -- s', 'INSERT INTO items (a) VALUES (1) -- i', 'DELETE FROM items -- d', 'UPDATE items SET a = (a + 1) -- u']
|
|
3423
3420
|
end
|
|
3424
3421
|
end
|
|
3425
3422
|
|
|
3426
3423
|
describe "Sequel::Dataset#each_server" do
|
|
3427
|
-
before do
|
|
3428
|
-
@db = Sequel::Database.new(:servers=>{:s=>{}, :i=>{}})
|
|
3429
|
-
@ds = @db[:items]
|
|
3430
|
-
sqls = @sqls = []
|
|
3431
|
-
@db.meta_def(:execute) do |sql, opts|
|
|
3432
|
-
sqls << [sql, opts[:server]]
|
|
3433
|
-
end
|
|
3434
|
-
def @ds.fetch_rows(sql, &block)
|
|
3435
|
-
execute(sql)
|
|
3436
|
-
end
|
|
3437
|
-
end
|
|
3438
|
-
|
|
3439
3424
|
specify "should yield a dataset for each server" do
|
|
3425
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}})
|
|
3426
|
+
@ds = @db[:items]
|
|
3440
3427
|
@ds.each_server do |ds|
|
|
3441
3428
|
ds.should be_a_kind_of(Sequel::Dataset)
|
|
3442
3429
|
ds.should_not == @ds
|
|
3443
3430
|
ds.sql.should == @ds.sql
|
|
3444
3431
|
ds.all
|
|
3445
3432
|
end
|
|
3446
|
-
@sqls.
|
|
3433
|
+
@db.sqls.sort.should == ['SELECT * FROM items', 'SELECT * FROM items -- i', 'SELECT * FROM items -- s']
|
|
3447
3434
|
end
|
|
3448
3435
|
end
|
|
3449
3436
|
|
|
@@ -3493,23 +3480,23 @@ end
|
|
|
3493
3480
|
|
|
3494
3481
|
describe "Sequel::Dataset#qualify" do
|
|
3495
3482
|
specify "should qualify to the given table" do
|
|
3496
|
-
|
|
3483
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3497
3484
|
end
|
|
3498
3485
|
|
|
3499
3486
|
specify "should qualify to the first source if no table if given" do
|
|
3500
|
-
|
|
3487
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
|
|
3501
3488
|
end
|
|
3502
3489
|
end
|
|
3503
3490
|
|
|
3504
3491
|
describe "Sequel::Dataset#qualify_to" do
|
|
3505
3492
|
specify "should qualify to the given table" do
|
|
3506
|
-
|
|
3493
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3507
3494
|
end
|
|
3508
3495
|
end
|
|
3509
3496
|
|
|
3510
3497
|
describe "Sequel::Dataset#qualify_to_first_source" do
|
|
3511
3498
|
before do
|
|
3512
|
-
@ds =
|
|
3499
|
+
@ds = Sequel::Database.new[:t]
|
|
3513
3500
|
end
|
|
3514
3501
|
|
|
3515
3502
|
specify "should qualify_to the first source" do
|
|
@@ -3519,13 +3506,11 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3519
3506
|
end
|
|
3520
3507
|
|
|
3521
3508
|
specify "should handle the select, order, where, having, and group options/clauses" do
|
|
3522
|
-
@ds.select(:a).filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should ==
|
|
3523
|
-
'SELECT t.a FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
|
|
3509
|
+
@ds.select(:a).filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should == 'SELECT t.a FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
|
|
3524
3510
|
end
|
|
3525
3511
|
|
|
3526
3512
|
specify "should handle the select using a table.* if all columns are currently selected" do
|
|
3527
|
-
@ds.filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should ==
|
|
3528
|
-
'SELECT t.* FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
|
|
3513
|
+
@ds.filter(:a=>1).order(:a).group(:a).having(:a).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.a = 1) GROUP BY t.a HAVING t.a ORDER BY t.a'
|
|
3529
3514
|
end
|
|
3530
3515
|
|
|
3531
3516
|
specify "should handle hashes in select option" do
|
|
@@ -3541,7 +3526,7 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3541
3526
|
end
|
|
3542
3527
|
|
|
3543
3528
|
specify "should handle hashes" do
|
|
3544
|
-
@ds.select({:b=>{:c=>1}}
|
|
3529
|
+
@ds.select(Sequel.case({:b=>{:c=>1}}, false)).qualify_to_first_source.sql.should == "SELECT (CASE WHEN t.b THEN (t.c = 1) ELSE 'f' END) FROM t"
|
|
3545
3530
|
end
|
|
3546
3531
|
|
|
3547
3532
|
specify "should handle SQL::Identifiers" do
|
|
@@ -3549,15 +3534,15 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3549
3534
|
end
|
|
3550
3535
|
|
|
3551
3536
|
specify "should handle SQL::OrderedExpressions" do
|
|
3552
|
-
@ds.order(:a
|
|
3537
|
+
@ds.order(Sequel.desc(:a), Sequel.asc(:b)).qualify_to_first_source.sql.should == 'SELECT t.* FROM t ORDER BY t.a DESC, t.b ASC'
|
|
3553
3538
|
end
|
|
3554
3539
|
|
|
3555
3540
|
specify "should handle SQL::AliasedExpressions" do
|
|
3556
|
-
@ds.select(:a.as(:b)).qualify_to_first_source.sql.should == 'SELECT t.a AS b FROM t'
|
|
3541
|
+
@ds.select(Sequel.expr(:a).as(:b)).qualify_to_first_source.sql.should == 'SELECT t.a AS b FROM t'
|
|
3557
3542
|
end
|
|
3558
3543
|
|
|
3559
3544
|
specify "should handle SQL::CaseExpressions" do
|
|
3560
|
-
@ds.filter{{a=>b}
|
|
3545
|
+
@ds.filter{Sequel.case({a=>b}, c, d)}.qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (CASE t.d WHEN t.a THEN t.b ELSE t.c END)'
|
|
3561
3546
|
end
|
|
3562
3547
|
|
|
3563
3548
|
specify "should handle SQL:Casts" do
|
|
@@ -3573,7 +3558,7 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3573
3558
|
end
|
|
3574
3559
|
|
|
3575
3560
|
specify "should handle SQL::ValueLists" do
|
|
3576
|
-
@ds.filter(:a=>[:b, :c]
|
|
3561
|
+
@ds.filter(:a=>Sequel.value_list([:b, :c])).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.a IN (t.b, t.c))'
|
|
3577
3562
|
end
|
|
3578
3563
|
|
|
3579
3564
|
specify "should handle SQL::Subscripts" do
|
|
@@ -3588,20 +3573,97 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3588
3573
|
@ds.filter(':a > :b', :a=>:c, :b=>1).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.c > 1)'
|
|
3589
3574
|
end
|
|
3590
3575
|
|
|
3576
|
+
specify "should handle SQL::Wrappers" do
|
|
3577
|
+
@ds.filter(Sequel::SQL::Wrapper.new(:a)).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE t.a'
|
|
3578
|
+
end
|
|
3579
|
+
|
|
3591
3580
|
specify "should handle SQL::WindowFunctions" do
|
|
3592
3581
|
@ds.meta_def(:supports_window_functions?){true}
|
|
3593
3582
|
@ds.select{sum(:over, :args=>:a, :partition=>:b, :order=>:c){}}.qualify_to_first_source.sql.should == 'SELECT sum(t.a) OVER (PARTITION BY t.b ORDER BY t.c) FROM t'
|
|
3594
3583
|
end
|
|
3595
3584
|
|
|
3596
3585
|
specify "should handle all other objects by returning them unchanged" do
|
|
3597
|
-
@ds.select("a").filter{a(3)}.filter('blah').order('true'
|
|
3598
|
-
|
|
3586
|
+
@ds.select("a").filter{a(3)}.filter('blah').order(Sequel.lit('true')).group(Sequel.lit('a > ?', 1)).having(false).qualify_to_first_source.sql.should == "SELECT 'a' FROM t WHERE (a(3) AND (blah)) GROUP BY a > 1 HAVING 'f' ORDER BY true"
|
|
3587
|
+
end
|
|
3588
|
+
end
|
|
3589
|
+
|
|
3590
|
+
describe "Sequel::Dataset#unbind" do
|
|
3591
|
+
before do
|
|
3592
|
+
@ds = Sequel::Database.new[:t]
|
|
3593
|
+
@u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
|
|
3594
|
+
end
|
|
3595
|
+
|
|
3596
|
+
specify "should unbind values assigned to equality and inequality statements" do
|
|
3597
|
+
@ds.filter(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo = $foo)"
|
|
3598
|
+
@ds.exclude(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo != $foo)"
|
|
3599
|
+
@ds.filter{foo > 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo > $foo)"
|
|
3600
|
+
@ds.filter{foo >= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo >= $foo)"
|
|
3601
|
+
@ds.filter{foo < 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo < $foo)"
|
|
3602
|
+
@ds.filter{foo <= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo <= $foo)"
|
|
3603
|
+
end
|
|
3604
|
+
|
|
3605
|
+
specify "should return variables that could be used bound to recreate the previous query" do
|
|
3606
|
+
@ds.filter(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3607
|
+
@ds.exclude(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3608
|
+
end
|
|
3609
|
+
|
|
3610
|
+
specify "should handle numerics, strings, dates, times, and datetimes" do
|
|
3611
|
+
@u[@ds.filter(:foo=>1)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1}]
|
|
3612
|
+
@u[@ds.filter(:foo=>1.0)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1.0}]
|
|
3613
|
+
@u[@ds.filter(:foo=>BigDecimal.new('1.0'))].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>BigDecimal.new('1.0')}]
|
|
3614
|
+
@u[@ds.filter(:foo=>'a')].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>'a'}]
|
|
3615
|
+
@u[@ds.filter(:foo=>Date.today)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>Date.today}]
|
|
3616
|
+
t = Time.now
|
|
3617
|
+
@u[@ds.filter(:foo=>t)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>t}]
|
|
3618
|
+
dt = DateTime.now
|
|
3619
|
+
@u[@ds.filter(:foo=>dt)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>dt}]
|
|
3620
|
+
end
|
|
3621
|
+
|
|
3622
|
+
specify "should not unbind literal strings" do
|
|
3623
|
+
@u[@ds.filter(:foo=>Sequel.lit('a'))].should == ["SELECT * FROM t WHERE (foo = a)", {}]
|
|
3624
|
+
end
|
|
3625
|
+
|
|
3626
|
+
specify "should not unbind Identifiers, QualifiedIdentifiers, or Symbols used as booleans" do
|
|
3627
|
+
@u[@ds.filter(:foo).filter{bar}.filter{foo__bar}].should == ["SELECT * FROM t WHERE (foo AND bar AND foo.bar)", {}]
|
|
3628
|
+
end
|
|
3629
|
+
|
|
3630
|
+
specify "should not unbind for values it doesn't understand" do
|
|
3631
|
+
@u[@ds.filter(:foo=>Class.new{def sql_literal(ds) 'bar' end}.new)].should == ["SELECT * FROM t WHERE (foo = bar)", {}]
|
|
3632
|
+
end
|
|
3633
|
+
|
|
3634
|
+
specify "should handle QualifiedIdentifiers" do
|
|
3635
|
+
@u[@ds.filter{foo__bar > 1}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3636
|
+
end
|
|
3637
|
+
|
|
3638
|
+
specify "should handle wrapped objects" do
|
|
3639
|
+
@u[@ds.filter{Sequel::SQL::Wrapper.new(foo__bar) > Sequel::SQL::Wrapper.new(1)}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3640
|
+
end
|
|
3641
|
+
|
|
3642
|
+
specify "should handle deep nesting" do
|
|
3643
|
+
@u[@ds.filter{foo > 1}.and{bar < 2}.or(:baz=>3).and(Sequel.case({~Sequel.expr(:x=>4)=>true}, false))].should == ["SELECT * FROM t WHERE ((((foo > $foo) AND (bar < $bar)) OR (baz = $baz)) AND (CASE WHEN (x != $x) THEN 't' ELSE 'f' END))", {:foo=>1, :bar=>2, :baz=>3, :x=>4}]
|
|
3644
|
+
end
|
|
3645
|
+
|
|
3646
|
+
specify "should handle JOIN ON" do
|
|
3647
|
+
@u[@ds.cross_join(:x).join(:a, [:u]).join(:b, [[:c, :d], [:e,1]])].should == ["SELECT * FROM t CROSS JOIN x INNER JOIN a USING (u) INNER JOIN b ON ((b.c = a.d) AND (b.e = $b.e))", {:"b.e"=>1}]
|
|
3648
|
+
end
|
|
3649
|
+
|
|
3650
|
+
specify "should raise an UnbindDuplicate exception if same variable is used with multiple different values" do
|
|
3651
|
+
proc{@ds.filter(:foo=>1).or(:foo=>2).unbind}.should raise_error(Sequel::UnbindDuplicate)
|
|
3652
|
+
end
|
|
3653
|
+
|
|
3654
|
+
specify "should handle case where the same variable has the same value in multiple places " do
|
|
3655
|
+
@u[@ds.filter(:foo=>1).or(:foo=>1)].should == ["SELECT * FROM t WHERE ((foo = $foo) OR (foo = $foo))", {:foo=>1}]
|
|
3656
|
+
end
|
|
3657
|
+
|
|
3658
|
+
specify "should raise Error for unhandled objects inside Identifiers and QualifiedIndentifiers" do
|
|
3659
|
+
proc{@ds.filter(Sequel::SQL::Identifier.new([]) > 1).unbind}.should raise_error(Sequel::Error)
|
|
3660
|
+
proc{@ds.filter{foo.qualify({}) > 1}.unbind}.should raise_error(Sequel::Error)
|
|
3599
3661
|
end
|
|
3600
3662
|
end
|
|
3601
3663
|
|
|
3602
3664
|
describe "Sequel::Dataset #with and #with_recursive" do
|
|
3603
3665
|
before do
|
|
3604
|
-
@db =
|
|
3666
|
+
@db = Sequel::Database.new
|
|
3605
3667
|
@ds = @db[:t]
|
|
3606
3668
|
end
|
|
3607
3669
|
|
|
@@ -3624,6 +3686,12 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
|
3624
3686
|
@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c]).sql.should == 'WITH t(b, c) AS (SELECT * FROM x UNION ALL SELECT * FROM t) SELECT * FROM t'
|
|
3625
3687
|
end
|
|
3626
3688
|
|
|
3689
|
+
specify "#with and #with_recursive should quote the columns in the :args option" do
|
|
3690
|
+
@ds.quote_identifiers = true
|
|
3691
|
+
@ds.with(:t, @db[:x], :args=>[:b]).sql.should == 'WITH "t"("b") AS (SELECT * FROM x) SELECT * FROM "t"'
|
|
3692
|
+
@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c]).sql.should == 'WITH "t"("b", "c") AS (SELECT * FROM x UNION ALL SELECT * FROM t) SELECT * FROM "t"'
|
|
3693
|
+
end
|
|
3694
|
+
|
|
3627
3695
|
specify "#with_recursive should take an :union_all=>false option" do
|
|
3628
3696
|
@ds.with_recursive(:t, @db[:x], @db[:t], :union_all=>false).sql.should == 'WITH t AS (SELECT * FROM x UNION SELECT * FROM t) SELECT * FROM t'
|
|
3629
3697
|
end
|
|
@@ -3633,56 +3701,72 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
|
3633
3701
|
proc{@ds.with(:t, @db[:x], :args=>[:b])}.should raise_error(Sequel::Error)
|
|
3634
3702
|
proc{@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c])}.should raise_error(Sequel::Error)
|
|
3635
3703
|
end
|
|
3704
|
+
|
|
3705
|
+
specify "#with should work on insert, update, and delete statements if they support it" do
|
|
3706
|
+
[:insert, :update, :delete].each do |m|
|
|
3707
|
+
@ds.meta_def(:"#{m}_clause_methods"){[:"#{m}_with_sql"] + super()}
|
|
3708
|
+
end
|
|
3709
|
+
@ds.with(:t, @db[:x]).insert_sql(1).should == 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
|
|
3710
|
+
@ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
|
|
3711
|
+
@ds.with(:t, @db[:x]).delete_sql.should == 'WITH t AS (SELECT * FROM x) DELETE FROM t'
|
|
3712
|
+
end
|
|
3713
|
+
|
|
3714
|
+
specify "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
|
|
3715
|
+
@ds.meta_def(:supports_cte?){true}
|
|
3716
|
+
@ds.meta_def(:supports_cte_in_subselect?){false}
|
|
3717
|
+
@ds.with(:t, @ds.from(:s).with(:s, @ds.from(:r))).sql.should == 'WITH s AS (SELECT * FROM r), t AS (SELECT * FROM s) SELECT * FROM t'
|
|
3718
|
+
@ds.with_recursive(:t, @ds.from(:s).with(:s, @ds.from(:r)), @ds.from(:q).with(:q, @ds.from(:p))).sql.should == 'WITH s AS (SELECT * FROM r), q AS (SELECT * FROM p), t AS (SELECT * FROM s UNION ALL SELECT * FROM q) SELECT * FROM t'
|
|
3719
|
+
end
|
|
3636
3720
|
end
|
|
3637
3721
|
|
|
3638
3722
|
describe Sequel::SQL::Constants do
|
|
3639
3723
|
before do
|
|
3640
|
-
@db =
|
|
3724
|
+
@db = Sequel::Database.new
|
|
3641
3725
|
end
|
|
3642
3726
|
|
|
3643
3727
|
it "should have CURRENT_DATE" do
|
|
3644
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_DATE) == 'CURRENT_DATE'
|
|
3645
|
-
@db.literal(Sequel::CURRENT_DATE) == 'CURRENT_DATE'
|
|
3728
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_DATE).should == 'CURRENT_DATE'
|
|
3729
|
+
@db.literal(Sequel::CURRENT_DATE).should == 'CURRENT_DATE'
|
|
3646
3730
|
end
|
|
3647
3731
|
|
|
3648
3732
|
it "should have CURRENT_TIME" do
|
|
3649
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_TIME) == 'CURRENT_TIME'
|
|
3650
|
-
@db.literal(Sequel::CURRENT_TIME) == 'CURRENT_TIME'
|
|
3733
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_TIME).should == 'CURRENT_TIME'
|
|
3734
|
+
@db.literal(Sequel::CURRENT_TIME).should == 'CURRENT_TIME'
|
|
3651
3735
|
end
|
|
3652
3736
|
|
|
3653
3737
|
it "should have CURRENT_TIMESTAMP" do
|
|
3654
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_TIMESTAMP) == 'CURRENT_TIMESTAMP'
|
|
3655
|
-
@db.literal(Sequel::CURRENT_TIMESTAMP) == 'CURRENT_TIMESTAMP'
|
|
3738
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_TIMESTAMP).should == 'CURRENT_TIMESTAMP'
|
|
3739
|
+
@db.literal(Sequel::CURRENT_TIMESTAMP).should == 'CURRENT_TIMESTAMP'
|
|
3656
3740
|
end
|
|
3657
3741
|
|
|
3658
3742
|
it "should have NULL" do
|
|
3659
|
-
@db.literal(Sequel::SQL::Constants::NULL) == 'NULL'
|
|
3660
|
-
@db.literal(Sequel::NULL) == 'NULL'
|
|
3743
|
+
@db.literal(Sequel::SQL::Constants::NULL).should == 'NULL'
|
|
3744
|
+
@db.literal(Sequel::NULL).should == 'NULL'
|
|
3661
3745
|
end
|
|
3662
3746
|
|
|
3663
3747
|
it "should have NOTNULL" do
|
|
3664
|
-
@db.literal(Sequel::SQL::Constants::NOTNULL) == 'NOT NULL'
|
|
3665
|
-
@db.literal(Sequel::NOTNULL) == 'NOT NULL'
|
|
3748
|
+
@db.literal(Sequel::SQL::Constants::NOTNULL).should == 'NOT NULL'
|
|
3749
|
+
@db.literal(Sequel::NOTNULL).should == 'NOT NULL'
|
|
3666
3750
|
end
|
|
3667
3751
|
|
|
3668
3752
|
it "should have TRUE and SQLTRUE" do
|
|
3669
|
-
@db.literal(Sequel::SQL::Constants::TRUE) == '
|
|
3670
|
-
@db.literal(Sequel::TRUE) == '
|
|
3671
|
-
@db.literal(Sequel::SQL::Constants::SQLTRUE) == '
|
|
3672
|
-
@db.literal(Sequel::SQLTRUE) == '
|
|
3753
|
+
@db.literal(Sequel::SQL::Constants::TRUE).should == "'t'"
|
|
3754
|
+
@db.literal(Sequel::TRUE).should == "'t'"
|
|
3755
|
+
@db.literal(Sequel::SQL::Constants::SQLTRUE).should == "'t'"
|
|
3756
|
+
@db.literal(Sequel::SQLTRUE).should == "'t'"
|
|
3673
3757
|
end
|
|
3674
3758
|
|
|
3675
3759
|
it "should have FALSE and SQLFALSE" do
|
|
3676
|
-
@db.literal(Sequel::SQL::Constants::FALSE) == '
|
|
3677
|
-
@db.literal(Sequel::FALSE) == '
|
|
3678
|
-
@db.literal(Sequel::SQL::Constants::SQLFALSE) == '
|
|
3679
|
-
@db.literal(Sequel::SQLFALSE) == '
|
|
3760
|
+
@db.literal(Sequel::SQL::Constants::FALSE).should == "'f'"
|
|
3761
|
+
@db.literal(Sequel::FALSE).should == "'f'"
|
|
3762
|
+
@db.literal(Sequel::SQL::Constants::SQLFALSE).should == "'f'"
|
|
3763
|
+
@db.literal(Sequel::SQLFALSE).should == "'f'"
|
|
3680
3764
|
end
|
|
3681
3765
|
end
|
|
3682
3766
|
|
|
3683
3767
|
describe "Sequel timezone support" do
|
|
3684
3768
|
before do
|
|
3685
|
-
@db =
|
|
3769
|
+
@db = Sequel::Database.new
|
|
3686
3770
|
@dataset = @db.dataset
|
|
3687
3771
|
@dataset.meta_def(:supports_timestamp_timezones?){true}
|
|
3688
3772
|
@dataset.meta_def(:supports_timestamp_usecs?){false}
|
|
@@ -3717,6 +3801,30 @@ describe "Sequel timezone support" do
|
|
|
3717
3801
|
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3718
3802
|
end
|
|
3719
3803
|
|
|
3804
|
+
specify "should have Database#timezone override Sequel.database_timezone" do
|
|
3805
|
+
Sequel.database_timezone = :local
|
|
3806
|
+
@db.timezone = :utc
|
|
3807
|
+
|
|
3808
|
+
t = Time.now
|
|
3809
|
+
s = t.getutc.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3810
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3811
|
+
|
|
3812
|
+
t = DateTime.now
|
|
3813
|
+
s = t.new_offset(0).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3814
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3815
|
+
|
|
3816
|
+
Sequel.database_timezone = :utc
|
|
3817
|
+
@db.timezone = :local
|
|
3818
|
+
|
|
3819
|
+
t = Time.now.utc
|
|
3820
|
+
s = t.getlocal.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3821
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3822
|
+
|
|
3823
|
+
t = DateTime.now.new_offset(0)
|
|
3824
|
+
s = t.new_offset(DateTime.now.offset).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3825
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3826
|
+
end
|
|
3827
|
+
|
|
3720
3828
|
specify "should handle converting database timestamps into application timestamps" do
|
|
3721
3829
|
Sequel.database_timezone = :utc
|
|
3722
3830
|
Sequel.application_timezone = :local
|
|
@@ -3827,13 +3935,7 @@ end
|
|
|
3827
3935
|
|
|
3828
3936
|
describe "Sequel::Dataset#select_map" do
|
|
3829
3937
|
before do
|
|
3830
|
-
@ds =
|
|
3831
|
-
def @ds.fetch_rows(sql)
|
|
3832
|
-
db << sql
|
|
3833
|
-
yield({:c=>1})
|
|
3834
|
-
yield({:c=>2})
|
|
3835
|
-
end
|
|
3836
|
-
@ds.db.reset
|
|
3938
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3837
3939
|
end
|
|
3838
3940
|
|
|
3839
3941
|
specify "should do select and map in one step" do
|
|
@@ -3846,31 +3948,63 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3846
3948
|
@ds.db.sqls.should == ['SELECT a.b FROM t']
|
|
3847
3949
|
end
|
|
3848
3950
|
|
|
3951
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
3952
|
+
proc{@ds.select_map([Sequel.function(:a), :b])}.should raise_error(Sequel::Error)
|
|
3953
|
+
proc{@ds.select_map(Sequel.function(:a)){b}}.should raise_error(Sequel::Error)
|
|
3954
|
+
proc{@ds.select_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
3955
|
+
end
|
|
3956
|
+
|
|
3849
3957
|
specify "should handle implicit aliases in arguments" do
|
|
3850
3958
|
@ds.select_map(:a___b).should == [1, 2]
|
|
3851
3959
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
3852
3960
|
end
|
|
3853
3961
|
|
|
3854
3962
|
specify "should handle other objects" do
|
|
3855
|
-
@ds.select_map("a".
|
|
3963
|
+
@ds.select_map(Sequel.lit("a").as(:b)).should == [1, 2]
|
|
3856
3964
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
3857
3965
|
end
|
|
3858
3966
|
|
|
3967
|
+
specify "should handle identifiers with strings" do
|
|
3968
|
+
@ds.select_map([Sequel::SQL::Identifier.new('c'), :c]).should == [[1, 1], [2, 2]]
|
|
3969
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3970
|
+
end
|
|
3971
|
+
|
|
3859
3972
|
specify "should accept a block" do
|
|
3860
3973
|
@ds.select_map{a(t__c)}.should == [1, 2]
|
|
3861
3974
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t']
|
|
3862
3975
|
end
|
|
3976
|
+
|
|
3977
|
+
specify "should accept a block with an array of columns" do
|
|
3978
|
+
@ds.select_map{[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
3979
|
+
@ds.db.sqls.should == ['SELECT a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3980
|
+
end
|
|
3981
|
+
|
|
3982
|
+
specify "should accept a block with a column" do
|
|
3983
|
+
@ds.select_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
3984
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t']
|
|
3985
|
+
end
|
|
3986
|
+
|
|
3987
|
+
specify "should accept a block and array of arguments" do
|
|
3988
|
+
@ds.select_map([:c, :c]){[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
3989
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3990
|
+
end
|
|
3991
|
+
|
|
3992
|
+
specify "should handle an array of columns" do
|
|
3993
|
+
@ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3994
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3995
|
+
@ds.select_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b), :a__c, :a__d___c]).should == [[1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2]]
|
|
3996
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
|
|
3997
|
+
end
|
|
3998
|
+
|
|
3999
|
+
specify "should handle an array with a single element" do
|
|
4000
|
+
@ds.select_map([:c]).should == [[1], [2]]
|
|
4001
|
+
@ds.db.sqls.should == ['SELECT c FROM t']
|
|
4002
|
+
end
|
|
3863
4003
|
end
|
|
3864
4004
|
|
|
3865
4005
|
describe "Sequel::Dataset#select_order_map" do
|
|
3866
4006
|
before do
|
|
3867
|
-
@ds =
|
|
3868
|
-
def @ds.fetch_rows(sql)
|
|
3869
|
-
db << sql
|
|
3870
|
-
yield({:c=>1})
|
|
3871
|
-
yield({:c=>2})
|
|
3872
|
-
end
|
|
3873
|
-
@ds.db.reset
|
|
4007
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3874
4008
|
end
|
|
3875
4009
|
|
|
3876
4010
|
specify "should do select and map in one step" do
|
|
@@ -3883,6 +4017,12 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3883
4017
|
@ds.db.sqls.should == ['SELECT a.b FROM t ORDER BY a.b']
|
|
3884
4018
|
end
|
|
3885
4019
|
|
|
4020
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
4021
|
+
proc{@ds.select_order_map([Sequel.function(:a), :b])}.should raise_error(Sequel::Error)
|
|
4022
|
+
proc{@ds.select_order_map(Sequel.function(:a)){b}}.should raise_error(Sequel::Error)
|
|
4023
|
+
proc{@ds.select_order_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
4024
|
+
end
|
|
4025
|
+
|
|
3886
4026
|
specify "should handle implicit aliases in arguments" do
|
|
3887
4027
|
@ds.select_order_map(:a___b).should == [1, 2]
|
|
3888
4028
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
@@ -3894,59 +4034,164 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3894
4034
|
end
|
|
3895
4035
|
|
|
3896
4036
|
specify "should handle AliasedExpressions" do
|
|
3897
|
-
@ds.select_order_map("a".
|
|
4037
|
+
@ds.select_order_map(Sequel.lit("a").as(:b)).should == [1, 2]
|
|
3898
4038
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
3899
4039
|
end
|
|
3900
4040
|
|
|
4041
|
+
specify "should handle OrderedExpressions" do
|
|
4042
|
+
@ds.select_order_map(Sequel.desc(:a)).should == [1, 2]
|
|
4043
|
+
@ds.db.sqls.should == ['SELECT a FROM t ORDER BY a DESC']
|
|
4044
|
+
end
|
|
4045
|
+
|
|
3901
4046
|
specify "should accept a block" do
|
|
3902
4047
|
@ds.select_order_map{a(t__c)}.should == [1, 2]
|
|
3903
4048
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t ORDER BY a(t.c)']
|
|
3904
4049
|
end
|
|
4050
|
+
|
|
4051
|
+
specify "should accept a block with an array of columns" do
|
|
4052
|
+
@ds.select_order_map{[c.desc, a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
4053
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c DESC, a(t.c)']
|
|
4054
|
+
end
|
|
4055
|
+
|
|
4056
|
+
specify "should accept a block with a column" do
|
|
4057
|
+
@ds.select_order_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
4058
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c, a(t.c)']
|
|
4059
|
+
end
|
|
4060
|
+
|
|
4061
|
+
specify "should accept a block and array of arguments" do
|
|
4062
|
+
@ds.select_order_map([:c, :c]){[a(t__c).as(c), c.desc]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
4063
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, c FROM t ORDER BY c, c, a(t.c), c DESC']
|
|
4064
|
+
end
|
|
4065
|
+
|
|
4066
|
+
specify "should handle an array of columns" do
|
|
4067
|
+
@ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
4068
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
|
|
4069
|
+
@ds.select_order_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b), Sequel.identifier(:c).qualify(:b).desc, :a__c, Sequel.desc(:a__d___c), Sequel.desc(Sequel.expr(:a__d___c))]).should == [[1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2]]
|
|
4070
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, b.c, a.c, a.d AS c, a.d AS c FROM t ORDER BY d, b.c, c, b.c, b.c DESC, a.c, a.d DESC, a.d DESC']
|
|
4071
|
+
end
|
|
4072
|
+
|
|
4073
|
+
specify "should handle an array with a single element" do
|
|
4074
|
+
@ds.select_order_map([:c]).should == [[1], [2]]
|
|
4075
|
+
@ds.db.sqls.should == ['SELECT c FROM t ORDER BY c']
|
|
4076
|
+
end
|
|
3905
4077
|
end
|
|
3906
4078
|
|
|
3907
4079
|
describe "Sequel::Dataset#select_hash" do
|
|
3908
4080
|
before do
|
|
3909
|
-
@
|
|
3910
|
-
|
|
3911
|
-
@hs = hs
|
|
3912
|
-
end
|
|
3913
|
-
def @ds.fetch_rows(sql)
|
|
3914
|
-
db << sql
|
|
3915
|
-
@hs.each{|h| yield h}
|
|
3916
|
-
end
|
|
3917
|
-
@ds.db.reset
|
|
4081
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4082
|
+
@ds = @db[:t]
|
|
3918
4083
|
end
|
|
3919
4084
|
|
|
3920
|
-
specify "should do select and
|
|
3921
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4085
|
+
specify "should do select and to_hash in one step" do
|
|
3922
4086
|
@ds.select_hash(:a, :b).should == {1=>2, 3=>4}
|
|
3923
4087
|
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3924
4088
|
end
|
|
3925
4089
|
|
|
3926
4090
|
specify "should handle implicit qualifiers in arguments" do
|
|
3927
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3928
4091
|
@ds.select_hash(:t__a, :t__b).should == {1=>2, 3=>4}
|
|
3929
4092
|
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3930
4093
|
end
|
|
3931
4094
|
|
|
3932
4095
|
specify "should handle implicit aliases in arguments" do
|
|
3933
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3934
4096
|
@ds.select_hash(:c___a, :d___b).should == {1=>2, 3=>4}
|
|
3935
4097
|
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
3936
4098
|
end
|
|
3937
4099
|
|
|
3938
4100
|
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
3939
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3940
4101
|
@ds.select_hash(:t__c___a, :t__d___b).should == {1=>2, 3=>4}
|
|
3941
4102
|
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
3942
4103
|
end
|
|
4104
|
+
|
|
4105
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
4106
|
+
@ds.select_hash(Sequel.identifier(:a), Sequel.identifier(:b)).should == {1=>2, 3=>4}
|
|
4107
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4108
|
+
end
|
|
4109
|
+
|
|
4110
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
4111
|
+
@ds.select_hash(Sequel.qualify(:t, :a), Sequel.identifier(:b).qualify(:t)).should == {1=>2, 3=>4}
|
|
4112
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4113
|
+
end
|
|
4114
|
+
|
|
4115
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
4116
|
+
@ds.select_hash(Sequel.expr(:c).as(:a), Sequel.expr(:t).as(:b)).should == {1=>2, 3=>4}
|
|
4117
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
4118
|
+
end
|
|
4119
|
+
|
|
4120
|
+
specify "should work with arrays of columns" do
|
|
4121
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
4122
|
+
@ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [4, 6]=>5}
|
|
4123
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
4124
|
+
@ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 4=>[5, 6]}
|
|
4125
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
4126
|
+
@ds.select_hash([:a, :b], [:b, :c]).should == {[1, 2]=>[2, 3], [4, 5]=>[5, 6]}
|
|
4127
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
4128
|
+
end
|
|
4129
|
+
|
|
4130
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
4131
|
+
proc{@ds.select_hash(Sequel.expr(:c).as(:a), Sequel.function(:b))}.should raise_error(Sequel::Error)
|
|
4132
|
+
end
|
|
4133
|
+
end
|
|
4134
|
+
|
|
4135
|
+
describe "Sequel::Dataset#select_hash_groups" do
|
|
4136
|
+
before do
|
|
4137
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4138
|
+
@ds = @db[:t]
|
|
4139
|
+
end
|
|
4140
|
+
|
|
4141
|
+
specify "should do select and to_hash in one step" do
|
|
4142
|
+
@ds.select_hash_groups(:a, :b).should == {1=>[2], 3=>[4]}
|
|
4143
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4144
|
+
end
|
|
4145
|
+
|
|
4146
|
+
specify "should handle implicit qualifiers in arguments" do
|
|
4147
|
+
@ds.select_hash_groups(:t__a, :t__b).should == {1=>[2], 3=>[4]}
|
|
4148
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4149
|
+
end
|
|
4150
|
+
|
|
4151
|
+
specify "should handle implicit aliases in arguments" do
|
|
4152
|
+
@ds.select_hash_groups(:c___a, :d___b).should == {1=>[2], 3=>[4]}
|
|
4153
|
+
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
4154
|
+
end
|
|
4155
|
+
|
|
4156
|
+
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
4157
|
+
@ds.select_hash_groups(:t__c___a, :t__d___b).should == {1=>[2], 3=>[4]}
|
|
4158
|
+
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
4159
|
+
end
|
|
4160
|
+
|
|
4161
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
4162
|
+
@ds.select_hash_groups(Sequel.identifier(:a), Sequel.identifier(:b)).should == {1=>[2], 3=>[4]}
|
|
4163
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4164
|
+
end
|
|
4165
|
+
|
|
4166
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
4167
|
+
@ds.select_hash_groups(Sequel.qualify(:t, :a), Sequel.identifier(:b).qualify(:t)).should == {1=>[2], 3=>[4]}
|
|
4168
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4169
|
+
end
|
|
4170
|
+
|
|
4171
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
4172
|
+
@ds.select_hash_groups(Sequel.expr(:c).as(:a), Sequel.expr(:t).as(:b)).should == {1=>[2], 3=>[4]}
|
|
4173
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
4174
|
+
end
|
|
4175
|
+
|
|
4176
|
+
specify "should work with arrays of columns" do
|
|
4177
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
4178
|
+
@ds.select_hash_groups([:a, :c], :b).should == {[1, 3]=>[2], [4, 6]=>[5]}
|
|
4179
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
4180
|
+
@ds.select_hash_groups(:a, [:b, :c]).should == {1=>[[2, 3]], 4=>[[5, 6]]}
|
|
4181
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
4182
|
+
@ds.select_hash_groups([:a, :b], [:b, :c]).should == {[1, 2]=>[[2, 3]], [4, 5]=>[[5, 6]]}
|
|
4183
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
4184
|
+
end
|
|
4185
|
+
|
|
4186
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
4187
|
+
proc{@ds.select_hash_groups(Sequel.expr(:c).as(:a), Sequel.function(:b))}.should raise_error(Sequel::Error)
|
|
4188
|
+
end
|
|
3943
4189
|
end
|
|
3944
4190
|
|
|
3945
4191
|
describe "Modifying joined datasets" do
|
|
3946
4192
|
before do
|
|
3947
|
-
@ds =
|
|
4193
|
+
@ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
|
|
3948
4194
|
@ds.meta_def(:supports_modifying_joins?){true}
|
|
3949
|
-
@ds.db.reset
|
|
3950
4195
|
end
|
|
3951
4196
|
|
|
3952
4197
|
specify "should allow deleting from joined datasets" do
|
|
@@ -3962,7 +4207,7 @@ end
|
|
|
3962
4207
|
|
|
3963
4208
|
describe "Dataset#lock_style and for_update" do
|
|
3964
4209
|
before do
|
|
3965
|
-
@ds =
|
|
4210
|
+
@ds = Sequel::Dataset.new(nil).from(:t)
|
|
3966
4211
|
end
|
|
3967
4212
|
|
|
3968
4213
|
specify "#for_update should use FOR UPDATE" do
|
|
@@ -3977,3 +4222,173 @@ describe "Dataset#lock_style and for_update" do
|
|
|
3977
4222
|
@ds.lock_style("FOR SHARE").sql.should == "SELECT * FROM t FOR SHARE"
|
|
3978
4223
|
end
|
|
3979
4224
|
end
|
|
4225
|
+
|
|
4226
|
+
describe "Custom ASTTransformer" do
|
|
4227
|
+
specify "should transform given objects" do
|
|
4228
|
+
c = Class.new(Sequel::ASTTransformer) do
|
|
4229
|
+
def v(s)
|
|
4230
|
+
(s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
|
|
4231
|
+
end
|
|
4232
|
+
end.new
|
|
4233
|
+
ds = Sequel::Dataset.new(nil).from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
|
4234
|
+
ds.sql.should == 'SELECT * FROM t CROSS JOIN a AS g INNER JOIN b AS h USING (c) INNER JOIN d AS i ON (i.e = h.f)'
|
|
4235
|
+
ds.clone(:from=>c.transform(ds.opts[:from]), :join=>c.transform(ds.opts[:join])).sql.should == 'SELECT * FROM tt CROSS JOIN aa AS gg INNER JOIN bb AS hh USING (cc) INNER JOIN dd AS ii ON (ii.ee = hh.ff)'
|
|
4236
|
+
end
|
|
4237
|
+
end
|
|
4238
|
+
|
|
4239
|
+
describe "Dataset#returning" do
|
|
4240
|
+
before do
|
|
4241
|
+
@ds = Sequel.mock(:fetch=>proc{|s| {:foo=>s}})[:t].returning(:foo)
|
|
4242
|
+
@pr = proc do
|
|
4243
|
+
[:insert, :update, :delete].each do |m|
|
|
4244
|
+
@ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_returning_sql"]}
|
|
4245
|
+
end
|
|
4246
|
+
end
|
|
4247
|
+
end
|
|
4248
|
+
|
|
4249
|
+
specify "should use RETURNING clause in the SQL if the dataset supports it" do
|
|
4250
|
+
@pr.call
|
|
4251
|
+
@ds.delete_sql.should == "DELETE FROM t RETURNING foo"
|
|
4252
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1) RETURNING foo"
|
|
4253
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1 RETURNING foo"
|
|
4254
|
+
end
|
|
4255
|
+
|
|
4256
|
+
specify "should not use RETURNING clause in the SQL if the dataset does not support it" do
|
|
4257
|
+
@ds.delete_sql.should == "DELETE FROM t"
|
|
4258
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1)"
|
|
4259
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1"
|
|
4260
|
+
end
|
|
4261
|
+
|
|
4262
|
+
specify "should have insert, update, and delete yield to blocks if RETURNING is used" do
|
|
4263
|
+
@pr.call
|
|
4264
|
+
h = {}
|
|
4265
|
+
@ds.delete{|r| h = r}
|
|
4266
|
+
h.should == {:foo=>"DELETE FROM t RETURNING foo"}
|
|
4267
|
+
@ds.insert(1){|r| h = r}
|
|
4268
|
+
h.should == {:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}
|
|
4269
|
+
@ds.update(:foo=>1){|r| h = r}
|
|
4270
|
+
h.should == {:foo=>"UPDATE t SET foo = 1 RETURNING foo"}
|
|
4271
|
+
end
|
|
4272
|
+
|
|
4273
|
+
specify "should have insert, update, and delete return arrays of hashes if RETURNING is used and a block is not given" do
|
|
4274
|
+
@pr.call
|
|
4275
|
+
h = {}
|
|
4276
|
+
@ds.delete.should == [{:foo=>"DELETE FROM t RETURNING foo"}]
|
|
4277
|
+
@ds.insert(1).should == [{:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}]
|
|
4278
|
+
@ds.update(:foo=>1).should == [{:foo=>"UPDATE t SET foo = 1 RETURNING foo"}]
|
|
4279
|
+
end
|
|
4280
|
+
end
|
|
4281
|
+
|
|
4282
|
+
describe "Dataset emulating bitwise operator support" do
|
|
4283
|
+
before do
|
|
4284
|
+
@ds = Sequel::Database.new.dataset
|
|
4285
|
+
@ds.quote_identifiers = true
|
|
4286
|
+
def @ds.complex_expression_sql_append(sql, op, args)
|
|
4287
|
+
sql << complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
|
4288
|
+
end
|
|
4289
|
+
end
|
|
4290
|
+
|
|
4291
|
+
it "should work with any numbers of arguments for operators" do
|
|
4292
|
+
@ds.select(Sequel::SQL::ComplexExpression.new(:&, :x)).sql.should == 'SELECT "x"'
|
|
4293
|
+
@ds.select(Sequel.expr(:x) & 1).sql.should == 'SELECT bitand("x", 1)'
|
|
4294
|
+
@ds.select(Sequel.expr(:x) & 1 & 2).sql.should == 'SELECT bitand(bitand("x", 1), 2)'
|
|
4295
|
+
end
|
|
4296
|
+
end
|
|
4297
|
+
|
|
4298
|
+
describe "Dataset feature defaults" do
|
|
4299
|
+
it "should not require aliases for recursive CTEs by default" do
|
|
4300
|
+
Sequel::Database.new.dataset.recursive_cte_requires_column_aliases?.should be_false
|
|
4301
|
+
end
|
|
4302
|
+
|
|
4303
|
+
it "should not require placeholder type specifiers by default" do
|
|
4304
|
+
Sequel::Database.new.dataset.requires_placeholder_type_specifiers?.should be_false
|
|
4305
|
+
end
|
|
4306
|
+
|
|
4307
|
+
it "offset use should be returning a separate row number column by default" do
|
|
4308
|
+
Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
|
|
4309
|
+
end
|
|
4310
|
+
end
|
|
4311
|
+
|
|
4312
|
+
describe "Dataset extensions" do
|
|
4313
|
+
before(:all) do
|
|
4314
|
+
class << Sequel
|
|
4315
|
+
alias _extension extension
|
|
4316
|
+
def extension(*)
|
|
4317
|
+
end
|
|
4318
|
+
end
|
|
4319
|
+
end
|
|
4320
|
+
after(:all) do
|
|
4321
|
+
class << Sequel
|
|
4322
|
+
alias extension _extension
|
|
4323
|
+
end
|
|
4324
|
+
end
|
|
4325
|
+
before do
|
|
4326
|
+
@ds = Sequel::Dataset.new(nil)
|
|
4327
|
+
end
|
|
4328
|
+
|
|
4329
|
+
specify "should be able to register an extension with a module Database#extension extend the module" do
|
|
4330
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4331
|
+
@ds.extension(:foo).a.should == 1
|
|
4332
|
+
end
|
|
4333
|
+
|
|
4334
|
+
specify "should be able to register an extension with a block and Database#extension call the block" do
|
|
4335
|
+
@ds.quote_identifiers = false
|
|
4336
|
+
Sequel::Dataset.register_extension(:foo){|db| db.quote_identifiers = true}
|
|
4337
|
+
@ds.extension(:foo).quote_identifiers?.should be_true
|
|
4338
|
+
end
|
|
4339
|
+
|
|
4340
|
+
specify "should be able to register an extension with a callable and Database#extension call the callable" do
|
|
4341
|
+
@ds.quote_identifiers = false
|
|
4342
|
+
Sequel::Dataset.register_extension(:foo, proc{|db| db.quote_identifiers = true})
|
|
4343
|
+
@ds.extension(:foo).quote_identifiers?.should be_true
|
|
4344
|
+
end
|
|
4345
|
+
|
|
4346
|
+
specify "should be able to load multiple extensions in the same call" do
|
|
4347
|
+
@ds.quote_identifiers = false
|
|
4348
|
+
@ds.identifier_input_method = :downcase
|
|
4349
|
+
Sequel::Dataset.register_extension(:foo, proc{|ds| ds.quote_identifiers = true})
|
|
4350
|
+
Sequel::Dataset.register_extension(:bar, proc{|ds| ds.identifier_input_method = nil})
|
|
4351
|
+
ds = @ds.extension(:foo, :bar)
|
|
4352
|
+
ds.quote_identifiers?.should be_true
|
|
4353
|
+
ds.identifier_input_method.should be_nil
|
|
4354
|
+
end
|
|
4355
|
+
|
|
4356
|
+
specify "should have #extension not modify the receiver" do
|
|
4357
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4358
|
+
@ds.extension(:foo)
|
|
4359
|
+
proc{@ds.a}.should raise_error(NoMethodError)
|
|
4360
|
+
end
|
|
4361
|
+
|
|
4362
|
+
specify "should have #extension not return a cloned dataset" do
|
|
4363
|
+
@ds.extend(Module.new{def b; 2; end})
|
|
4364
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4365
|
+
v = @ds.extension(:foo)
|
|
4366
|
+
v.should_not equal(@ds)
|
|
4367
|
+
v.should be_a_kind_of(Sequel::Dataset)
|
|
4368
|
+
v.b.should == 2
|
|
4369
|
+
end
|
|
4370
|
+
|
|
4371
|
+
specify "should have #extension! modify the receiver" do
|
|
4372
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4373
|
+
@ds.extension!(:foo)
|
|
4374
|
+
@ds.a.should == 1
|
|
4375
|
+
end
|
|
4376
|
+
|
|
4377
|
+
specify "should have #extension! return the receiver" do
|
|
4378
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4379
|
+
@ds.extension!(:foo).should equal(@ds)
|
|
4380
|
+
end
|
|
4381
|
+
|
|
4382
|
+
specify "should register a Database extension for modifying all datasets when registering with a module" do
|
|
4383
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4384
|
+
Sequel.mock.extension(:foo).dataset.a.should == 1
|
|
4385
|
+
end
|
|
4386
|
+
|
|
4387
|
+
specify "should raise an Error if registering with both a module and a block" do
|
|
4388
|
+
proc{Sequel::Dataset.register_extension(:foo, Module.new){}}.should raise_error(Sequel::Error)
|
|
4389
|
+
end
|
|
4390
|
+
|
|
4391
|
+
specify "should raise an Error if attempting to load an incompatible extension" do
|
|
4392
|
+
proc{@ds.extension(:foo2)}.should raise_error(Sequel::Error)
|
|
4393
|
+
end
|
|
4394
|
+
end
|