sequel 3.21.0 → 3.39.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 +1061 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +103 -63
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +67 -51
- data/doc/advanced_associations.rdoc +189 -75
- data/doc/association_basics.rdoc +327 -79
- 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 +547 -0
- data/doc/opening_databases.rdoc +114 -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/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/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- 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 +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +56 -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 +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -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 +7 -24
- 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 +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +279 -97
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +125 -222
- data/lib/sequel/adapters/mysql2.rb +65 -56
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +368 -138
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +343 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +401 -116
- data/lib/sequel/adapters/shared/mysql.rb +424 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +257 -45
- data/lib/sequel/adapters/shared/postgres.rb +675 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +285 -96
- data/lib/sequel/adapters/sqlite.rb +101 -39
- 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 +28 -19
- data/lib/sequel/adapters/tinytds.rb +174 -22
- 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/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +43 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +38 -28
- 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 +190 -46
- data/lib/sequel/database/query.rb +272 -110
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +300 -67
- 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 +305 -54
- data/lib/sequel/dataset/sql.rb +720 -292
- 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/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 +537 -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 +313 -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 +208 -0
- data/lib/sequel/extensions/pg_range.rb +512 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +572 -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 +22 -4
- 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 +58 -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 +167 -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 +5 -3
- 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/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 +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +55 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +649 -122
- 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 +1 -1
- data/spec/adapters/mssql_spec.rb +194 -66
- data/spec/adapters/mysql_spec.rb +475 -306
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +1982 -325
- data/spec/adapters/spec_helper.rb +9 -6
- data/spec/adapters/sqlite_spec.rb +203 -75
- data/spec/core/connection_pool_spec.rb +218 -93
- data/spec/core/database_spec.rb +956 -522
- data/spec/core/dataset_spec.rb +1631 -1242
- data/spec/core/expression_filters_spec.rb +690 -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 +66 -32
- 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/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 +320 -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 +194 -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 +323 -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 +23 -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 +13 -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 +58 -67
- data/spec/extensions/validation_helpers_spec.rb +31 -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 +11 -5
- data/spec/integration/dataset_test.rb +717 -129
- 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 +604 -147
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +367 -57
- data/spec/integration/spec_helper.rb +42 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +31 -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 +209 -80
- 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,36 @@ 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
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1589
|
+
@dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1480
1590
|
end
|
|
1481
1591
|
end
|
|
1482
1592
|
|
|
@@ -1486,42 +1596,33 @@ describe "Dataset#limit" do
|
|
|
1486
1596
|
end
|
|
1487
1597
|
|
|
1488
1598
|
specify "should include a LIMIT clause in the select statement" do
|
|
1489
|
-
@dataset.limit(10).sql.should ==
|
|
1490
|
-
'SELECT * FROM test LIMIT 10'
|
|
1599
|
+
@dataset.limit(10).sql.should == 'SELECT * FROM test LIMIT 10'
|
|
1491
1600
|
end
|
|
1492
1601
|
|
|
1493
1602
|
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'
|
|
1603
|
+
@dataset.limit(3..7).sql.should == 'SELECT * FROM test LIMIT 5 OFFSET 3'
|
|
1604
|
+
@dataset.limit(3...7).sql.should == 'SELECT * FROM test LIMIT 4 OFFSET 3'
|
|
1499
1605
|
end
|
|
1500
1606
|
|
|
1501
1607
|
specify "should include an offset if a second argument is given" do
|
|
1502
|
-
@dataset.limit(6, 10).sql.should ==
|
|
1503
|
-
|
|
1504
|
-
end
|
|
1608
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 10'
|
|
1609
|
+
end
|
|
1505
1610
|
|
|
1506
1611
|
specify "should convert regular strings to integers" do
|
|
1507
|
-
@dataset.limit('6', 'a() - 1').sql.should ==
|
|
1508
|
-
'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1612
|
+
@dataset.limit('6', 'a() - 1').sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1509
1613
|
end
|
|
1510
1614
|
|
|
1511
1615
|
specify "should not convert literal strings to integers" do
|
|
1512
|
-
@dataset.limit('6'.lit
|
|
1513
|
-
'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1616
|
+
@dataset.limit(Sequel.lit('6'), Sequel.lit('a() - 1')).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1514
1617
|
end
|
|
1515
1618
|
|
|
1516
1619
|
specify "should not convert other objects" do
|
|
1517
|
-
@dataset.limit(6, :a
|
|
1518
|
-
'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1620
|
+
@dataset.limit(6, Sequel.function(:a) - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1519
1621
|
end
|
|
1520
1622
|
|
|
1521
1623
|
specify "should work with fixed sql datasets" do
|
|
1522
1624
|
@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'
|
|
1625
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
|
1525
1626
|
end
|
|
1526
1627
|
|
|
1527
1628
|
specify "should raise an error if an invalid limit or offset is used" do
|
|
@@ -1535,15 +1636,20 @@ describe "Dataset#limit" do
|
|
|
1535
1636
|
end
|
|
1536
1637
|
|
|
1537
1638
|
describe "Dataset#naked" do
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1639
|
+
specify "should returned clone dataset without row_proc" do
|
|
1640
|
+
d = Sequel::Dataset.new(nil)
|
|
1641
|
+
d.row_proc = Proc.new{|r| r}
|
|
1642
|
+
d.naked.row_proc.should be_nil
|
|
1643
|
+
d.row_proc.should_not be_nil
|
|
1542
1644
|
end
|
|
1543
|
-
|
|
1645
|
+
end
|
|
1646
|
+
|
|
1647
|
+
describe "Dataset#naked!" do
|
|
1544
1648
|
specify "should remove any existing row_proc" do
|
|
1545
|
-
|
|
1546
|
-
|
|
1649
|
+
d = Sequel::Dataset.new(nil)
|
|
1650
|
+
d.row_proc = Proc.new{|r| r}
|
|
1651
|
+
d.naked!.row_proc.should be_nil
|
|
1652
|
+
d.row_proc.should be_nil
|
|
1547
1653
|
end
|
|
1548
1654
|
end
|
|
1549
1655
|
|
|
@@ -1555,7 +1661,7 @@ describe "Dataset#qualified_column_name" do
|
|
|
1555
1661
|
specify "should return the literal value if not given a symbol" do
|
|
1556
1662
|
@dataset.literal(@dataset.send(:qualified_column_name, 'ccc__b', :items)).should == "'ccc__b'"
|
|
1557
1663
|
@dataset.literal(@dataset.send(:qualified_column_name, 3, :items)).should == '3'
|
|
1558
|
-
@dataset.literal(@dataset.send(:qualified_column_name, 'a'
|
|
1664
|
+
@dataset.literal(@dataset.send(:qualified_column_name, Sequel.lit('a'), :items)).should == 'a'
|
|
1559
1665
|
end
|
|
1560
1666
|
|
|
1561
1667
|
specify "should qualify the column with the supplied table name if given an unqualified symbol" do
|
|
@@ -1567,42 +1673,46 @@ describe "Dataset#qualified_column_name" do
|
|
|
1567
1673
|
end
|
|
1568
1674
|
|
|
1569
1675
|
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)
|
|
1676
|
+
@dataset.literal(@dataset.send(:qualified_column_name, :ccc, Sequel.expr(:items).as(:i))).should == 'i.ccc'
|
|
1582
1677
|
end
|
|
1583
1678
|
end
|
|
1584
1679
|
|
|
1585
1680
|
describe "Dataset#map" do
|
|
1586
1681
|
before do
|
|
1587
|
-
@d =
|
|
1682
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1588
1683
|
end
|
|
1589
1684
|
|
|
1590
1685
|
specify "should provide the usual functionality if no argument is given" do
|
|
1591
|
-
@d.map
|
|
1686
|
+
@d.map{|n| n[:a] + n[:b]}.should == [3, 7, 11]
|
|
1592
1687
|
end
|
|
1593
1688
|
|
|
1594
1689
|
specify "should map using #[column name] if column name is given" do
|
|
1595
1690
|
@d.map(:a).should == [1, 3, 5]
|
|
1596
1691
|
end
|
|
1597
1692
|
|
|
1693
|
+
specify "should support multiple column names if an array of column names is given" do
|
|
1694
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1695
|
+
end
|
|
1696
|
+
|
|
1697
|
+
specify "should not call the row_proc if an argument is given" do
|
|
1698
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1699
|
+
@d.map(:a).should == [1, 3, 5]
|
|
1700
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1701
|
+
end
|
|
1702
|
+
|
|
1703
|
+
specify "should call the row_proc if no argument is given" do
|
|
1704
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1705
|
+
@d.map{|n| n[:a] + n[:b]}.should == [6, 14, 22]
|
|
1706
|
+
end
|
|
1707
|
+
|
|
1598
1708
|
specify "should return the complete dataset values if nothing is given" do
|
|
1599
|
-
@d.map.to_a.should ==
|
|
1709
|
+
@d.map.to_a.should == [{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}]
|
|
1600
1710
|
end
|
|
1601
1711
|
end
|
|
1602
1712
|
|
|
1603
1713
|
describe "Dataset#to_hash" do
|
|
1604
1714
|
before do
|
|
1605
|
-
@d =
|
|
1715
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1606
1716
|
end
|
|
1607
1717
|
|
|
1608
1718
|
specify "should provide a hash with the first column as key and the second as value" do
|
|
@@ -1614,11 +1724,73 @@ describe "Dataset#to_hash" do
|
|
|
1614
1724
|
@d.to_hash(:a).should == {1 => {:a => 1, :b => 2}, 3 => {:a => 3, :b => 4}, 5 => {:a => 5, :b => 6}}
|
|
1615
1725
|
@d.to_hash(:b).should == {2 => {:a => 1, :b => 2}, 4 => {:a => 3, :b => 4}, 6 => {:a => 5, :b => 6}}
|
|
1616
1726
|
end
|
|
1727
|
+
|
|
1728
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1729
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1730
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1731
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1732
|
+
@d.to_hash([:a, :b]).should == {[1, 2] => {:a => 1, :b => 2}, [3, 4] => {:a => 3, :b => 4}, [5, 6] => {:a => 5, :b => 6}}
|
|
1733
|
+
end
|
|
1734
|
+
|
|
1735
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1736
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1737
|
+
@d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
|
|
1738
|
+
@d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
|
|
1739
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1740
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1741
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1742
|
+
end
|
|
1743
|
+
|
|
1744
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1745
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1746
|
+
@d.to_hash(:a).should == {2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12}}
|
|
1747
|
+
@d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
|
|
1748
|
+
@d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
|
|
1749
|
+
end
|
|
1750
|
+
end
|
|
1751
|
+
|
|
1752
|
+
describe "Dataset#to_hash_groups" do
|
|
1753
|
+
before do
|
|
1754
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 1, :b => 6}, {:a => 7, :b => 4}])[:items]
|
|
1755
|
+
end
|
|
1756
|
+
|
|
1757
|
+
specify "should provide a hash with the first column as key and the second as value" do
|
|
1758
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1759
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1760
|
+
end
|
|
1761
|
+
|
|
1762
|
+
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
|
|
1763
|
+
@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}]}
|
|
1764
|
+
@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}]}
|
|
1765
|
+
end
|
|
1766
|
+
|
|
1767
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1768
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1769
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1770
|
+
@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]]}
|
|
1771
|
+
@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}]}
|
|
1772
|
+
end
|
|
1773
|
+
|
|
1774
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1775
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1776
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1777
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1778
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1779
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1780
|
+
@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]]}
|
|
1781
|
+
end
|
|
1782
|
+
|
|
1783
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1784
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1785
|
+
@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}]}
|
|
1786
|
+
@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}]}
|
|
1787
|
+
@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}]}
|
|
1788
|
+
end
|
|
1617
1789
|
end
|
|
1618
1790
|
|
|
1619
1791
|
describe "Dataset#distinct" do
|
|
1620
1792
|
before do
|
|
1621
|
-
@db =
|
|
1793
|
+
@db = Sequel.mock
|
|
1622
1794
|
@dataset = @db[:test].select(:name)
|
|
1623
1795
|
end
|
|
1624
1796
|
|
|
@@ -1634,7 +1806,7 @@ describe "Dataset#distinct" do
|
|
|
1634
1806
|
specify "should use DISTINCT ON if columns are given and DISTINCT ON is supported" do
|
|
1635
1807
|
@dataset.meta_def(:supports_distinct_on?){true}
|
|
1636
1808
|
@dataset.distinct(:a, :b).sql.should == 'SELECT DISTINCT ON (a, b) name FROM test'
|
|
1637
|
-
@dataset.distinct(
|
|
1809
|
+
@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
1810
|
end
|
|
1639
1811
|
|
|
1640
1812
|
specify "should do a subselect for count" do
|
|
@@ -1645,132 +1817,119 @@ end
|
|
|
1645
1817
|
|
|
1646
1818
|
describe "Dataset#count" do
|
|
1647
1819
|
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)
|
|
1820
|
+
@db = Sequel.mock(:fetch=>{:count=>1})
|
|
1821
|
+
@dataset = @db.from(:test).columns(:count)
|
|
1660
1822
|
end
|
|
1661
1823
|
|
|
1662
1824
|
specify "should format SQL properly" do
|
|
1663
1825
|
@dataset.count.should == 1
|
|
1664
|
-
@
|
|
1826
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
|
|
1827
|
+
end
|
|
1828
|
+
|
|
1829
|
+
specify "should accept an argument" do
|
|
1830
|
+
@dataset.count(:foo).should == 1
|
|
1831
|
+
@db.sqls.should == ['SELECT COUNT(foo) AS count FROM test LIMIT 1']
|
|
1832
|
+
end
|
|
1833
|
+
|
|
1834
|
+
specify "should work with a nil argument" do
|
|
1835
|
+
@dataset.count(nil).should == 1
|
|
1836
|
+
@db.sqls.should == ['SELECT COUNT(NULL) AS count FROM test LIMIT 1']
|
|
1837
|
+
end
|
|
1838
|
+
|
|
1839
|
+
specify "should accept a virtual row block" do
|
|
1840
|
+
@dataset.count{foo(bar)}.should == 1
|
|
1841
|
+
@db.sqls.should == ['SELECT COUNT(foo(bar)) AS count FROM test LIMIT 1']
|
|
1842
|
+
end
|
|
1843
|
+
|
|
1844
|
+
specify "should raise an Error if given an argument and a block" do
|
|
1845
|
+
proc{@dataset.count(:foo){foo(bar)}}.should raise_error(Sequel::Error)
|
|
1665
1846
|
end
|
|
1666
1847
|
|
|
1667
1848
|
specify "should include the where clause if it's there" do
|
|
1668
|
-
@dataset.filter(:abc
|
|
1669
|
-
@
|
|
1849
|
+
@dataset.filter(Sequel.expr(:abc) < 30).count.should == 1
|
|
1850
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
|
|
1670
1851
|
end
|
|
1671
1852
|
|
|
1672
1853
|
specify "should count properly for datasets with fixed sql" do
|
|
1673
1854
|
@dataset.opts[:sql] = "select abc from xyz"
|
|
1674
1855
|
@dataset.count.should == 1
|
|
1675
|
-
@
|
|
1856
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
|
|
1676
1857
|
end
|
|
1677
1858
|
|
|
1678
1859
|
specify "should count properly when using UNION, INTERSECT, or EXCEPT" do
|
|
1679
1860
|
@dataset.union(@dataset).count.should == 1
|
|
1680
|
-
@
|
|
1861
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1681
1862
|
@dataset.intersect(@dataset).count.should == 1
|
|
1682
|
-
@
|
|
1863
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1683
1864
|
@dataset.except(@dataset).count.should == 1
|
|
1684
|
-
@
|
|
1865
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1685
1866
|
end
|
|
1686
1867
|
|
|
1687
1868
|
specify "should return limit if count is greater than it" do
|
|
1688
1869
|
@dataset.limit(5).count.should == 1
|
|
1689
|
-
@
|
|
1870
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"]
|
|
1690
1871
|
end
|
|
1691
1872
|
|
|
1692
1873
|
it "should work on a graphed_dataset" do
|
|
1693
1874
|
@dataset.should_receive(:columns).twice.and_return([:a])
|
|
1694
1875
|
@dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
|
|
1695
|
-
@
|
|
1876
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
1696
1877
|
end
|
|
1697
1878
|
|
|
1698
1879
|
specify "should not cache the columns value" do
|
|
1699
|
-
ds = @dataset.from(:blah)
|
|
1880
|
+
ds = @dataset.from(:blah).columns(:a)
|
|
1700
1881
|
ds.columns.should == [:a]
|
|
1701
1882
|
ds.count.should == 1
|
|
1702
|
-
@
|
|
1883
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM blah LIMIT 1']
|
|
1703
1884
|
ds.columns.should == [:a]
|
|
1704
1885
|
end
|
|
1705
1886
|
end
|
|
1706
1887
|
|
|
1707
|
-
|
|
1708
1888
|
describe "Dataset#group_and_count" do
|
|
1709
1889
|
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)
|
|
1890
|
+
@ds = Sequel::Dataset.new(nil).from(:test)
|
|
1721
1891
|
end
|
|
1722
1892
|
|
|
1723
1893
|
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"
|
|
1894
|
+
@ds.group_and_count(:name).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1726
1895
|
end
|
|
1727
1896
|
|
|
1728
1897
|
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"
|
|
1898
|
+
@ds.group_and_count(:a, :b).sql.should == "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
|
|
1731
1899
|
end
|
|
1732
1900
|
|
|
1733
1901
|
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"
|
|
1902
|
+
@ds.group_and_count(:name___n).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1903
|
+
@ds.group_and_count(:name__n).sql.should == "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
|
1738
1904
|
end
|
|
1739
1905
|
|
|
1740
1906
|
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"
|
|
1907
|
+
@ds.group_and_count(Sequel.identifier(:name___n)).sql.should == "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1743
1908
|
end
|
|
1744
1909
|
|
|
1745
1910
|
specify "should handle literal strings" do
|
|
1746
|
-
@ds.group_and_count("name"
|
|
1747
|
-
"SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1911
|
+
@ds.group_and_count(Sequel.lit("name")).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1748
1912
|
end
|
|
1749
1913
|
|
|
1750
1914
|
specify "should handle aliased expressions" do
|
|
1751
|
-
@ds.group_and_count(:name.as(:n)).sql.should ==
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1915
|
+
@ds.group_and_count(Sequel.expr(:name).as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1916
|
+
@ds.group_and_count(Sequel.identifier(:name).as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1917
|
+
end
|
|
1918
|
+
|
|
1919
|
+
specify "should take a virtual row block" do
|
|
1920
|
+
@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)"
|
|
1921
|
+
@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)"
|
|
1922
|
+
@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
1923
|
end
|
|
1756
1924
|
end
|
|
1757
1925
|
|
|
1758
1926
|
describe "Dataset#empty?" do
|
|
1759
1927
|
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"
|
|
1928
|
+
db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
|
|
1929
|
+
db.from(:test).should_not be_empty
|
|
1930
|
+
db.sqls.should == ['SELECT 1 AS one FROM test LIMIT 1']
|
|
1931
|
+
db.from(:test).filter(false).should be_empty
|
|
1932
|
+
db.sqls.should == ["SELECT 1 AS one FROM test WHERE 'f' LIMIT 1"]
|
|
1774
1933
|
end
|
|
1775
1934
|
end
|
|
1776
1935
|
|
|
@@ -1781,22 +1940,22 @@ describe "Dataset#first_source_alias" do
|
|
|
1781
1940
|
|
|
1782
1941
|
specify "should be the entire first source if not aliased" do
|
|
1783
1942
|
@ds.from(:t).first_source_alias.should == :t
|
|
1784
|
-
@ds.from(:t__a
|
|
1943
|
+
@ds.from(Sequel.identifier(:t__a)).first_source_alias.should == Sequel.identifier(:t__a)
|
|
1785
1944
|
@ds.from(:s__t).first_source_alias.should == :s__t
|
|
1786
|
-
@ds.from(
|
|
1945
|
+
@ds.from(Sequel.qualify(:s, :t)).first_source_alias.should == Sequel.qualify(:s, :t)
|
|
1787
1946
|
end
|
|
1788
1947
|
|
|
1789
1948
|
specify "should be the alias if aliased" do
|
|
1790
1949
|
@ds.from(:t___a).first_source_alias.should == :a
|
|
1791
1950
|
@ds.from(:s__t___a).first_source_alias.should == :a
|
|
1792
|
-
@ds.from(:t.as(:a)).first_source_alias.should == :a
|
|
1951
|
+
@ds.from(Sequel.expr(:t).as(:a)).first_source_alias.should == :a
|
|
1793
1952
|
end
|
|
1794
1953
|
|
|
1795
1954
|
specify "should be aliased as first_source" do
|
|
1796
1955
|
@ds.from(:t).first_source.should == :t
|
|
1797
|
-
@ds.from(:t__a
|
|
1956
|
+
@ds.from(Sequel.identifier(:t__a)).first_source.should == Sequel.identifier(:t__a)
|
|
1798
1957
|
@ds.from(:s__t___a).first_source.should == :a
|
|
1799
|
-
@ds.from(:t.as(:a)).first_source.should == :a
|
|
1958
|
+
@ds.from(Sequel.expr(:t).as(:a)).first_source.should == :a
|
|
1800
1959
|
end
|
|
1801
1960
|
|
|
1802
1961
|
specify "should raise exception if table doesn't have a source" do
|
|
@@ -1811,15 +1970,15 @@ describe "Dataset#first_source_table" do
|
|
|
1811
1970
|
|
|
1812
1971
|
specify "should be the entire first source if not aliased" do
|
|
1813
1972
|
@ds.from(:t).first_source_table.should == :t
|
|
1814
|
-
@ds.from(:t__a
|
|
1973
|
+
@ds.from(Sequel.identifier(:t__a)).first_source_table.should == Sequel.identifier(:t__a)
|
|
1815
1974
|
@ds.from(:s__t).first_source_table.should == :s__t
|
|
1816
|
-
@ds.from(
|
|
1975
|
+
@ds.from(Sequel.qualify(:s, :t)).first_source_table.should == Sequel.qualify(:s, :t)
|
|
1817
1976
|
end
|
|
1818
1977
|
|
|
1819
1978
|
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 ==
|
|
1979
|
+
@ds.literal(@ds.from(:t___a).first_source_table).should == "t"
|
|
1980
|
+
@ds.literal(@ds.from(:s__t___a).first_source_table).should == "s.t"
|
|
1981
|
+
@ds.literal(@ds.from(Sequel.expr(:t).as(:a)).first_source_table).should == "t"
|
|
1823
1982
|
end
|
|
1824
1983
|
|
|
1825
1984
|
specify "should raise exception if table doesn't have a source" do
|
|
@@ -1849,73 +2008,64 @@ describe "Dataset#from_self" do
|
|
|
1849
2008
|
'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
|
|
1850
2009
|
end
|
|
1851
2010
|
|
|
1852
|
-
specify "should not options such as server" do
|
|
2011
|
+
specify "should not remove non-SQL options such as :server" do
|
|
1853
2012
|
@ds.server(:blah).from_self(:alias=>:some_name).opts[:server].should == :blah
|
|
1854
2013
|
end
|
|
1855
2014
|
|
|
2015
|
+
specify "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
|
|
2016
|
+
ds = Sequel::Dataset.new(nil)
|
|
2017
|
+
ds.meta_def(:supports_cte?){true}
|
|
2018
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2019
|
+
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'
|
|
2020
|
+
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'
|
|
2021
|
+
end
|
|
1856
2022
|
end
|
|
1857
2023
|
|
|
1858
2024
|
describe "Dataset#join_table" do
|
|
1859
2025
|
before do
|
|
1860
|
-
@d =
|
|
2026
|
+
@d = Sequel::Dataset.new(nil).from(:items)
|
|
1861
2027
|
@d.quote_identifiers = true
|
|
1862
2028
|
end
|
|
1863
2029
|
|
|
1864
2030
|
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")'
|
|
2031
|
+
@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
2032
|
end
|
|
1868
2033
|
|
|
1869
2034
|
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 ==
|
|
2035
|
+
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
|
1871
2036
|
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND ("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100))'
|
|
1872
2037
|
end
|
|
1873
2038
|
|
|
1874
2039
|
specify "should include WHERE clause if applicable" do
|
|
1875
|
-
@d.filter(:price
|
|
2040
|
+
@d.filter(Sequel.expr(:price) < 100).join_table(:right_outer, :categories, :category_id => :id).sql.should ==
|
|
1876
2041
|
'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") WHERE ("price" < 100)'
|
|
1877
2042
|
end
|
|
1878
2043
|
|
|
1879
2044
|
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"'
|
|
2045
|
+
@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
2046
|
end
|
|
1883
2047
|
|
|
1884
2048
|
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")'
|
|
2049
|
+
@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
2050
|
end
|
|
1888
2051
|
|
|
1889
2052
|
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")'
|
|
2053
|
+
@d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1892
2054
|
end
|
|
1893
2055
|
|
|
1894
2056
|
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"'
|
|
2057
|
+
@d.left_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2058
|
+
@d.right_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2059
|
+
@d.full_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2060
|
+
@d.inner_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2061
|
+
@d.left_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2062
|
+
@d.right_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2063
|
+
@d.full_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2064
|
+
@d.natural_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2065
|
+
@d.natural_left_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
|
|
2066
|
+
@d.natural_right_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
|
|
2067
|
+
@d.natural_full_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
|
|
2068
|
+
@d.cross_join(:categories).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
1919
2069
|
end
|
|
1920
2070
|
|
|
1921
2071
|
specify "should raise an error if additional arguments are provided to join methods that don't take conditions" do
|
|
@@ -1935,95 +2085,76 @@ describe "Dataset#join_table" do
|
|
|
1935
2085
|
end
|
|
1936
2086
|
|
|
1937
2087
|
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")'
|
|
2088
|
+
@d.join_table(nil, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1940
2089
|
end
|
|
1941
2090
|
|
|
1942
2091
|
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")'
|
|
2092
|
+
@d.join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1945
2093
|
end
|
|
1946
2094
|
|
|
1947
2095
|
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")'
|
|
2096
|
+
@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
2097
|
end
|
|
1951
2098
|
|
|
1952
2099
|
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")'
|
|
2100
|
+
@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
2101
|
end
|
|
1956
2102
|
|
|
1957
2103
|
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")'
|
|
2104
|
+
@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
2105
|
end
|
|
1961
2106
|
|
|
1962
2107
|
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")'
|
|
2108
|
+
@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
2109
|
end
|
|
1968
2110
|
|
|
1969
2111
|
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")'
|
|
2112
|
+
@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
2113
|
end
|
|
1973
2114
|
|
|
1974
2115
|
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")'
|
|
2116
|
+
@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")'
|
|
2117
|
+
@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
2118
|
end
|
|
1980
2119
|
|
|
1981
2120
|
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")'
|
|
2121
|
+
@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
2122
|
end
|
|
1985
2123
|
|
|
1986
2124
|
specify "should support the :implicit_qualifier option" do
|
|
1987
|
-
@d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should ==
|
|
1988
|
-
|
|
2125
|
+
@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")'
|
|
2126
|
+
end
|
|
2127
|
+
|
|
2128
|
+
specify "should not qualify if :qualify=>false option is given" do
|
|
2129
|
+
@d.from('stats').join(:players, {:id => :player_id}, :qualify=>false).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON ("id" = "player_id")'
|
|
2130
|
+
end
|
|
2131
|
+
|
|
2132
|
+
specify "should do deep qualification if :qualify=>:deep option is given" do
|
|
2133
|
+
@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
2134
|
end
|
|
1990
2135
|
|
|
1991
2136
|
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))'
|
|
2137
|
+
@d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
|
2138
|
+
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
|
2139
|
+
@d.join_table(:left_outer, :categories, :timestamp => Sequel::CURRENT_TIMESTAMP).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
|
2140
|
+
@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
2141
|
end
|
|
2001
2142
|
|
|
2002
2143
|
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)
|
|
2144
|
+
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.should raise_error(Sequel::Error)
|
|
2005
2145
|
end
|
|
2006
2146
|
|
|
2007
2147
|
specify "should support joining datasets" do
|
|
2008
2148
|
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
|
-
|
|
2149
|
+
@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
2150
|
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")'
|
|
2151
|
+
@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")'
|
|
2152
|
+
@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
2153
|
end
|
|
2021
2154
|
|
|
2022
2155
|
specify "should support joining datasets and aliasing the join" do
|
|
2023
2156
|
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")'
|
|
2157
|
+
@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
2158
|
end
|
|
2028
2159
|
|
|
2029
2160
|
specify "should support joining multiple datasets" do
|
|
@@ -2037,43 +2168,27 @@ describe "Dataset#join_table" do
|
|
|
2037
2168
|
'RIGHT OUTER JOIN (SELECT * FROM attributes WHERE (name = \'blah\')) AS "t3" ON ("t3"."attribute_id" = "t2"."id")'
|
|
2038
2169
|
end
|
|
2039
2170
|
|
|
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")'
|
|
2046
|
-
end
|
|
2047
|
-
|
|
2048
|
-
specify "should support using a SQL String as the join condition" do
|
|
2049
|
-
@d.join(:categories, %{c.item_id = items.id}, :c).sql.should ==
|
|
2050
|
-
'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
|
2171
|
+
specify "should support using an SQL String as the join condition" do
|
|
2172
|
+
@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)'
|
|
2051
2173
|
end
|
|
2052
2174
|
|
|
2053
2175
|
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"'
|
|
2176
|
+
@d.join(:categories, :active).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
|
2056
2177
|
end
|
|
2057
2178
|
|
|
2058
2179
|
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)'
|
|
2180
|
+
@d.join(:categories, Sequel.expr(:number) > 10).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2061
2181
|
end
|
|
2062
2182
|
|
|
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"'
|
|
2183
|
+
specify "should support natural and cross joins" do
|
|
2184
|
+
@d.join_table(:natural, :categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2185
|
+
@d.join_table(:cross, :categories, nil).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2186
|
+
@d.join_table(:natural, :categories, nil, :c).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
|
2070
2187
|
end
|
|
2071
2188
|
|
|
2072
2189
|
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")'
|
|
2190
|
+
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
|
|
2191
|
+
@d.join(:categories, [:id1, :id2]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
|
2077
2192
|
end
|
|
2078
2193
|
|
|
2079
2194
|
specify "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
|
|
@@ -2081,6 +2196,12 @@ describe "Dataset#join_table" do
|
|
|
2081
2196
|
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."id" = "items"."id")'
|
|
2082
2197
|
end
|
|
2083
2198
|
|
|
2199
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
2200
|
+
@d.meta_def(:supports_cte?){true}
|
|
2201
|
+
@d.meta_def(:supports_cte_in_subselect?){false}
|
|
2202
|
+
@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")'
|
|
2203
|
+
end
|
|
2204
|
+
|
|
2084
2205
|
specify "should raise an error if using an array of symbols with a block" do
|
|
2085
2206
|
proc{@d.join(:categories, [:id]){|j,lj,js|}}.should raise_error(Sequel::Error)
|
|
2086
2207
|
end
|
|
@@ -2135,27 +2256,21 @@ describe "Dataset#join_table" do
|
|
|
2135
2256
|
end
|
|
2136
2257
|
|
|
2137
2258
|
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")'
|
|
2259
|
+
@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")'
|
|
2260
|
+
@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
2261
|
end
|
|
2143
2262
|
|
|
2144
2263
|
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"))'
|
|
2264
|
+
@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"))'
|
|
2265
|
+
@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
2266
|
end
|
|
2150
2267
|
|
|
2151
2268
|
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 ==
|
|
2269
|
+
@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")'
|
|
2270
|
+
@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
2271
|
'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2156
2272
|
end
|
|
2157
2273
|
|
|
2158
|
-
|
|
2159
2274
|
specify "should not allow insert, update, delete, or truncate" do
|
|
2160
2275
|
proc{@d.join(:categories, :a=>:d).insert_sql}.should raise_error(Sequel::InvalidOperation)
|
|
2161
2276
|
proc{@d.join(:categories, :a=>:d).update_sql(:a=>1)}.should raise_error(Sequel::InvalidOperation)
|
|
@@ -2165,86 +2280,64 @@ describe "Dataset#join_table" do
|
|
|
2165
2280
|
|
|
2166
2281
|
specify "should raise an error if an invalid option is passed" do
|
|
2167
2282
|
proc{@d.join(:c, [:id], nil)}.should raise_error(Sequel::Error)
|
|
2168
|
-
proc{@d.join(:c, [:id],
|
|
2283
|
+
proc{@d.join(:c, [:id], Sequel.qualify(:d, :c))}.should raise_error(Sequel::Error)
|
|
2169
2284
|
end
|
|
2170
2285
|
end
|
|
2171
2286
|
|
|
2172
2287
|
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
2288
|
specify "should perform an update on the specified filter" do
|
|
2188
|
-
|
|
2189
|
-
|
|
2289
|
+
db = Sequel.mock
|
|
2290
|
+
ds = db[:items]
|
|
2291
|
+
ds[:a => 1] = {:x => 3}
|
|
2292
|
+
db.sqls.should == ['UPDATE items SET x = 3 WHERE (a = 1)']
|
|
2190
2293
|
end
|
|
2191
2294
|
end
|
|
2192
2295
|
|
|
2193
2296
|
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
2297
|
specify "should act as alias to #update" do
|
|
2209
|
-
|
|
2210
|
-
|
|
2298
|
+
db = Sequel.mock
|
|
2299
|
+
ds = db[:items]
|
|
2300
|
+
ds.set({:x => 3})
|
|
2301
|
+
db.sqls.should == ['UPDATE items SET x = 3']
|
|
2211
2302
|
end
|
|
2212
2303
|
end
|
|
2213
2304
|
|
|
2214
|
-
|
|
2215
2305
|
describe "Dataset#insert_multiple" do
|
|
2216
2306
|
before do
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
def insert(arg)
|
|
2220
|
-
@inserts ||= []
|
|
2221
|
-
@inserts << arg
|
|
2222
|
-
end
|
|
2223
|
-
end
|
|
2224
|
-
|
|
2225
|
-
@d = c.new(nil)
|
|
2307
|
+
@db = Sequel.mock(:autoid=>2)
|
|
2308
|
+
@ds = @db[:items]
|
|
2226
2309
|
end
|
|
2227
2310
|
|
|
2228
2311
|
specify "should insert all items in the supplied array" do
|
|
2229
|
-
@
|
|
2230
|
-
@
|
|
2312
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}])
|
|
2313
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('aa')",
|
|
2314
|
+
"INSERT INTO items VALUES (5)",
|
|
2315
|
+
"INSERT INTO items VALUES (3)",
|
|
2316
|
+
"INSERT INTO items (a) VALUES (2)"]
|
|
2231
2317
|
end
|
|
2232
2318
|
|
|
2233
2319
|
specify "should pass array items through the supplied block if given" do
|
|
2234
|
-
|
|
2235
|
-
@
|
|
2236
|
-
|
|
2320
|
+
@ds.insert_multiple(["inevitable", "hello", "the ticking clock"]){|i| i.gsub('l', 'r')}
|
|
2321
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('inevitabre')",
|
|
2322
|
+
"INSERT INTO items VALUES ('herro')",
|
|
2323
|
+
"INSERT INTO items VALUES ('the ticking crock')"]
|
|
2324
|
+
end
|
|
2325
|
+
|
|
2326
|
+
specify "should return array of inserted ids" do
|
|
2327
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}]).should == [2, 3, 4, 5]
|
|
2328
|
+
end
|
|
2329
|
+
|
|
2330
|
+
specify "should work exactly like in metioned in the example" do
|
|
2331
|
+
@ds.insert_multiple([{:x=>1}, {:x=>2}]){|row| row[:y] = row[:x] * 2 ; row }
|
|
2332
|
+
sqls = @db.sqls
|
|
2333
|
+
["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls[0])
|
|
2334
|
+
["INSERT INTO items (x, y) VALUES (2, 4)", "INSERT INTO items (y, x) VALUES (4, 2)"].should include(sqls[1])
|
|
2237
2335
|
end
|
|
2238
2336
|
end
|
|
2239
2337
|
|
|
2240
2338
|
describe "Dataset aggregate methods" do
|
|
2241
2339
|
before do
|
|
2242
|
-
|
|
2243
|
-
def fetch_rows(sql)
|
|
2244
|
-
yield({1 => sql})
|
|
2245
|
-
end
|
|
2246
|
-
end
|
|
2247
|
-
@d = c.new(nil).from(:test)
|
|
2340
|
+
@d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
|
|
2248
2341
|
end
|
|
2249
2342
|
|
|
2250
2343
|
specify "should include min" do
|
|
@@ -2278,116 +2371,88 @@ end
|
|
|
2278
2371
|
|
|
2279
2372
|
describe "Dataset#range" do
|
|
2280
2373
|
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)
|
|
2374
|
+
@db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
|
|
2375
|
+
@ds = @db[:test]
|
|
2292
2376
|
end
|
|
2293
2377
|
|
|
2294
2378
|
specify "should generate a correct SQL statement" do
|
|
2295
|
-
@
|
|
2296
|
-
@
|
|
2379
|
+
@ds.range(:stamp)
|
|
2380
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
|
|
2297
2381
|
|
|
2298
|
-
@
|
|
2299
|
-
@
|
|
2382
|
+
@ds.filter(Sequel.expr(:price) > 100).range(:stamp)
|
|
2383
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
|
|
2300
2384
|
end
|
|
2301
2385
|
|
|
2302
2386
|
specify "should return a range object" do
|
|
2303
|
-
@
|
|
2387
|
+
@ds.range(:tryme).should == (1..10)
|
|
2304
2388
|
end
|
|
2305
2389
|
|
|
2306
2390
|
specify "should use a subselect for the same conditions as count" do
|
|
2307
|
-
@
|
|
2308
|
-
@
|
|
2391
|
+
@ds.order(:stamp).limit(5).range(:stamp).should == (1..10)
|
|
2392
|
+
@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
2393
|
end
|
|
2310
2394
|
end
|
|
2311
2395
|
|
|
2312
2396
|
describe "Dataset#interval" do
|
|
2313
2397
|
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)
|
|
2398
|
+
@db = Sequel.mock(:fetch=>{:v => 1234})
|
|
2399
|
+
@ds = @db[:test]
|
|
2325
2400
|
end
|
|
2326
2401
|
|
|
2327
|
-
specify "should generate
|
|
2328
|
-
@
|
|
2329
|
-
@
|
|
2402
|
+
specify "should generate the correct SQL statement" do
|
|
2403
|
+
@ds.interval(:stamp)
|
|
2404
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"]
|
|
2330
2405
|
|
|
2331
|
-
@
|
|
2332
|
-
@
|
|
2333
|
-
end
|
|
2334
|
-
|
|
2335
|
-
specify "should return an integer" do
|
|
2336
|
-
@d.interval(:tryme).should == 1234
|
|
2406
|
+
@ds.filter(Sequel.expr(:price) > 100).interval(:stamp)
|
|
2407
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"]
|
|
2337
2408
|
end
|
|
2338
2409
|
|
|
2339
2410
|
specify "should use a subselect for the same conditions as count" do
|
|
2340
|
-
@
|
|
2341
|
-
@
|
|
2411
|
+
@ds.order(:stamp).limit(5).interval(:stamp).should == 1234
|
|
2412
|
+
@db.sqls.should == ['SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
|
|
2342
2413
|
end
|
|
2343
2414
|
end
|
|
2344
2415
|
|
|
2345
2416
|
describe "Dataset #first and #last" do
|
|
2346
2417
|
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)
|
|
2418
|
+
@db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
|
|
2419
|
+
@d = @db[:test]
|
|
2355
2420
|
end
|
|
2356
2421
|
|
|
2357
2422
|
specify "should return a single record if no argument is given" do
|
|
2358
|
-
@d.order(:a).first.should ==
|
|
2359
|
-
@d.order(:a).last.should ==
|
|
2423
|
+
@d.order(:a).first.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
|
|
2424
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2360
2425
|
end
|
|
2361
2426
|
|
|
2362
2427
|
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 ==
|
|
2428
|
+
@d.order(:a).first(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
|
|
2429
|
+
@d.order(:a).first('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
|
|
2430
|
+
@d.order(:a).last(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1'}
|
|
2431
|
+
@d.order(:a).last('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1'}
|
|
2367
2432
|
end
|
|
2368
2433
|
|
|
2369
2434
|
specify "should set the limit and return an array of records if the given number is > 1" do
|
|
2370
2435
|
i = rand(10) + 10
|
|
2371
|
-
r = @d.order(:a).first(i).should == [
|
|
2436
|
+
r = @d.order(:a).first(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
|
|
2372
2437
|
i = rand(10) + 10
|
|
2373
|
-
r = @d.order(:a).last(i).should == [
|
|
2438
|
+
r = @d.order(:a).last(i).should == [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
|
|
2374
2439
|
end
|
|
2375
2440
|
|
|
2376
2441
|
specify "should return the first matching record if a block is given without an argument" do
|
|
2377
|
-
@d.first{
|
|
2378
|
-
@d.order(:name).last{
|
|
2442
|
+
@d.first{z > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
|
|
2443
|
+
@d.order(:name).last{z > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1'}
|
|
2379
2444
|
end
|
|
2380
2445
|
|
|
2381
2446
|
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){
|
|
2447
|
+
@d.first(:y=>25){z > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
|
|
2448
|
+
@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
2449
|
end
|
|
2385
2450
|
|
|
2386
2451
|
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
|
2387
2452
|
i = rand(10) + 10
|
|
2388
|
-
r = @d.order(:a).first(i){
|
|
2453
|
+
r = @d.order(:a).first(i){z > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
|
|
2389
2454
|
i = rand(10) + 10
|
|
2390
|
-
r = @d.order(:a).last(i){
|
|
2455
|
+
r = @d.order(:a).last(i){z > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"}]
|
|
2391
2456
|
end
|
|
2392
2457
|
|
|
2393
2458
|
specify "#last should raise if no order is given" do
|
|
@@ -2398,10 +2463,10 @@ describe "Dataset #first and #last" do
|
|
|
2398
2463
|
end
|
|
2399
2464
|
|
|
2400
2465
|
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
|
|
2466
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2467
|
+
@d.order(Sequel.desc(:b)).last.should == {:s=>'SELECT * FROM test ORDER BY b ASC LIMIT 1'}
|
|
2468
|
+
@d.order(:c, :d).last.should == {:s=>'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'}
|
|
2469
|
+
@d.order(Sequel.desc(:e), :f).last.should == {:s=>'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'}
|
|
2405
2470
|
end
|
|
2406
2471
|
end
|
|
2407
2472
|
|
|
@@ -2412,55 +2477,37 @@ describe "Dataset compound operations" do
|
|
|
2412
2477
|
end
|
|
2413
2478
|
|
|
2414
2479
|
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"
|
|
2480
|
+
@a.union(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2481
|
+
@b.union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2482
|
+
@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
2483
|
end
|
|
2422
2484
|
|
|
2423
2485
|
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"
|
|
2486
|
+
@a.intersect(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2487
|
+
@b.intersect(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2488
|
+
@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
2489
|
end
|
|
2431
2490
|
|
|
2432
2491
|
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"
|
|
2492
|
+
@a.except(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2493
|
+
@b.except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2494
|
+
@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
2495
|
end
|
|
2440
2496
|
|
|
2441
2497
|
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"
|
|
2498
|
+
@a.union(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2499
|
+
@a.intersect(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2500
|
+
@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
2501
|
end
|
|
2449
2502
|
|
|
2450
2503
|
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)"
|
|
2504
|
+
@b.union(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
|
|
2505
|
+
@b.intersect(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
|
|
2506
|
+
@b.except(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
|
|
2457
2507
|
|
|
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)"
|
|
2508
|
+
@b.union(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
|
|
2509
|
+
@b.intersect(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2510
|
+
@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
2511
|
end
|
|
2465
2512
|
|
|
2466
2513
|
specify "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
|
|
@@ -2480,141 +2527,105 @@ describe "Dataset compound operations" do
|
|
|
2480
2527
|
end
|
|
2481
2528
|
|
|
2482
2529
|
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"
|
|
2530
|
+
@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"
|
|
2531
|
+
@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"
|
|
2532
|
+
@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
2533
|
end
|
|
2490
2534
|
|
|
2491
2535
|
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"
|
|
2536
|
+
@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"
|
|
2537
|
+
@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"
|
|
2538
|
+
@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
2539
|
end
|
|
2499
2540
|
|
|
2500
2541
|
specify "should order and limit properly when using UNION, INTERSECT, or EXCEPT" do
|
|
2501
2542
|
@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"
|
|
2543
|
+
@dataset.union(@dataset).limit(2).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
|
|
2544
|
+
@dataset.limit(2).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2545
|
+
@dataset.except(@dataset.limit(2)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
|
|
2546
|
+
|
|
2547
|
+
@dataset.union(@dataset).order(:num).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
|
|
2548
|
+
@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"
|
|
2549
|
+
@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
2550
|
|
|
2516
2551
|
@dataset.limit(2).order(:a).union(@dataset.limit(3).order(:b)).order(:c).limit(4).sql.should ==
|
|
2517
2552
|
"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
2553
|
end
|
|
2519
2554
|
|
|
2555
|
+
specify "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
|
|
2556
|
+
ds = Sequel::Dataset.new(nil)
|
|
2557
|
+
ds.meta_def(:supports_cte?){true}
|
|
2558
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2559
|
+
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'
|
|
2560
|
+
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'
|
|
2561
|
+
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'
|
|
2562
|
+
end
|
|
2520
2563
|
end
|
|
2521
2564
|
|
|
2522
2565
|
describe "Dataset#[]" do
|
|
2523
2566
|
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)
|
|
2567
|
+
@db = Sequel.mock(:fetch=>{1 => 2, 3 => 4})
|
|
2568
|
+
@d = @db[:items]
|
|
2537
2569
|
end
|
|
2538
2570
|
|
|
2539
2571
|
specify "should return a single record filtered according to the given conditions" do
|
|
2540
2572
|
@d[:name => 'didi'].should == {1 => 2, 3 => 4}
|
|
2541
|
-
@
|
|
2573
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (name = 'didi') LIMIT 1"]
|
|
2542
2574
|
|
|
2543
2575
|
@d[:id => 5..45].should == {1 => 2, 3 => 4}
|
|
2544
|
-
@
|
|
2576
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((id >= 5) AND (id <= 45)) LIMIT 1"]
|
|
2545
2577
|
end
|
|
2546
2578
|
end
|
|
2547
2579
|
|
|
2548
2580
|
describe "Dataset#single_record" do
|
|
2549
2581
|
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)
|
|
2582
|
+
@db = Sequel.mock
|
|
2561
2583
|
end
|
|
2562
2584
|
|
|
2563
2585
|
specify "should call each with a limit of 1 and return the record" do
|
|
2564
|
-
@
|
|
2586
|
+
@db.fetch = {:a=>1}
|
|
2587
|
+
@db[:test].single_record.should == {:a=>1}
|
|
2588
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2565
2589
|
end
|
|
2566
2590
|
|
|
2567
2591
|
specify "should return nil if no record is present" do
|
|
2568
|
-
@
|
|
2592
|
+
@db[:test].single_record.should be_nil
|
|
2593
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2569
2594
|
end
|
|
2570
2595
|
end
|
|
2571
2596
|
|
|
2572
2597
|
describe "Dataset#single_value" do
|
|
2573
2598
|
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)
|
|
2599
|
+
@db = Sequel.mock
|
|
2585
2600
|
end
|
|
2586
2601
|
|
|
2587
2602
|
specify "should call each and return the first value of the first record" do
|
|
2588
|
-
@
|
|
2603
|
+
@db.fetch = {:a=>1}
|
|
2604
|
+
@db[:test].single_value.should == 1
|
|
2605
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2589
2606
|
end
|
|
2590
2607
|
|
|
2591
2608
|
specify "should return nil if no records" do
|
|
2592
|
-
@
|
|
2609
|
+
@db[:test].single_value.should be_nil
|
|
2610
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2593
2611
|
end
|
|
2594
2612
|
|
|
2595
2613
|
it "should work on a graphed_dataset" do
|
|
2596
|
-
@
|
|
2597
|
-
@
|
|
2614
|
+
@db.fetch = {:a=>1}
|
|
2615
|
+
ds = @db[:test].columns(:a)
|
|
2616
|
+
ds.graph(ds, [:a], :table_alias=>:test2).single_value.should == 1
|
|
2617
|
+
@db.sqls.should == ['SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
2598
2618
|
end
|
|
2599
2619
|
end
|
|
2600
2620
|
|
|
2601
2621
|
describe "Dataset#get" do
|
|
2602
2622
|
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)
|
|
2623
|
+
@d = Sequel.mock(:fetch=>proc{|s| {:name=>s}})[:test]
|
|
2613
2624
|
end
|
|
2614
2625
|
|
|
2615
2626
|
specify "should select the specified column and fetch its value" do
|
|
2616
2627
|
@d.get(:name).should == "SELECT name FROM test LIMIT 1"
|
|
2617
|
-
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2628
|
+
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2618
2629
|
end
|
|
2619
2630
|
|
|
2620
2631
|
specify "should work with filters" do
|
|
@@ -2622,7 +2633,7 @@ describe "Dataset#get" do
|
|
|
2622
2633
|
end
|
|
2623
2634
|
|
|
2624
2635
|
specify "should work with aliased fields" do
|
|
2625
|
-
@d.get(:x__b.as(:name)).should == "SELECT x.b AS name FROM test LIMIT 1"
|
|
2636
|
+
@d.get(Sequel.expr(:x__b).as(:name)).should == "SELECT x.b AS name FROM test LIMIT 1"
|
|
2626
2637
|
end
|
|
2627
2638
|
|
|
2628
2639
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -2633,243 +2644,253 @@ describe "Dataset#get" do
|
|
|
2633
2644
|
specify "should raise an error if both a regular argument and block argument are used" do
|
|
2634
2645
|
proc{@d.get(:name){|o| o.x__b.as(:name)}}.should raise_error(Sequel::Error)
|
|
2635
2646
|
end
|
|
2647
|
+
|
|
2648
|
+
specify "should support false and nil values" do
|
|
2649
|
+
@d.get(false).should == "SELECT 'f' FROM test LIMIT 1"
|
|
2650
|
+
@d.get(nil).should == "SELECT NULL FROM test LIMIT 1"
|
|
2651
|
+
end
|
|
2636
2652
|
end
|
|
2637
2653
|
|
|
2638
2654
|
describe "Dataset#set_row_proc" do
|
|
2639
2655
|
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)
|
|
2656
|
+
@db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
|
|
2657
|
+
@dataset = @db[:items]
|
|
2658
|
+
@dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
|
|
2647
2659
|
end
|
|
2648
2660
|
|
|
2649
2661
|
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
2662
|
rows = @dataset.all
|
|
2653
|
-
rows.
|
|
2654
|
-
|
|
2655
|
-
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
|
2663
|
+
rows.map{|h| h[:der]}.should == [3, 4]
|
|
2664
|
+
@db.sqls.should == ['SELECT * FROM items']
|
|
2656
2665
|
end
|
|
2657
2666
|
|
|
2658
2667
|
specify "should be copied over when dataset is cloned" do
|
|
2659
|
-
@dataset.
|
|
2660
|
-
|
|
2661
|
-
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
|
2668
|
+
@dataset.filter(:a => 1).all.should == [{:a=>1, :der=>3}, {:a=>2, :der=>4}]
|
|
2662
2669
|
end
|
|
2663
2670
|
end
|
|
2664
2671
|
|
|
2665
2672
|
describe "Dataset#<<" do
|
|
2666
2673
|
before do
|
|
2667
|
-
@
|
|
2668
|
-
@d.meta_def(:insert) do |*args|
|
|
2669
|
-
1234567890
|
|
2670
|
-
end
|
|
2674
|
+
@db = Sequel.mock
|
|
2671
2675
|
end
|
|
2672
|
-
|
|
2676
|
+
|
|
2673
2677
|
specify "should call #insert" do
|
|
2674
|
-
|
|
2678
|
+
@db[:items] << {:name => 1}
|
|
2679
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)']
|
|
2680
|
+
end
|
|
2681
|
+
|
|
2682
|
+
specify "should be chainable" do
|
|
2683
|
+
@db[:items] << {:name => 1} << @db[:old_items].select(:name)
|
|
2684
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)', 'INSERT INTO items SELECT name FROM old_items']
|
|
2675
2685
|
end
|
|
2676
2686
|
end
|
|
2677
2687
|
|
|
2678
2688
|
describe "Dataset#columns" do
|
|
2679
2689
|
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}
|
|
2690
|
+
@dataset = Sequel.mock[:items]
|
|
2684
2691
|
end
|
|
2685
2692
|
|
|
2686
2693
|
specify "should return the value of @columns if @columns is not nil" do
|
|
2687
|
-
@dataset.columns
|
|
2688
|
-
@dataset.
|
|
2694
|
+
@dataset.columns(:a, :b, :c).columns.should == [:a, :b, :c]
|
|
2695
|
+
@dataset.db.sqls.should == []
|
|
2689
2696
|
end
|
|
2690
2697
|
|
|
2691
2698
|
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
|
-
|
|
2699
|
+
@dataset.db.columns = [:a]
|
|
2700
|
+
@dataset.columns.should == [:a]
|
|
2701
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2702
|
+
end
|
|
2703
|
+
|
|
2704
|
+
specify "should be cleared if you change the selected columns" do
|
|
2705
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2706
|
+
@dataset.columns.should == [:a]
|
|
2707
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2708
|
+
@dataset.columns.should == [:a]
|
|
2709
|
+
@dataset.db.sqls.should == []
|
|
2710
|
+
ds = @dataset.select{foo{}}
|
|
2711
|
+
ds.columns.should == [:b]
|
|
2712
|
+
@dataset.db.sqls.should == ['SELECT foo() FROM items LIMIT 1']
|
|
2713
|
+
end
|
|
2714
|
+
|
|
2715
|
+
specify "should be cleared if you change the FROM table" do
|
|
2716
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2717
|
+
@dataset.columns.should == [:a]
|
|
2718
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2719
|
+
ds = @dataset.from(:foo)
|
|
2720
|
+
ds.columns.should == [:b]
|
|
2721
|
+
@dataset.db.sqls.should == ['SELECT * FROM foo LIMIT 1']
|
|
2722
|
+
end
|
|
2723
|
+
|
|
2724
|
+
specify "should be cleared if you join a table to the dataset" do
|
|
2725
|
+
@dataset.db.columns = [[:a], [:a, :b]]
|
|
2726
|
+
@dataset.columns.should == [:a]
|
|
2727
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2728
|
+
ds = @dataset.cross_join(:foo)
|
|
2729
|
+
ds.columns.should == [:a, :b]
|
|
2730
|
+
@dataset.db.sqls.should == ['SELECT * FROM items CROSS JOIN foo LIMIT 1']
|
|
2731
|
+
end
|
|
2732
|
+
|
|
2733
|
+
specify "should be cleared if you set custom SQL for the dataset" do
|
|
2734
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2735
|
+
@dataset.columns.should == [:a]
|
|
2736
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2737
|
+
ds = @dataset.with_sql('SELECT b FROM foo')
|
|
2738
|
+
ds.columns.should == [:b]
|
|
2739
|
+
@dataset.db.sqls.should == ['SELECT b FROM foo']
|
|
2696
2740
|
end
|
|
2697
2741
|
|
|
2698
2742
|
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
|
2743
|
+
@dataset.db.columns = [:a]
|
|
2699
2744
|
@dataset.filter!(:b=>100).order!(:b).distinct!
|
|
2700
|
-
@dataset.columns
|
|
2701
|
-
@dataset.
|
|
2745
|
+
@dataset.columns.should == [:a]
|
|
2746
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2702
2747
|
end
|
|
2703
2748
|
end
|
|
2704
2749
|
|
|
2705
2750
|
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
2751
|
specify "should always attempt to get a record and return @columns" do
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2752
|
+
ds = Sequel.mock(:columns=>[[:a, :b, :c], [:d, :e, :f]])[:items]
|
|
2753
|
+
ds.columns!.should == [:a, :b, :c]
|
|
2754
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2755
|
+
ds.columns!.should == [:d, :e, :f]
|
|
2756
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2717
2757
|
end
|
|
2718
2758
|
end
|
|
2719
2759
|
|
|
2720
2760
|
describe "Dataset#import" do
|
|
2721
2761
|
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'}]
|
|
2762
|
+
@db = Sequel.mock
|
|
2763
|
+
@ds = @db[:items]
|
|
2743
2764
|
end
|
|
2744
2765
|
|
|
2766
|
+
specify "should return nil without a query if no values" do
|
|
2767
|
+
@ds.import(['x', 'y'], []).should == nil
|
|
2768
|
+
@db.sqls.should == []
|
|
2769
|
+
end
|
|
2770
|
+
|
|
2745
2771
|
specify "should accept string keys as column names" do
|
|
2746
2772
|
@ds.import(['x', 'y'], [[1, 2], [3, 4]])
|
|
2747
|
-
@db.sqls.should == [
|
|
2748
|
-
'BEGIN',
|
|
2773
|
+
@db.sqls.should == ['BEGIN',
|
|
2749
2774
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2750
2775
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2751
|
-
'COMMIT'
|
|
2752
|
-
]
|
|
2776
|
+
'COMMIT']
|
|
2753
2777
|
end
|
|
2754
2778
|
|
|
2755
2779
|
specify "should accept a columns array and a values array" do
|
|
2756
2780
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
2757
|
-
@db.sqls.should == [
|
|
2758
|
-
'BEGIN',
|
|
2781
|
+
@db.sqls.should == ['BEGIN',
|
|
2759
2782
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2760
2783
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2761
|
-
'COMMIT'
|
|
2762
|
-
]
|
|
2784
|
+
'COMMIT']
|
|
2763
2785
|
end
|
|
2764
2786
|
|
|
2765
2787
|
specify "should accept a columns array and a dataset" do
|
|
2766
|
-
@ds2 =
|
|
2788
|
+
@ds2 = @ds.from(:cats).filter(:purr => true).select(:a, :b)
|
|
2767
2789
|
|
|
2768
2790
|
@ds.import([:x, :y], @ds2)
|
|
2769
|
-
@db.sqls.should == [
|
|
2770
|
-
'BEGIN',
|
|
2791
|
+
@db.sqls.should == ['BEGIN',
|
|
2771
2792
|
"INSERT INTO items (x, y) SELECT a, b FROM cats WHERE (purr IS TRUE)",
|
|
2772
|
-
'COMMIT'
|
|
2773
|
-
]
|
|
2793
|
+
'COMMIT']
|
|
2774
2794
|
end
|
|
2775
2795
|
|
|
2776
2796
|
specify "should accept a columns array and a values array with :commit_every option" do
|
|
2777
2797
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 3)
|
|
2778
|
-
@db.sqls.should == [
|
|
2779
|
-
'BEGIN',
|
|
2798
|
+
@db.sqls.should == ['BEGIN',
|
|
2780
2799
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2781
2800
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2782
2801
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2783
|
-
'COMMIT'
|
|
2784
|
-
]
|
|
2802
|
+
'COMMIT']
|
|
2785
2803
|
end
|
|
2786
|
-
specify "should accept a columns array and a values array with slice option" do
|
|
2804
|
+
specify "should accept a columns array and a values array with :slice option" do
|
|
2787
2805
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
|
2788
|
-
@db.sqls.should == [
|
|
2789
|
-
'BEGIN',
|
|
2806
|
+
@db.sqls.should == ['BEGIN',
|
|
2790
2807
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2791
2808
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2792
2809
|
'COMMIT',
|
|
2793
2810
|
'BEGIN',
|
|
2794
2811
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2795
|
-
'COMMIT'
|
|
2796
|
-
]
|
|
2812
|
+
'COMMIT']
|
|
2797
2813
|
end
|
|
2798
2814
|
end
|
|
2799
2815
|
|
|
2800
2816
|
describe "Dataset#multi_insert" do
|
|
2801
2817
|
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
|
-
|
|
2818
|
+
@db = Sequel.mock(:servers=>{:s1=>{}})
|
|
2819
|
+
@ds = @db[:items]
|
|
2822
2820
|
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
|
2823
2821
|
end
|
|
2824
2822
|
|
|
2823
|
+
specify "should return nil without a query if no values" do
|
|
2824
|
+
@ds.multi_insert([]).should == nil
|
|
2825
|
+
@db.sqls.should == []
|
|
2826
|
+
end
|
|
2827
|
+
|
|
2825
2828
|
specify "should issue multiple insert statements inside a transaction" do
|
|
2826
2829
|
@ds.multi_insert(@list)
|
|
2827
|
-
@db.sqls.should == [
|
|
2828
|
-
'BEGIN',
|
|
2830
|
+
@db.sqls.should == ['BEGIN',
|
|
2829
2831
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2830
2832
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2831
2833
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2832
|
-
'COMMIT'
|
|
2833
|
-
|
|
2834
|
+
'COMMIT']
|
|
2835
|
+
end
|
|
2836
|
+
|
|
2837
|
+
specify "should respect :server option" do
|
|
2838
|
+
@ds.multi_insert(@list, :server=>:s1)
|
|
2839
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2840
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2841
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2842
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2843
|
+
'COMMIT -- s1']
|
|
2844
|
+
end
|
|
2845
|
+
|
|
2846
|
+
specify "should respect existing :server option on dataset" do
|
|
2847
|
+
@ds.server(:s1).multi_insert(@list)
|
|
2848
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2849
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2850
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2851
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2852
|
+
'COMMIT -- s1']
|
|
2853
|
+
end
|
|
2854
|
+
|
|
2855
|
+
specify "should respect :return=>:primary_key option" do
|
|
2856
|
+
@db.autoid = 1
|
|
2857
|
+
@ds.multi_insert(@list, :return=>:primary_key).should == [1, 2, 3]
|
|
2858
|
+
@db.sqls.should == ['BEGIN',
|
|
2859
|
+
"INSERT INTO items (name) VALUES ('abc')",
|
|
2860
|
+
"INSERT INTO items (name) VALUES ('def')",
|
|
2861
|
+
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2862
|
+
'COMMIT']
|
|
2834
2863
|
end
|
|
2835
2864
|
|
|
2836
2865
|
specify "should handle different formats for tables" do
|
|
2837
2866
|
@ds = @ds.from(:sch__tab)
|
|
2838
2867
|
@ds.multi_insert(@list)
|
|
2839
|
-
@db.sqls.should == [
|
|
2840
|
-
'BEGIN',
|
|
2868
|
+
@db.sqls.should == ['BEGIN',
|
|
2841
2869
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2842
2870
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2843
2871
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2844
|
-
'COMMIT'
|
|
2845
|
-
]
|
|
2846
|
-
@db.sqls.clear
|
|
2872
|
+
'COMMIT']
|
|
2847
2873
|
|
|
2848
|
-
@ds = @ds.from(
|
|
2874
|
+
@ds = @ds.from(Sequel.qualify(:sch, :tab))
|
|
2849
2875
|
@ds.multi_insert(@list)
|
|
2850
|
-
@db.sqls.should == [
|
|
2851
|
-
'BEGIN',
|
|
2876
|
+
@db.sqls.should == ['BEGIN',
|
|
2852
2877
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2853
2878
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2854
2879
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2855
|
-
'COMMIT'
|
|
2856
|
-
|
|
2857
|
-
@
|
|
2858
|
-
@ds = @ds.from(:sch__tab.identifier)
|
|
2880
|
+
'COMMIT']
|
|
2881
|
+
|
|
2882
|
+
@ds = @ds.from(Sequel.identifier(:sch__tab))
|
|
2859
2883
|
@ds.multi_insert(@list)
|
|
2860
|
-
@db.sqls.should == [
|
|
2861
|
-
'BEGIN',
|
|
2884
|
+
@db.sqls.should == ['BEGIN',
|
|
2862
2885
|
"INSERT INTO sch__tab (name) VALUES ('abc')",
|
|
2863
2886
|
"INSERT INTO sch__tab (name) VALUES ('def')",
|
|
2864
2887
|
"INSERT INTO sch__tab (name) VALUES ('ghi')",
|
|
2865
|
-
'COMMIT'
|
|
2866
|
-
]
|
|
2888
|
+
'COMMIT']
|
|
2867
2889
|
end
|
|
2868
2890
|
|
|
2869
2891
|
specify "should accept the :commit_every option for committing every x records" do
|
|
2870
2892
|
@ds.multi_insert(@list, :commit_every => 1)
|
|
2871
|
-
@db.sqls.should == [
|
|
2872
|
-
'BEGIN',
|
|
2893
|
+
@db.sqls.should == ['BEGIN',
|
|
2873
2894
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2874
2895
|
'COMMIT',
|
|
2875
2896
|
'BEGIN',
|
|
@@ -2877,36 +2898,31 @@ describe "Dataset#multi_insert" do
|
|
|
2877
2898
|
'COMMIT',
|
|
2878
2899
|
'BEGIN',
|
|
2879
2900
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2880
|
-
'COMMIT'
|
|
2881
|
-
]
|
|
2901
|
+
'COMMIT']
|
|
2882
2902
|
end
|
|
2883
2903
|
|
|
2884
2904
|
specify "should accept the :slice option for committing every x records" do
|
|
2885
2905
|
@ds.multi_insert(@list, :slice => 2)
|
|
2886
|
-
@db.sqls.should == [
|
|
2887
|
-
'BEGIN',
|
|
2906
|
+
@db.sqls.should == ['BEGIN',
|
|
2888
2907
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2889
2908
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2890
2909
|
'COMMIT',
|
|
2891
2910
|
'BEGIN',
|
|
2892
2911
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2893
|
-
'COMMIT'
|
|
2894
|
-
]
|
|
2912
|
+
'COMMIT']
|
|
2895
2913
|
end
|
|
2896
2914
|
|
|
2897
2915
|
specify "should accept string keys as column names" do
|
|
2898
2916
|
@ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
|
|
2899
|
-
@db.sqls
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
'COMMIT'
|
|
2904
|
-
]
|
|
2917
|
+
sqls = @db.sqls
|
|
2918
|
+
["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls.slice!(1))
|
|
2919
|
+
["INSERT INTO items (x, y) VALUES (3, 4)", "INSERT INTO items (y, x) VALUES (4, 3)"].should include(sqls.slice!(1))
|
|
2920
|
+
sqls.should == ['BEGIN', 'COMMIT']
|
|
2905
2921
|
end
|
|
2906
2922
|
|
|
2907
2923
|
specify "should not do anything if no hashes are provided" do
|
|
2908
2924
|
@ds.multi_insert([])
|
|
2909
|
-
@db.sqls.should
|
|
2925
|
+
@db.sqls.should == []
|
|
2910
2926
|
end
|
|
2911
2927
|
end
|
|
2912
2928
|
|
|
@@ -2936,7 +2952,7 @@ describe "Dataset" do
|
|
|
2936
2952
|
end
|
|
2937
2953
|
|
|
2938
2954
|
specify "should support self-changing filter! with block" do
|
|
2939
|
-
@d.filter!{
|
|
2955
|
+
@d.filter!{y < 2}
|
|
2940
2956
|
@d.sql.should == "SELECT * FROM x WHERE (y < 2)"
|
|
2941
2957
|
end
|
|
2942
2958
|
|
|
@@ -2951,41 +2967,21 @@ describe "Dataset" do
|
|
|
2951
2967
|
end
|
|
2952
2968
|
|
|
2953
2969
|
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"
|
|
2970
|
+
@d.order!(:y).filter!(:y => 1).sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
|
2957
2971
|
end
|
|
2958
2972
|
end
|
|
2959
2973
|
|
|
2960
2974
|
describe "Dataset#to_csv" do
|
|
2961
2975
|
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} ]
|
|
2976
|
+
@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
2977
|
end
|
|
2980
2978
|
|
|
2981
2979
|
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"
|
|
2980
|
+
@ds.to_csv.should == "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2984
2981
|
end
|
|
2985
2982
|
|
|
2986
2983
|
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"
|
|
2984
|
+
@ds.to_csv(false).should == "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2989
2985
|
end
|
|
2990
2986
|
end
|
|
2991
2987
|
|
|
@@ -3007,7 +3003,7 @@ describe "Dataset#update_sql" do
|
|
|
3007
3003
|
end
|
|
3008
3004
|
|
|
3009
3005
|
specify "should accept array subscript references" do
|
|
3010
|
-
@ds.update_sql((:day
|
|
3006
|
+
@ds.update_sql((Sequel.subscript(:day, 1)) => 'd').should == "UPDATE items SET day[1] = 'd'"
|
|
3011
3007
|
end
|
|
3012
3008
|
end
|
|
3013
3009
|
|
|
@@ -3025,7 +3021,7 @@ describe "Dataset#insert_sql" do
|
|
|
3025
3021
|
end
|
|
3026
3022
|
|
|
3027
3023
|
specify "should accept array subscript references" do
|
|
3028
|
-
@ds.insert_sql((:day
|
|
3024
|
+
@ds.insert_sql((Sequel.subscript(:day, 1)) => 'd').should == "INSERT INTO items (day[1]) VALUES ('d')"
|
|
3029
3025
|
end
|
|
3030
3026
|
|
|
3031
3027
|
specify "should raise an Error if the dataset has no sources" do
|
|
@@ -3063,164 +3059,117 @@ describe "Dataset#insert_sql" do
|
|
|
3063
3059
|
end
|
|
3064
3060
|
|
|
3065
3061
|
specify "should accept a single LiteralString" do
|
|
3066
|
-
@ds.insert_sql('VALUES (1, 2, 3)'
|
|
3062
|
+
@ds.insert_sql(Sequel.lit('VALUES (1, 2, 3)')).should == "INSERT INTO items VALUES (1, 2, 3)"
|
|
3067
3063
|
end
|
|
3068
3064
|
|
|
3069
3065
|
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')"
|
|
3066
|
+
@ds.insert_sql([:a, :b, :c], Sequel.lit('VALUES (1, 2, 3)')).should == "INSERT INTO items (a, b, c) VALUES (1, 2, 3)"
|
|
3083
3067
|
end
|
|
3084
3068
|
end
|
|
3085
3069
|
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
true
|
|
3070
|
+
describe "Dataset#inspect" do
|
|
3071
|
+
before do
|
|
3072
|
+
class ::InspectDataset < Sequel::Dataset; end
|
|
3090
3073
|
end
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
class DummyMummyDatabase < Sequel::Database
|
|
3094
|
-
attr_reader :sqls
|
|
3095
|
-
|
|
3096
|
-
def execute(sql)
|
|
3097
|
-
@sqls ||= []
|
|
3098
|
-
@sqls << sql
|
|
3074
|
+
after do
|
|
3075
|
+
Object.send(:remove_const, :InspectDataset) if defined?(::InspectDataset)
|
|
3099
3076
|
end
|
|
3100
|
-
|
|
3101
|
-
def transaction; yield; end
|
|
3102
3077
|
|
|
3103
|
-
|
|
3104
|
-
|
|
3078
|
+
specify "should include the class name and the corresponding SQL statement" do
|
|
3079
|
+
Sequel::Dataset.new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
3080
|
+
InspectDataset.new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3105
3081
|
end
|
|
3106
|
-
end
|
|
3107
3082
|
|
|
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]
|
|
3083
|
+
specify "should skip anonymous classes" do
|
|
3084
|
+
Class.new(Class.new(Sequel::Dataset)).new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
3085
|
+
Class.new(InspectDataset).new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3115
3086
|
end
|
|
3116
3087
|
end
|
|
3117
3088
|
|
|
3118
3089
|
describe "Dataset#all" do
|
|
3119
3090
|
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)
|
|
3091
|
+
@dataset = Sequel.mock(:fetch=>[{:x => 1, :y => 2}, {:x => 3, :y => 4}])[:items]
|
|
3128
3092
|
end
|
|
3129
3093
|
|
|
3130
3094
|
specify "should return an array with all records" do
|
|
3131
|
-
@dataset.all.should == [
|
|
3132
|
-
|
|
3133
|
-
{:x => 3, :y => 4},
|
|
3134
|
-
"SELECT * FROM items"
|
|
3135
|
-
]
|
|
3095
|
+
@dataset.all.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3096
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3136
3097
|
end
|
|
3137
3098
|
|
|
3138
3099
|
specify "should iterate over the array if a block is given" do
|
|
3139
3100
|
a = []
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
end
|
|
3144
|
-
|
|
3145
|
-
a.should == [1, 3, "SELECT * FROM items"]
|
|
3101
|
+
@dataset.all{|r| a << r.values_at(:x, :y)}.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3102
|
+
a.should == [[1, 2], [3, 4]]
|
|
3103
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3146
3104
|
end
|
|
3147
3105
|
end
|
|
3148
3106
|
|
|
3149
3107
|
describe "Dataset#grep" do
|
|
3150
3108
|
before do
|
|
3151
|
-
@ds = Sequel
|
|
3109
|
+
@ds = Sequel.mock[:posts]
|
|
3152
3110
|
end
|
|
3153
3111
|
|
|
3154
3112
|
specify "should format a SQL filter correctly" do
|
|
3155
|
-
@ds.grep(:title, 'ruby').sql.should ==
|
|
3156
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3113
|
+
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3157
3114
|
end
|
|
3158
3115
|
|
|
3159
3116
|
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'))"
|
|
3117
|
+
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
|
3162
3118
|
end
|
|
3163
3119
|
|
|
3164
3120
|
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'))"
|
|
3121
|
+
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
|
3167
3122
|
end
|
|
3168
3123
|
|
|
3169
3124
|
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'))"
|
|
3125
|
+
@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
3126
|
end
|
|
3173
3127
|
|
|
3174
3128
|
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')))"
|
|
3129
|
+
@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
3130
|
end
|
|
3178
3131
|
|
|
3179
3132
|
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')))"
|
|
3133
|
+
@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
3134
|
end
|
|
3183
3135
|
|
|
3184
3136
|
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'))"
|
|
3137
|
+
@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
3138
|
end
|
|
3188
3139
|
|
|
3189
3140
|
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'))"
|
|
3141
|
+
@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
3142
|
end
|
|
3193
3143
|
|
|
3194
3144
|
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')))"
|
|
3145
|
+
@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
3146
|
end
|
|
3198
3147
|
|
|
3199
3148
|
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')))"
|
|
3149
|
+
@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
3150
|
end
|
|
3203
3151
|
|
|
3204
3152
|
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'))"
|
|
3153
|
+
@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
3154
|
end
|
|
3208
3155
|
|
|
3209
|
-
specify "should support regexps
|
|
3210
|
-
@ds.grep(:title, /ruby/).sql.should
|
|
3211
|
-
|
|
3156
|
+
specify "should not support regexps if the database doesn't supports it" do
|
|
3157
|
+
proc{@ds.grep(:title, /ruby/).sql}.should raise_error(Sequel::InvalidOperation)
|
|
3158
|
+
proc{@ds.grep(:title, [/^ruby/, 'ruby']).sql}.should raise_error(Sequel::InvalidOperation)
|
|
3159
|
+
end
|
|
3212
3160
|
|
|
3213
|
-
|
|
3214
|
-
|
|
3161
|
+
specify "should support regexps if the database supports it" do
|
|
3162
|
+
def @ds.supports_regexp?; true end
|
|
3163
|
+
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
|
3164
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
|
3215
3165
|
end
|
|
3216
3166
|
|
|
3217
3167
|
specify "should support searching against other columns" do
|
|
3218
|
-
@ds.grep(:title, :body).sql.should ==
|
|
3219
|
-
"SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3168
|
+
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3220
3169
|
end
|
|
3221
3170
|
end
|
|
3222
3171
|
|
|
3223
|
-
describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #execute" do
|
|
3172
|
+
describe "Dataset default #fetch_rows, #insert, #update, #delete, #with_sql_delete, #truncate, #execute" do
|
|
3224
3173
|
before do
|
|
3225
3174
|
@db = Sequel::Database.new
|
|
3226
3175
|
@ds = @db[:items]
|
|
@@ -3237,6 +3186,14 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3237
3186
|
@ds.delete
|
|
3238
3187
|
end
|
|
3239
3188
|
|
|
3189
|
+
specify "#with_sql_delete should execute delete SQL" do
|
|
3190
|
+
sql = 'DELETE FROM foo'
|
|
3191
|
+
@db.should_receive(:execute).once.with(sql, :server=>:default)
|
|
3192
|
+
@ds.with_sql_delete(sql)
|
|
3193
|
+
@db.should_receive(:execute_dui).once.with(sql, :server=>:default)
|
|
3194
|
+
@ds.with_sql_delete(sql)
|
|
3195
|
+
end
|
|
3196
|
+
|
|
3240
3197
|
specify "#insert should execute insert SQL" do
|
|
3241
3198
|
@db.should_receive(:execute).once.with('INSERT INTO items DEFAULT VALUES', :server=>:default)
|
|
3242
3199
|
@ds.insert([])
|
|
@@ -3260,6 +3217,7 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3260
3217
|
|
|
3261
3218
|
specify "#truncate should raise an InvalidOperation exception if the dataset is filtered" do
|
|
3262
3219
|
proc{@ds.filter(:a=>1).truncate}.should raise_error(Sequel::InvalidOperation)
|
|
3220
|
+
proc{@ds.having(:a=>1).truncate}.should raise_error(Sequel::InvalidOperation)
|
|
3263
3221
|
end
|
|
3264
3222
|
|
|
3265
3223
|
specify "#execute should execute the SQL on the database" do
|
|
@@ -3270,58 +3228,80 @@ end
|
|
|
3270
3228
|
|
|
3271
3229
|
describe "Dataset prepared statements and bound variables " do
|
|
3272
3230
|
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
|
|
3231
|
+
@db = Sequel.mock
|
|
3285
3232
|
@ds = @db[:items]
|
|
3233
|
+
@ds.meta_def(:insert_sql){|*v| "#{super(*v)}#{' RETURNING *' if opts.has_key?(:returning)}" }
|
|
3286
3234
|
end
|
|
3287
3235
|
|
|
3288
3236
|
specify "#call should take a type and bind hash and interpolate it" do
|
|
3237
|
+
@ds.filter(:num=>:$n).call(:each, :n=>1)
|
|
3289
3238
|
@ds.filter(:num=>:$n).call(:select, :n=>1)
|
|
3239
|
+
@ds.filter(:num=>:$n).call([:map, :a], :n=>1)
|
|
3240
|
+
@ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
|
|
3241
|
+
@ds.filter(:num=>:$n).call([:to_hash_groups, :a, :b], :n=>1)
|
|
3290
3242
|
@ds.filter(:num=>:$n).call(:first, :n=>1)
|
|
3291
3243
|
@ds.filter(:num=>:$n).call(:delete, :n=>1)
|
|
3292
3244
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
|
3293
3245
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
|
3294
|
-
@
|
|
3246
|
+
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
|
3247
|
+
@db.sqls.should == [
|
|
3248
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3249
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3250
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3251
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3252
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3295
3253
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3296
3254
|
'DELETE FROM items WHERE (num = 1)',
|
|
3297
3255
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3298
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3256
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3257
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3299
3258
|
end
|
|
3300
3259
|
|
|
3301
3260
|
specify "#prepare should take a type and name and store it in the database for later use with call" do
|
|
3302
3261
|
pss = []
|
|
3262
|
+
pss << @ds.filter(:num=>:$n).prepare(:each, :en)
|
|
3303
3263
|
pss << @ds.filter(:num=>:$n).prepare(:select, :sn)
|
|
3264
|
+
pss << @ds.filter(:num=>:$n).prepare([:map, :a], :sm)
|
|
3265
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
|
|
3266
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash_groups, :a, :b], :shg)
|
|
3304
3267
|
pss << @ds.filter(:num=>:$n).prepare(:first, :fn)
|
|
3305
3268
|
pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
|
|
3306
3269
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
|
3307
3270
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
|
3308
|
-
@
|
|
3309
|
-
[:
|
|
3271
|
+
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
|
3272
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :en, :fn, :in, :ins, :sh, :shg, :sm, :sn, :un]
|
|
3273
|
+
[:en, :sn, :sm, :sh, :shg, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3274
|
+
@db.call(:en, :n=>1){}
|
|
3310
3275
|
@db.call(:sn, :n=>1)
|
|
3276
|
+
@db.call(:sm, :n=>1)
|
|
3277
|
+
@db.call(:sh, :n=>1)
|
|
3278
|
+
@db.call(:shg, :n=>1)
|
|
3311
3279
|
@db.call(:fn, :n=>1)
|
|
3312
3280
|
@db.call(:dn, :n=>1)
|
|
3313
3281
|
@db.call(:un, :n=>1, :n2=>2)
|
|
3314
3282
|
@db.call(:in, :n=>1)
|
|
3315
|
-
@db.
|
|
3283
|
+
@db.call(:ins, :n=>1)
|
|
3284
|
+
@db.sqls.should == [
|
|
3285
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3286
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3287
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3288
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3289
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3316
3290
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3317
3291
|
'DELETE FROM items WHERE (num = 1)',
|
|
3318
3292
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3319
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3293
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3294
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3320
3295
|
end
|
|
3321
3296
|
|
|
3297
|
+
specify "#call should default to using :all if an invalid type is given" do
|
|
3298
|
+
@ds.filter(:num=>:$n).call(:select_all, :n=>1)
|
|
3299
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3300
|
+
end
|
|
3301
|
+
|
|
3322
3302
|
specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
|
|
3323
3303
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
|
3324
|
-
'<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3304
|
+
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3325
3305
|
end
|
|
3326
3306
|
|
|
3327
3307
|
specify "should handle literal strings" do
|
|
@@ -3329,6 +3309,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3329
3309
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3330
3310
|
end
|
|
3331
3311
|
|
|
3312
|
+
specify "should handle columns on prepared statements correctly" do
|
|
3313
|
+
@db.columns = [:num]
|
|
3314
|
+
@ds.meta_def(:select_where_sql){|sql| super(sql); sql << " OR #{columns.first} = 1" if opts[:where]}
|
|
3315
|
+
@ds.filter(:num=>:$n).prepare(:select, :sn).sql.should == 'SELECT * FROM items WHERE (num = $n) OR num = 1'
|
|
3316
|
+
@db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
3317
|
+
end
|
|
3318
|
+
|
|
3332
3319
|
specify "should handle datasets using static sql and placeholders" do
|
|
3333
3320
|
@db["SELECT * FROM items WHERE (num = ?)", :$n].call(:select, :n=>1)
|
|
3334
3321
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
@@ -3357,23 +3344,16 @@ end
|
|
|
3357
3344
|
|
|
3358
3345
|
describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3359
3346
|
before do
|
|
3360
|
-
@db = Sequel
|
|
3361
|
-
@db.meta_def(:sqls){@sqls||=[]}
|
|
3362
|
-
def @db.execute(sql, opts={})
|
|
3363
|
-
sqls << [sql, *opts[:arguments]]
|
|
3364
|
-
end
|
|
3347
|
+
@db = Sequel.mock
|
|
3365
3348
|
@ds = @db[:items].filter(:num=>:$n)
|
|
3366
|
-
def @ds.fetch_rows(sql, &block)
|
|
3367
|
-
execute(sql)
|
|
3368
|
-
end
|
|
3369
3349
|
def @ds.execute(sql, opts={}, &block)
|
|
3370
|
-
|
|
3350
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3371
3351
|
end
|
|
3372
|
-
def @ds.execute_dui(
|
|
3373
|
-
|
|
3352
|
+
def @ds.execute_dui(sql, opts={}, &block)
|
|
3353
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3374
3354
|
end
|
|
3375
|
-
def @ds.execute_insert(
|
|
3376
|
-
|
|
3355
|
+
def @ds.execute_insert(sql, opts={}, &block)
|
|
3356
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3377
3357
|
end
|
|
3378
3358
|
@ps = []
|
|
3379
3359
|
@ps << @ds.prepare(:select, :s)
|
|
@@ -3386,64 +3366,51 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
|
3386
3366
|
end
|
|
3387
3367
|
|
|
3388
3368
|
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 = ?)">'
|
|
3369
|
+
@ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
|
3390
3370
|
end
|
|
3391
3371
|
|
|
3392
|
-
specify "should
|
|
3372
|
+
specify "should submit the SQL to the database with placeholders and bind variables" do
|
|
3393
3373
|
@ps.each{|p| p.prepared_sql; p.call(:n=>1)}
|
|
3394
|
-
@db.sqls.should == [
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3374
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3375
|
+
"SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3376
|
+
"SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
|
|
3377
|
+
"DELETE FROM items WHERE (num = ?) -- args: [1]",
|
|
3378
|
+
"INSERT INTO items (num) VALUES (?) -- args: [1]",
|
|
3379
|
+
"UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
|
|
3380
|
+
end
|
|
3381
|
+
|
|
3382
|
+
specify "should handle unrecognized statement types as :all" do
|
|
3383
|
+
ps = @ds.prepare(:select_all, :s)
|
|
3384
|
+
ps.extend(Sequel::Dataset::UnnumberedArgumentMapper)
|
|
3385
|
+
ps.prepared_sql
|
|
3386
|
+
ps.call(:n=>1)
|
|
3387
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]"]
|
|
3401
3388
|
end
|
|
3402
3389
|
end
|
|
3403
3390
|
|
|
3404
3391
|
describe "Sequel::Dataset#server" do
|
|
3405
3392
|
specify "should set the server to use for the dataset" do
|
|
3406
|
-
@db = Sequel
|
|
3393
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}, :d=>{}, :u=>{}})
|
|
3407
3394
|
@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
3395
|
@ds.all
|
|
3416
3396
|
@ds.server(:i).insert(:a=>1)
|
|
3417
3397
|
@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]]
|
|
3398
|
+
@ds.server(:u).update(:a=>Sequel.expr(:a)+1)
|
|
3399
|
+
@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
3400
|
end
|
|
3424
3401
|
end
|
|
3425
3402
|
|
|
3426
3403
|
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
3404
|
specify "should yield a dataset for each server" do
|
|
3405
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}})
|
|
3406
|
+
@ds = @db[:items]
|
|
3440
3407
|
@ds.each_server do |ds|
|
|
3441
3408
|
ds.should be_a_kind_of(Sequel::Dataset)
|
|
3442
3409
|
ds.should_not == @ds
|
|
3443
3410
|
ds.sql.should == @ds.sql
|
|
3444
3411
|
ds.all
|
|
3445
3412
|
end
|
|
3446
|
-
@sqls.
|
|
3413
|
+
@db.sqls.sort.should == ['SELECT * FROM items', 'SELECT * FROM items -- i', 'SELECT * FROM items -- s']
|
|
3447
3414
|
end
|
|
3448
3415
|
end
|
|
3449
3416
|
|
|
@@ -3493,23 +3460,23 @@ end
|
|
|
3493
3460
|
|
|
3494
3461
|
describe "Sequel::Dataset#qualify" do
|
|
3495
3462
|
specify "should qualify to the given table" do
|
|
3496
|
-
|
|
3463
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3497
3464
|
end
|
|
3498
3465
|
|
|
3499
3466
|
specify "should qualify to the first source if no table if given" do
|
|
3500
|
-
|
|
3467
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
|
|
3501
3468
|
end
|
|
3502
3469
|
end
|
|
3503
3470
|
|
|
3504
3471
|
describe "Sequel::Dataset#qualify_to" do
|
|
3505
3472
|
specify "should qualify to the given table" do
|
|
3506
|
-
|
|
3473
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3507
3474
|
end
|
|
3508
3475
|
end
|
|
3509
3476
|
|
|
3510
3477
|
describe "Sequel::Dataset#qualify_to_first_source" do
|
|
3511
3478
|
before do
|
|
3512
|
-
@ds =
|
|
3479
|
+
@ds = Sequel::Database.new[:t]
|
|
3513
3480
|
end
|
|
3514
3481
|
|
|
3515
3482
|
specify "should qualify_to the first source" do
|
|
@@ -3519,13 +3486,11 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3519
3486
|
end
|
|
3520
3487
|
|
|
3521
3488
|
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'
|
|
3489
|
+
@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
3490
|
end
|
|
3525
3491
|
|
|
3526
3492
|
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'
|
|
3493
|
+
@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
3494
|
end
|
|
3530
3495
|
|
|
3531
3496
|
specify "should handle hashes in select option" do
|
|
@@ -3541,7 +3506,7 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3541
3506
|
end
|
|
3542
3507
|
|
|
3543
3508
|
specify "should handle hashes" do
|
|
3544
|
-
@ds.select({:b=>{:c=>1}}
|
|
3509
|
+
@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
3510
|
end
|
|
3546
3511
|
|
|
3547
3512
|
specify "should handle SQL::Identifiers" do
|
|
@@ -3549,15 +3514,15 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3549
3514
|
end
|
|
3550
3515
|
|
|
3551
3516
|
specify "should handle SQL::OrderedExpressions" do
|
|
3552
|
-
@ds.order(:a
|
|
3517
|
+
@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
3518
|
end
|
|
3554
3519
|
|
|
3555
3520
|
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'
|
|
3521
|
+
@ds.select(Sequel.expr(:a).as(:b)).qualify_to_first_source.sql.should == 'SELECT t.a AS b FROM t'
|
|
3557
3522
|
end
|
|
3558
3523
|
|
|
3559
3524
|
specify "should handle SQL::CaseExpressions" do
|
|
3560
|
-
@ds.filter{{a=>b}
|
|
3525
|
+
@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
3526
|
end
|
|
3562
3527
|
|
|
3563
3528
|
specify "should handle SQL:Casts" do
|
|
@@ -3573,7 +3538,7 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3573
3538
|
end
|
|
3574
3539
|
|
|
3575
3540
|
specify "should handle SQL::ValueLists" do
|
|
3576
|
-
@ds.filter(:a=>[:b, :c]
|
|
3541
|
+
@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
3542
|
end
|
|
3578
3543
|
|
|
3579
3544
|
specify "should handle SQL::Subscripts" do
|
|
@@ -3588,20 +3553,97 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3588
3553
|
@ds.filter(':a > :b', :a=>:c, :b=>1).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.c > 1)'
|
|
3589
3554
|
end
|
|
3590
3555
|
|
|
3556
|
+
specify "should handle SQL::Wrappers" do
|
|
3557
|
+
@ds.filter(Sequel::SQL::Wrapper.new(:a)).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE t.a'
|
|
3558
|
+
end
|
|
3559
|
+
|
|
3591
3560
|
specify "should handle SQL::WindowFunctions" do
|
|
3592
3561
|
@ds.meta_def(:supports_window_functions?){true}
|
|
3593
3562
|
@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
3563
|
end
|
|
3595
3564
|
|
|
3596
3565
|
specify "should handle all other objects by returning them unchanged" do
|
|
3597
|
-
@ds.select("a").filter{a(3)}.filter('blah').order('true'
|
|
3598
|
-
|
|
3566
|
+
@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"
|
|
3567
|
+
end
|
|
3568
|
+
end
|
|
3569
|
+
|
|
3570
|
+
describe "Sequel::Dataset#unbind" do
|
|
3571
|
+
before do
|
|
3572
|
+
@ds = Sequel::Database.new[:t]
|
|
3573
|
+
@u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
|
|
3574
|
+
end
|
|
3575
|
+
|
|
3576
|
+
specify "should unbind values assigned to equality and inequality statements" do
|
|
3577
|
+
@ds.filter(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo = $foo)"
|
|
3578
|
+
@ds.exclude(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo != $foo)"
|
|
3579
|
+
@ds.filter{foo > 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo > $foo)"
|
|
3580
|
+
@ds.filter{foo >= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo >= $foo)"
|
|
3581
|
+
@ds.filter{foo < 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo < $foo)"
|
|
3582
|
+
@ds.filter{foo <= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo <= $foo)"
|
|
3583
|
+
end
|
|
3584
|
+
|
|
3585
|
+
specify "should return variables that could be used bound to recreate the previous query" do
|
|
3586
|
+
@ds.filter(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3587
|
+
@ds.exclude(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3588
|
+
end
|
|
3589
|
+
|
|
3590
|
+
specify "should handle numerics, strings, dates, times, and datetimes" do
|
|
3591
|
+
@u[@ds.filter(:foo=>1)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1}]
|
|
3592
|
+
@u[@ds.filter(:foo=>1.0)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1.0}]
|
|
3593
|
+
@u[@ds.filter(:foo=>BigDecimal.new('1.0'))].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>BigDecimal.new('1.0')}]
|
|
3594
|
+
@u[@ds.filter(:foo=>'a')].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>'a'}]
|
|
3595
|
+
@u[@ds.filter(:foo=>Date.today)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>Date.today}]
|
|
3596
|
+
t = Time.now
|
|
3597
|
+
@u[@ds.filter(:foo=>t)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>t}]
|
|
3598
|
+
dt = DateTime.now
|
|
3599
|
+
@u[@ds.filter(:foo=>dt)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>dt}]
|
|
3600
|
+
end
|
|
3601
|
+
|
|
3602
|
+
specify "should not unbind literal strings" do
|
|
3603
|
+
@u[@ds.filter(:foo=>Sequel.lit('a'))].should == ["SELECT * FROM t WHERE (foo = a)", {}]
|
|
3604
|
+
end
|
|
3605
|
+
|
|
3606
|
+
specify "should not unbind Identifiers, QualifiedIdentifiers, or Symbols used as booleans" do
|
|
3607
|
+
@u[@ds.filter(:foo).filter{bar}.filter{foo__bar}].should == ["SELECT * FROM t WHERE (foo AND bar AND foo.bar)", {}]
|
|
3608
|
+
end
|
|
3609
|
+
|
|
3610
|
+
specify "should not unbind for values it doesn't understand" do
|
|
3611
|
+
@u[@ds.filter(:foo=>Class.new{def sql_literal(ds) 'bar' end}.new)].should == ["SELECT * FROM t WHERE (foo = bar)", {}]
|
|
3612
|
+
end
|
|
3613
|
+
|
|
3614
|
+
specify "should handle QualifiedIdentifiers" do
|
|
3615
|
+
@u[@ds.filter{foo__bar > 1}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3616
|
+
end
|
|
3617
|
+
|
|
3618
|
+
specify "should handle wrapped objects" do
|
|
3619
|
+
@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}]
|
|
3620
|
+
end
|
|
3621
|
+
|
|
3622
|
+
specify "should handle deep nesting" do
|
|
3623
|
+
@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}]
|
|
3624
|
+
end
|
|
3625
|
+
|
|
3626
|
+
specify "should handle JOIN ON" do
|
|
3627
|
+
@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}]
|
|
3628
|
+
end
|
|
3629
|
+
|
|
3630
|
+
specify "should raise an UnbindDuplicate exception if same variable is used with multiple different values" do
|
|
3631
|
+
proc{@ds.filter(:foo=>1).or(:foo=>2).unbind}.should raise_error(Sequel::UnbindDuplicate)
|
|
3632
|
+
end
|
|
3633
|
+
|
|
3634
|
+
specify "should handle case where the same variable has the same value in multiple places " do
|
|
3635
|
+
@u[@ds.filter(:foo=>1).or(:foo=>1)].should == ["SELECT * FROM t WHERE ((foo = $foo) OR (foo = $foo))", {:foo=>1}]
|
|
3636
|
+
end
|
|
3637
|
+
|
|
3638
|
+
specify "should raise Error for unhandled objects inside Identifiers and QualifiedIndentifiers" do
|
|
3639
|
+
proc{@ds.filter(Sequel::SQL::Identifier.new([]) > 1).unbind}.should raise_error(Sequel::Error)
|
|
3640
|
+
proc{@ds.filter{foo.qualify({}) > 1}.unbind}.should raise_error(Sequel::Error)
|
|
3599
3641
|
end
|
|
3600
3642
|
end
|
|
3601
3643
|
|
|
3602
3644
|
describe "Sequel::Dataset #with and #with_recursive" do
|
|
3603
3645
|
before do
|
|
3604
|
-
@db =
|
|
3646
|
+
@db = Sequel::Database.new
|
|
3605
3647
|
@ds = @db[:t]
|
|
3606
3648
|
end
|
|
3607
3649
|
|
|
@@ -3633,56 +3675,72 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
|
3633
3675
|
proc{@ds.with(:t, @db[:x], :args=>[:b])}.should raise_error(Sequel::Error)
|
|
3634
3676
|
proc{@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c])}.should raise_error(Sequel::Error)
|
|
3635
3677
|
end
|
|
3678
|
+
|
|
3679
|
+
specify "#with should work on insert, update, and delete statements if they support it" do
|
|
3680
|
+
[:insert, :update, :delete].each do |m|
|
|
3681
|
+
@ds.meta_def(:"#{m}_clause_methods"){[:"#{m}_with_sql"] + super()}
|
|
3682
|
+
end
|
|
3683
|
+
@ds.with(:t, @db[:x]).insert_sql(1).should == 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
|
|
3684
|
+
@ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
|
|
3685
|
+
@ds.with(:t, @db[:x]).delete_sql.should == 'WITH t AS (SELECT * FROM x) DELETE FROM t'
|
|
3686
|
+
end
|
|
3687
|
+
|
|
3688
|
+
specify "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
|
|
3689
|
+
@ds.meta_def(:supports_cte?){true}
|
|
3690
|
+
@ds.meta_def(:supports_cte_in_subselect?){false}
|
|
3691
|
+
@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'
|
|
3692
|
+
@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'
|
|
3693
|
+
end
|
|
3636
3694
|
end
|
|
3637
3695
|
|
|
3638
3696
|
describe Sequel::SQL::Constants do
|
|
3639
3697
|
before do
|
|
3640
|
-
@db =
|
|
3698
|
+
@db = Sequel::Database.new
|
|
3641
3699
|
end
|
|
3642
3700
|
|
|
3643
3701
|
it "should have CURRENT_DATE" do
|
|
3644
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_DATE) == 'CURRENT_DATE'
|
|
3645
|
-
@db.literal(Sequel::CURRENT_DATE) == 'CURRENT_DATE'
|
|
3702
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_DATE).should == 'CURRENT_DATE'
|
|
3703
|
+
@db.literal(Sequel::CURRENT_DATE).should == 'CURRENT_DATE'
|
|
3646
3704
|
end
|
|
3647
3705
|
|
|
3648
3706
|
it "should have CURRENT_TIME" do
|
|
3649
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_TIME) == 'CURRENT_TIME'
|
|
3650
|
-
@db.literal(Sequel::CURRENT_TIME) == 'CURRENT_TIME'
|
|
3707
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_TIME).should == 'CURRENT_TIME'
|
|
3708
|
+
@db.literal(Sequel::CURRENT_TIME).should == 'CURRENT_TIME'
|
|
3651
3709
|
end
|
|
3652
3710
|
|
|
3653
3711
|
it "should have CURRENT_TIMESTAMP" do
|
|
3654
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_TIMESTAMP) == 'CURRENT_TIMESTAMP'
|
|
3655
|
-
@db.literal(Sequel::CURRENT_TIMESTAMP) == 'CURRENT_TIMESTAMP'
|
|
3712
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_TIMESTAMP).should == 'CURRENT_TIMESTAMP'
|
|
3713
|
+
@db.literal(Sequel::CURRENT_TIMESTAMP).should == 'CURRENT_TIMESTAMP'
|
|
3656
3714
|
end
|
|
3657
3715
|
|
|
3658
3716
|
it "should have NULL" do
|
|
3659
|
-
@db.literal(Sequel::SQL::Constants::NULL) == 'NULL'
|
|
3660
|
-
@db.literal(Sequel::NULL) == 'NULL'
|
|
3717
|
+
@db.literal(Sequel::SQL::Constants::NULL).should == 'NULL'
|
|
3718
|
+
@db.literal(Sequel::NULL).should == 'NULL'
|
|
3661
3719
|
end
|
|
3662
3720
|
|
|
3663
3721
|
it "should have NOTNULL" do
|
|
3664
|
-
@db.literal(Sequel::SQL::Constants::NOTNULL) == 'NOT NULL'
|
|
3665
|
-
@db.literal(Sequel::NOTNULL) == 'NOT NULL'
|
|
3722
|
+
@db.literal(Sequel::SQL::Constants::NOTNULL).should == 'NOT NULL'
|
|
3723
|
+
@db.literal(Sequel::NOTNULL).should == 'NOT NULL'
|
|
3666
3724
|
end
|
|
3667
3725
|
|
|
3668
3726
|
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) == '
|
|
3727
|
+
@db.literal(Sequel::SQL::Constants::TRUE).should == "'t'"
|
|
3728
|
+
@db.literal(Sequel::TRUE).should == "'t'"
|
|
3729
|
+
@db.literal(Sequel::SQL::Constants::SQLTRUE).should == "'t'"
|
|
3730
|
+
@db.literal(Sequel::SQLTRUE).should == "'t'"
|
|
3673
3731
|
end
|
|
3674
3732
|
|
|
3675
3733
|
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) == '
|
|
3734
|
+
@db.literal(Sequel::SQL::Constants::FALSE).should == "'f'"
|
|
3735
|
+
@db.literal(Sequel::FALSE).should == "'f'"
|
|
3736
|
+
@db.literal(Sequel::SQL::Constants::SQLFALSE).should == "'f'"
|
|
3737
|
+
@db.literal(Sequel::SQLFALSE).should == "'f'"
|
|
3680
3738
|
end
|
|
3681
3739
|
end
|
|
3682
3740
|
|
|
3683
3741
|
describe "Sequel timezone support" do
|
|
3684
3742
|
before do
|
|
3685
|
-
@db =
|
|
3743
|
+
@db = Sequel::Database.new
|
|
3686
3744
|
@dataset = @db.dataset
|
|
3687
3745
|
@dataset.meta_def(:supports_timestamp_timezones?){true}
|
|
3688
3746
|
@dataset.meta_def(:supports_timestamp_usecs?){false}
|
|
@@ -3717,6 +3775,30 @@ describe "Sequel timezone support" do
|
|
|
3717
3775
|
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3718
3776
|
end
|
|
3719
3777
|
|
|
3778
|
+
specify "should have Database#timezone override Sequel.database_timezone" do
|
|
3779
|
+
Sequel.database_timezone = :local
|
|
3780
|
+
@db.timezone = :utc
|
|
3781
|
+
|
|
3782
|
+
t = Time.now
|
|
3783
|
+
s = t.getutc.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3784
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3785
|
+
|
|
3786
|
+
t = DateTime.now
|
|
3787
|
+
s = t.new_offset(0).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3788
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3789
|
+
|
|
3790
|
+
Sequel.database_timezone = :utc
|
|
3791
|
+
@db.timezone = :local
|
|
3792
|
+
|
|
3793
|
+
t = Time.now.utc
|
|
3794
|
+
s = t.getlocal.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3795
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3796
|
+
|
|
3797
|
+
t = DateTime.now.new_offset(0)
|
|
3798
|
+
s = t.new_offset(DateTime.now.offset).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3799
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3800
|
+
end
|
|
3801
|
+
|
|
3720
3802
|
specify "should handle converting database timestamps into application timestamps" do
|
|
3721
3803
|
Sequel.database_timezone = :utc
|
|
3722
3804
|
Sequel.application_timezone = :local
|
|
@@ -3827,13 +3909,7 @@ end
|
|
|
3827
3909
|
|
|
3828
3910
|
describe "Sequel::Dataset#select_map" do
|
|
3829
3911
|
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
|
|
3912
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3837
3913
|
end
|
|
3838
3914
|
|
|
3839
3915
|
specify "should do select and map in one step" do
|
|
@@ -3846,31 +3922,63 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3846
3922
|
@ds.db.sqls.should == ['SELECT a.b FROM t']
|
|
3847
3923
|
end
|
|
3848
3924
|
|
|
3925
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
3926
|
+
proc{@ds.select_map([Sequel.function(:a), :b])}.should raise_error(Sequel::Error)
|
|
3927
|
+
proc{@ds.select_map(Sequel.function(:a)){b}}.should raise_error(Sequel::Error)
|
|
3928
|
+
proc{@ds.select_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
3929
|
+
end
|
|
3930
|
+
|
|
3849
3931
|
specify "should handle implicit aliases in arguments" do
|
|
3850
3932
|
@ds.select_map(:a___b).should == [1, 2]
|
|
3851
3933
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
3852
3934
|
end
|
|
3853
3935
|
|
|
3854
3936
|
specify "should handle other objects" do
|
|
3855
|
-
@ds.select_map("a".
|
|
3937
|
+
@ds.select_map(Sequel.lit("a").as(:b)).should == [1, 2]
|
|
3856
3938
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
3857
3939
|
end
|
|
3858
3940
|
|
|
3941
|
+
specify "should handle identifiers with strings" do
|
|
3942
|
+
@ds.select_map([Sequel::SQL::Identifier.new('c'), :c]).should == [[1, 1], [2, 2]]
|
|
3943
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3944
|
+
end
|
|
3945
|
+
|
|
3859
3946
|
specify "should accept a block" do
|
|
3860
3947
|
@ds.select_map{a(t__c)}.should == [1, 2]
|
|
3861
3948
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t']
|
|
3862
3949
|
end
|
|
3950
|
+
|
|
3951
|
+
specify "should accept a block with an array of columns" do
|
|
3952
|
+
@ds.select_map{[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
3953
|
+
@ds.db.sqls.should == ['SELECT a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3954
|
+
end
|
|
3955
|
+
|
|
3956
|
+
specify "should accept a block with a column" do
|
|
3957
|
+
@ds.select_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
3958
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t']
|
|
3959
|
+
end
|
|
3960
|
+
|
|
3961
|
+
specify "should accept a block and array of arguments" do
|
|
3962
|
+
@ds.select_map([:c, :c]){[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
3963
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3964
|
+
end
|
|
3965
|
+
|
|
3966
|
+
specify "should handle an array of columns" do
|
|
3967
|
+
@ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3968
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3969
|
+
@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]]
|
|
3970
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
|
|
3971
|
+
end
|
|
3972
|
+
|
|
3973
|
+
specify "should handle an array with a single element" do
|
|
3974
|
+
@ds.select_map([:c]).should == [[1], [2]]
|
|
3975
|
+
@ds.db.sqls.should == ['SELECT c FROM t']
|
|
3976
|
+
end
|
|
3863
3977
|
end
|
|
3864
3978
|
|
|
3865
3979
|
describe "Sequel::Dataset#select_order_map" do
|
|
3866
3980
|
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
|
|
3981
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3874
3982
|
end
|
|
3875
3983
|
|
|
3876
3984
|
specify "should do select and map in one step" do
|
|
@@ -3883,6 +3991,12 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3883
3991
|
@ds.db.sqls.should == ['SELECT a.b FROM t ORDER BY a.b']
|
|
3884
3992
|
end
|
|
3885
3993
|
|
|
3994
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
3995
|
+
proc{@ds.select_order_map([Sequel.function(:a), :b])}.should raise_error(Sequel::Error)
|
|
3996
|
+
proc{@ds.select_order_map(Sequel.function(:a)){b}}.should raise_error(Sequel::Error)
|
|
3997
|
+
proc{@ds.select_order_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
3998
|
+
end
|
|
3999
|
+
|
|
3886
4000
|
specify "should handle implicit aliases in arguments" do
|
|
3887
4001
|
@ds.select_order_map(:a___b).should == [1, 2]
|
|
3888
4002
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
@@ -3894,59 +4008,164 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3894
4008
|
end
|
|
3895
4009
|
|
|
3896
4010
|
specify "should handle AliasedExpressions" do
|
|
3897
|
-
@ds.select_order_map("a".
|
|
4011
|
+
@ds.select_order_map(Sequel.lit("a").as(:b)).should == [1, 2]
|
|
3898
4012
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
3899
4013
|
end
|
|
3900
4014
|
|
|
4015
|
+
specify "should handle OrderedExpressions" do
|
|
4016
|
+
@ds.select_order_map(Sequel.desc(:a)).should == [1, 2]
|
|
4017
|
+
@ds.db.sqls.should == ['SELECT a FROM t ORDER BY a DESC']
|
|
4018
|
+
end
|
|
4019
|
+
|
|
3901
4020
|
specify "should accept a block" do
|
|
3902
4021
|
@ds.select_order_map{a(t__c)}.should == [1, 2]
|
|
3903
4022
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t ORDER BY a(t.c)']
|
|
3904
4023
|
end
|
|
4024
|
+
|
|
4025
|
+
specify "should accept a block with an array of columns" do
|
|
4026
|
+
@ds.select_order_map{[c.desc, a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
4027
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c DESC, a(t.c)']
|
|
4028
|
+
end
|
|
4029
|
+
|
|
4030
|
+
specify "should accept a block with a column" do
|
|
4031
|
+
@ds.select_order_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
4032
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c, a(t.c)']
|
|
4033
|
+
end
|
|
4034
|
+
|
|
4035
|
+
specify "should accept a block and array of arguments" do
|
|
4036
|
+
@ds.select_order_map([:c, :c]){[a(t__c).as(c), c.desc]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
4037
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, c FROM t ORDER BY c, c, a(t.c), c DESC']
|
|
4038
|
+
end
|
|
4039
|
+
|
|
4040
|
+
specify "should handle an array of columns" do
|
|
4041
|
+
@ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
4042
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
|
|
4043
|
+
@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]]
|
|
4044
|
+
@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']
|
|
4045
|
+
end
|
|
4046
|
+
|
|
4047
|
+
specify "should handle an array with a single element" do
|
|
4048
|
+
@ds.select_order_map([:c]).should == [[1], [2]]
|
|
4049
|
+
@ds.db.sqls.should == ['SELECT c FROM t ORDER BY c']
|
|
4050
|
+
end
|
|
3905
4051
|
end
|
|
3906
4052
|
|
|
3907
4053
|
describe "Sequel::Dataset#select_hash" do
|
|
3908
4054
|
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
|
|
4055
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4056
|
+
@ds = @db[:t]
|
|
3918
4057
|
end
|
|
3919
4058
|
|
|
3920
|
-
specify "should do select and
|
|
3921
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4059
|
+
specify "should do select and to_hash in one step" do
|
|
3922
4060
|
@ds.select_hash(:a, :b).should == {1=>2, 3=>4}
|
|
3923
4061
|
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3924
4062
|
end
|
|
3925
4063
|
|
|
3926
4064
|
specify "should handle implicit qualifiers in arguments" do
|
|
3927
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3928
4065
|
@ds.select_hash(:t__a, :t__b).should == {1=>2, 3=>4}
|
|
3929
4066
|
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3930
4067
|
end
|
|
3931
4068
|
|
|
3932
4069
|
specify "should handle implicit aliases in arguments" do
|
|
3933
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3934
4070
|
@ds.select_hash(:c___a, :d___b).should == {1=>2, 3=>4}
|
|
3935
4071
|
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
3936
4072
|
end
|
|
3937
4073
|
|
|
3938
4074
|
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
3939
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3940
4075
|
@ds.select_hash(:t__c___a, :t__d___b).should == {1=>2, 3=>4}
|
|
3941
4076
|
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
3942
4077
|
end
|
|
4078
|
+
|
|
4079
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
4080
|
+
@ds.select_hash(Sequel.identifier(:a), Sequel.identifier(:b)).should == {1=>2, 3=>4}
|
|
4081
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4082
|
+
end
|
|
4083
|
+
|
|
4084
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
4085
|
+
@ds.select_hash(Sequel.qualify(:t, :a), Sequel.identifier(:b).qualify(:t)).should == {1=>2, 3=>4}
|
|
4086
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4087
|
+
end
|
|
4088
|
+
|
|
4089
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
4090
|
+
@ds.select_hash(Sequel.expr(:c).as(:a), Sequel.expr(:t).as(:b)).should == {1=>2, 3=>4}
|
|
4091
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
4092
|
+
end
|
|
4093
|
+
|
|
4094
|
+
specify "should work with arrays of columns" do
|
|
4095
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
4096
|
+
@ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [4, 6]=>5}
|
|
4097
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
4098
|
+
@ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 4=>[5, 6]}
|
|
4099
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
4100
|
+
@ds.select_hash([:a, :b], [:b, :c]).should == {[1, 2]=>[2, 3], [4, 5]=>[5, 6]}
|
|
4101
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
4102
|
+
end
|
|
4103
|
+
|
|
4104
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
4105
|
+
proc{@ds.select_hash(Sequel.expr(:c).as(:a), Sequel.function(:b))}.should raise_error(Sequel::Error)
|
|
4106
|
+
end
|
|
4107
|
+
end
|
|
4108
|
+
|
|
4109
|
+
describe "Sequel::Dataset#select_hash_groups" do
|
|
4110
|
+
before do
|
|
4111
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4112
|
+
@ds = @db[:t]
|
|
4113
|
+
end
|
|
4114
|
+
|
|
4115
|
+
specify "should do select and to_hash in one step" do
|
|
4116
|
+
@ds.select_hash_groups(:a, :b).should == {1=>[2], 3=>[4]}
|
|
4117
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4118
|
+
end
|
|
4119
|
+
|
|
4120
|
+
specify "should handle implicit qualifiers in arguments" do
|
|
4121
|
+
@ds.select_hash_groups(:t__a, :t__b).should == {1=>[2], 3=>[4]}
|
|
4122
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4123
|
+
end
|
|
4124
|
+
|
|
4125
|
+
specify "should handle implicit aliases in arguments" do
|
|
4126
|
+
@ds.select_hash_groups(:c___a, :d___b).should == {1=>[2], 3=>[4]}
|
|
4127
|
+
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
4128
|
+
end
|
|
4129
|
+
|
|
4130
|
+
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
4131
|
+
@ds.select_hash_groups(:t__c___a, :t__d___b).should == {1=>[2], 3=>[4]}
|
|
4132
|
+
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
4133
|
+
end
|
|
4134
|
+
|
|
4135
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
4136
|
+
@ds.select_hash_groups(Sequel.identifier(:a), Sequel.identifier(:b)).should == {1=>[2], 3=>[4]}
|
|
4137
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4138
|
+
end
|
|
4139
|
+
|
|
4140
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
4141
|
+
@ds.select_hash_groups(Sequel.qualify(:t, :a), Sequel.identifier(:b).qualify(:t)).should == {1=>[2], 3=>[4]}
|
|
4142
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4143
|
+
end
|
|
4144
|
+
|
|
4145
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
4146
|
+
@ds.select_hash_groups(Sequel.expr(:c).as(:a), Sequel.expr(:t).as(:b)).should == {1=>[2], 3=>[4]}
|
|
4147
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
4148
|
+
end
|
|
4149
|
+
|
|
4150
|
+
specify "should work with arrays of columns" do
|
|
4151
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
4152
|
+
@ds.select_hash_groups([:a, :c], :b).should == {[1, 3]=>[2], [4, 6]=>[5]}
|
|
4153
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
4154
|
+
@ds.select_hash_groups(:a, [:b, :c]).should == {1=>[[2, 3]], 4=>[[5, 6]]}
|
|
4155
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
4156
|
+
@ds.select_hash_groups([:a, :b], [:b, :c]).should == {[1, 2]=>[[2, 3]], [4, 5]=>[[5, 6]]}
|
|
4157
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
4158
|
+
end
|
|
4159
|
+
|
|
4160
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
4161
|
+
proc{@ds.select_hash_groups(Sequel.expr(:c).as(:a), Sequel.function(:b))}.should raise_error(Sequel::Error)
|
|
4162
|
+
end
|
|
3943
4163
|
end
|
|
3944
4164
|
|
|
3945
4165
|
describe "Modifying joined datasets" do
|
|
3946
4166
|
before do
|
|
3947
|
-
@ds =
|
|
4167
|
+
@ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
|
|
3948
4168
|
@ds.meta_def(:supports_modifying_joins?){true}
|
|
3949
|
-
@ds.db.reset
|
|
3950
4169
|
end
|
|
3951
4170
|
|
|
3952
4171
|
specify "should allow deleting from joined datasets" do
|
|
@@ -3962,7 +4181,7 @@ end
|
|
|
3962
4181
|
|
|
3963
4182
|
describe "Dataset#lock_style and for_update" do
|
|
3964
4183
|
before do
|
|
3965
|
-
@ds =
|
|
4184
|
+
@ds = Sequel::Dataset.new(nil).from(:t)
|
|
3966
4185
|
end
|
|
3967
4186
|
|
|
3968
4187
|
specify "#for_update should use FOR UPDATE" do
|
|
@@ -3977,3 +4196,173 @@ describe "Dataset#lock_style and for_update" do
|
|
|
3977
4196
|
@ds.lock_style("FOR SHARE").sql.should == "SELECT * FROM t FOR SHARE"
|
|
3978
4197
|
end
|
|
3979
4198
|
end
|
|
4199
|
+
|
|
4200
|
+
describe "Custom ASTTransformer" do
|
|
4201
|
+
specify "should transform given objects" do
|
|
4202
|
+
c = Class.new(Sequel::ASTTransformer) do
|
|
4203
|
+
def v(s)
|
|
4204
|
+
(s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
|
|
4205
|
+
end
|
|
4206
|
+
end.new
|
|
4207
|
+
ds = Sequel::Dataset.new(nil).from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
|
4208
|
+
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)'
|
|
4209
|
+
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)'
|
|
4210
|
+
end
|
|
4211
|
+
end
|
|
4212
|
+
|
|
4213
|
+
describe "Dataset#returning" do
|
|
4214
|
+
before do
|
|
4215
|
+
@ds = Sequel.mock(:fetch=>proc{|s| {:foo=>s}})[:t].returning(:foo)
|
|
4216
|
+
@pr = proc do
|
|
4217
|
+
[:insert, :update, :delete].each do |m|
|
|
4218
|
+
@ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_returning_sql"]}
|
|
4219
|
+
end
|
|
4220
|
+
end
|
|
4221
|
+
end
|
|
4222
|
+
|
|
4223
|
+
specify "should use RETURNING clause in the SQL if the dataset supports it" do
|
|
4224
|
+
@pr.call
|
|
4225
|
+
@ds.delete_sql.should == "DELETE FROM t RETURNING foo"
|
|
4226
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1) RETURNING foo"
|
|
4227
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1 RETURNING foo"
|
|
4228
|
+
end
|
|
4229
|
+
|
|
4230
|
+
specify "should not use RETURNING clause in the SQL if the dataset does not support it" do
|
|
4231
|
+
@ds.delete_sql.should == "DELETE FROM t"
|
|
4232
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1)"
|
|
4233
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1"
|
|
4234
|
+
end
|
|
4235
|
+
|
|
4236
|
+
specify "should have insert, update, and delete yield to blocks if RETURNING is used" do
|
|
4237
|
+
@pr.call
|
|
4238
|
+
h = {}
|
|
4239
|
+
@ds.delete{|r| h = r}
|
|
4240
|
+
h.should == {:foo=>"DELETE FROM t RETURNING foo"}
|
|
4241
|
+
@ds.insert(1){|r| h = r}
|
|
4242
|
+
h.should == {:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}
|
|
4243
|
+
@ds.update(:foo=>1){|r| h = r}
|
|
4244
|
+
h.should == {:foo=>"UPDATE t SET foo = 1 RETURNING foo"}
|
|
4245
|
+
end
|
|
4246
|
+
|
|
4247
|
+
specify "should have insert, update, and delete return arrays of hashes if RETURNING is used and a block is not given" do
|
|
4248
|
+
@pr.call
|
|
4249
|
+
h = {}
|
|
4250
|
+
@ds.delete.should == [{:foo=>"DELETE FROM t RETURNING foo"}]
|
|
4251
|
+
@ds.insert(1).should == [{:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}]
|
|
4252
|
+
@ds.update(:foo=>1).should == [{:foo=>"UPDATE t SET foo = 1 RETURNING foo"}]
|
|
4253
|
+
end
|
|
4254
|
+
end
|
|
4255
|
+
|
|
4256
|
+
describe "Dataset emulating bitwise operator support" do
|
|
4257
|
+
before do
|
|
4258
|
+
@ds = Sequel::Database.new.dataset
|
|
4259
|
+
@ds.quote_identifiers = true
|
|
4260
|
+
def @ds.complex_expression_sql_append(sql, op, args)
|
|
4261
|
+
sql << complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
|
4262
|
+
end
|
|
4263
|
+
end
|
|
4264
|
+
|
|
4265
|
+
it "should work with any numbers of arguments for operators" do
|
|
4266
|
+
@ds.select(Sequel::SQL::ComplexExpression.new(:&, :x)).sql.should == 'SELECT "x"'
|
|
4267
|
+
@ds.select(Sequel.expr(:x) & 1).sql.should == 'SELECT bitand("x", 1)'
|
|
4268
|
+
@ds.select(Sequel.expr(:x) & 1 & 2).sql.should == 'SELECT bitand(bitand("x", 1), 2)'
|
|
4269
|
+
end
|
|
4270
|
+
end
|
|
4271
|
+
|
|
4272
|
+
describe "Dataset feature defaults" do
|
|
4273
|
+
it "should not require aliases for recursive CTEs by default" do
|
|
4274
|
+
Sequel::Database.new.dataset.recursive_cte_requires_column_aliases?.should be_false
|
|
4275
|
+
end
|
|
4276
|
+
|
|
4277
|
+
it "should not require placeholder type specifiers by default" do
|
|
4278
|
+
Sequel::Database.new.dataset.requires_placeholder_type_specifiers?.should be_false
|
|
4279
|
+
end
|
|
4280
|
+
|
|
4281
|
+
it "offset use should be returning a separate row number column by default" do
|
|
4282
|
+
Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
|
|
4283
|
+
end
|
|
4284
|
+
end
|
|
4285
|
+
|
|
4286
|
+
describe "Dataset extensions" do
|
|
4287
|
+
before(:all) do
|
|
4288
|
+
class << Sequel
|
|
4289
|
+
alias _extension extension
|
|
4290
|
+
def extension(*)
|
|
4291
|
+
end
|
|
4292
|
+
end
|
|
4293
|
+
end
|
|
4294
|
+
after(:all) do
|
|
4295
|
+
class << Sequel
|
|
4296
|
+
alias extension _extension
|
|
4297
|
+
end
|
|
4298
|
+
end
|
|
4299
|
+
before do
|
|
4300
|
+
@ds = Sequel::Dataset.new(nil)
|
|
4301
|
+
end
|
|
4302
|
+
|
|
4303
|
+
specify "should be able to register an extension with a module Database#extension extend the module" do
|
|
4304
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4305
|
+
@ds.extension(:foo).a.should == 1
|
|
4306
|
+
end
|
|
4307
|
+
|
|
4308
|
+
specify "should be able to register an extension with a block and Database#extension call the block" do
|
|
4309
|
+
@ds.quote_identifiers = false
|
|
4310
|
+
Sequel::Dataset.register_extension(:foo){|db| db.quote_identifiers = true}
|
|
4311
|
+
@ds.extension(:foo).quote_identifiers?.should be_true
|
|
4312
|
+
end
|
|
4313
|
+
|
|
4314
|
+
specify "should be able to register an extension with a callable and Database#extension call the callable" do
|
|
4315
|
+
@ds.quote_identifiers = false
|
|
4316
|
+
Sequel::Dataset.register_extension(:foo, proc{|db| db.quote_identifiers = true})
|
|
4317
|
+
@ds.extension(:foo).quote_identifiers?.should be_true
|
|
4318
|
+
end
|
|
4319
|
+
|
|
4320
|
+
specify "should be able to load multiple extensions in the same call" do
|
|
4321
|
+
@ds.quote_identifiers = false
|
|
4322
|
+
@ds.identifier_input_method = :downcase
|
|
4323
|
+
Sequel::Dataset.register_extension(:foo, proc{|ds| ds.quote_identifiers = true})
|
|
4324
|
+
Sequel::Dataset.register_extension(:bar, proc{|ds| ds.identifier_input_method = nil})
|
|
4325
|
+
ds = @ds.extension(:foo, :bar)
|
|
4326
|
+
ds.quote_identifiers?.should be_true
|
|
4327
|
+
ds.identifier_input_method.should be_nil
|
|
4328
|
+
end
|
|
4329
|
+
|
|
4330
|
+
specify "should have #extension not modify the receiver" do
|
|
4331
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4332
|
+
@ds.extension(:foo)
|
|
4333
|
+
proc{@ds.a}.should raise_error(NoMethodError)
|
|
4334
|
+
end
|
|
4335
|
+
|
|
4336
|
+
specify "should have #extension not return a cloned dataset" do
|
|
4337
|
+
@ds.extend(Module.new{def b; 2; end})
|
|
4338
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4339
|
+
v = @ds.extension(:foo)
|
|
4340
|
+
v.should_not equal(@ds)
|
|
4341
|
+
v.should be_a_kind_of(Sequel::Dataset)
|
|
4342
|
+
v.b.should == 2
|
|
4343
|
+
end
|
|
4344
|
+
|
|
4345
|
+
specify "should have #extension! modify the receiver" do
|
|
4346
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4347
|
+
@ds.extension!(:foo)
|
|
4348
|
+
@ds.a.should == 1
|
|
4349
|
+
end
|
|
4350
|
+
|
|
4351
|
+
specify "should have #extension! return the receiver" do
|
|
4352
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4353
|
+
@ds.extension!(:foo).should equal(@ds)
|
|
4354
|
+
end
|
|
4355
|
+
|
|
4356
|
+
specify "should register a Database extension for modifying all datasets when registering with a module" do
|
|
4357
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4358
|
+
Sequel.mock.extension(:foo).dataset.a.should == 1
|
|
4359
|
+
end
|
|
4360
|
+
|
|
4361
|
+
specify "should raise an Error if registering with both a module and a block" do
|
|
4362
|
+
proc{Sequel::Dataset.register_extension(:foo, Module.new){}}.should raise_error(Sequel::Error)
|
|
4363
|
+
end
|
|
4364
|
+
|
|
4365
|
+
specify "should raise an Error if attempting to load an incompatible extension" do
|
|
4366
|
+
proc{@ds.extension(:foo2)}.should raise_error(Sequel::Error)
|
|
4367
|
+
end
|
|
4368
|
+
end
|