sequel 3.21.0 → 3.36.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 +855 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -7
- data/Rakefile +42 -24
- data/bin/sequel +26 -8
- data/doc/active_record.rdoc +1 -0
- data/doc/advanced_associations.rdoc +171 -11
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +85 -552
- data/doc/model_hooks.rdoc +78 -27
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +97 -50
- data/doc/prepared_statements.rdoc +40 -14
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +30 -4
- 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/schema_modification.rdoc +572 -0
- data/doc/sharding.rdoc +95 -3
- data/doc/testing.rdoc +129 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +51 -2
- 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 +1 -57
- 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 +47 -0
- data/lib/sequel/adapters/jdbc/derby.rb +287 -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 +29 -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 +58 -48
- 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 +265 -94
- data/lib/sequel/adapters/mock.rb +361 -0
- data/lib/sequel/adapters/mysql.rb +118 -222
- data/lib/sequel/adapters/mysql2.rb +58 -57
- data/lib/sequel/adapters/odbc/mssql.rb +15 -7
- 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 +356 -107
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +342 -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 +335 -118
- data/lib/sequel/adapters/shared/mysql.rb +340 -76
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +243 -45
- data/lib/sequel/adapters/shared/postgres.rb +524 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +265 -89
- data/lib/sequel/adapters/sqlite.rb +101 -39
- data/lib/sequel/adapters/swift/mysql.rb +9 -12
- data/lib/sequel/adapters/swift/postgres.rb +9 -74
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +8 -7
- data/lib/sequel/adapters/tinytds.rb +161 -21
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -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 +28 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +38 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +118 -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 +150 -46
- data/lib/sequel/database/query.rb +215 -65
- data/lib/sequel/database/schema_generator.rb +64 -20
- data/lib/sequel/database/schema_methods.rb +212 -54
- data/lib/sequel/dataset/actions.rb +322 -85
- data/lib/sequel/dataset/features.rb +96 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +237 -44
- data/lib/sequel/dataset/sql.rb +698 -278
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
- data/lib/sequel/extensions/migration.rb +97 -11
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query.rb +1 -1
- 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 +251 -37
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/server_block.rb +139 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1187 -393
- data/lib/sequel/model/base.rb +578 -170
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- 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/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -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 +123 -8
- 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 +12 -2
- data/lib/sequel/plugins/many_through_many.rb +79 -28
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +139 -63
- data/lib/sequel/plugins/optimistic_locking.rb +8 -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 +29 -15
- data/lib/sequel/plugins/schema.rb +7 -2
- 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 +10 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- 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/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +526 -59
- data/lib/sequel/timezones.rb +57 -38
- 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 +142 -40
- data/spec/adapters/mysql_spec.rb +380 -234
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +1050 -212
- data/spec/adapters/spec_helper.rb +8 -5
- data/spec/adapters/sqlite_spec.rb +139 -27
- data/spec/core/connection_pool_spec.rb +196 -93
- data/spec/core/database_spec.rb +879 -510
- data/spec/core/dataset_spec.rb +1415 -1086
- data/spec/core/expression_filters_spec.rb +554 -109
- data/spec/core/mock_adapter_spec.rb +449 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +482 -38
- data/spec/core/spec_helper.rb +6 -48
- 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/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/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +69 -92
- data/spec/extensions/identity_map_spec.rb +131 -22
- 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 -6
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +48 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- 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 +251 -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 +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -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 +168 -0
- data/spec/extensions/query_spec.rb +6 -0
- 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 +429 -22
- data/spec/extensions/schema_spec.rb +25 -21
- 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 +85 -43
- 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 +22 -61
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -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 +4 -7
- 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 +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- 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 +9 -3
- data/spec/integration/dataset_test.rb +605 -91
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +454 -143
- data/spec/integration/prepared_statement_test.rb +263 -128
- data/spec/integration/schema_test.rb +309 -43
- data/spec/integration/spec_helper.rb +40 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +18 -4
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +1067 -661
- data/spec/model/base_spec.rb +329 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +349 -67
- data/spec/model/model_spec.rb +240 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +490 -232
- data/spec/model/spec_helper.rb +14 -71
- data/spec/model/validations_spec.rb +11 -0
- data/spec/rcov.opts +2 -0
- metadata +178 -80
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'\)/)
|
|
@@ -245,8 +242,6 @@ describe "A simple dataset" do
|
|
|
245
242
|
end
|
|
246
243
|
|
|
247
244
|
specify "should format an insert statement with an object that respond_to? :values" do
|
|
248
|
-
dbb = Sequel::Database.new
|
|
249
|
-
|
|
250
245
|
v = Object.new
|
|
251
246
|
def v.values; {:a => 1}; end
|
|
252
247
|
|
|
@@ -261,29 +256,24 @@ describe "A simple dataset" do
|
|
|
261
256
|
end
|
|
262
257
|
|
|
263
258
|
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)"
|
|
259
|
+
@dataset.insert_sql(@dataset.from(:something).filter(:x => 2)).should == "INSERT INTO test SELECT * FROM something WHERE (x = 2)"
|
|
267
260
|
end
|
|
268
261
|
|
|
269
262
|
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)"
|
|
263
|
+
@dataset.insert_sql('a', 2, 6.5).should == "INSERT INTO test VALUES ('a', 2, 6.5)"
|
|
272
264
|
end
|
|
273
265
|
|
|
274
266
|
specify "should format an update statement" do
|
|
275
|
-
@dataset.update_sql(:name => 'abc').should ==
|
|
276
|
-
"UPDATE test SET name = 'abc'"
|
|
267
|
+
@dataset.update_sql(:name => 'abc').should == "UPDATE test SET name = 'abc'"
|
|
277
268
|
end
|
|
278
269
|
|
|
279
270
|
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"
|
|
271
|
+
@dataset.clone(:sql => 'xxx yyy zzz').select_sql.should == "xxx yyy zzz"
|
|
282
272
|
end
|
|
283
273
|
|
|
284
274
|
specify "should use the :sql option for all sql methods" do
|
|
285
275
|
sql = "X"
|
|
286
|
-
ds =
|
|
276
|
+
ds = @dataset.clone(:sql=>sql)
|
|
287
277
|
ds.sql.should == sql
|
|
288
278
|
ds.select_sql.should == sql
|
|
289
279
|
ds.insert_sql.should == sql
|
|
@@ -357,12 +347,12 @@ describe "Dataset#exists" do
|
|
|
357
347
|
@ds1.filter(@ds2.exists).sql.should ==
|
|
358
348
|
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
|
359
349
|
@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)))'
|
|
350
|
+
'SELECT * FROM test WHERE ((EXISTS (SELECT * FROM test WHERE (price < 100))) AND (EXISTS (SELECT * FROM test WHERE (price > 50))))'
|
|
361
351
|
end
|
|
362
352
|
|
|
363
353
|
specify "should work in select" do
|
|
364
354
|
@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'
|
|
355
|
+
'SELECT (EXISTS (SELECT * FROM test WHERE (price < 100))) AS a, (EXISTS (SELECT * FROM test WHERE (price > 50))) AS b FROM test'
|
|
366
356
|
end
|
|
367
357
|
end
|
|
368
358
|
|
|
@@ -418,7 +408,7 @@ describe "Dataset#where" do
|
|
|
418
408
|
b.should == a
|
|
419
409
|
end
|
|
420
410
|
|
|
421
|
-
specify "should not replace named placeholders that don't
|
|
411
|
+
specify "should not replace named placeholders that don't exist in the hash" do
|
|
422
412
|
@dataset.where('price < :price AND id in :ids', :price=>100).select_sql.should ==
|
|
423
413
|
"SELECT * FROM test WHERE (price < 100 AND id in :ids)"
|
|
424
414
|
end
|
|
@@ -510,62 +500,89 @@ describe "Dataset#where" do
|
|
|
510
500
|
"SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
|
511
501
|
end
|
|
512
502
|
|
|
503
|
+
specify "should handle all types of IN/NOT IN queries with empty arrays" do
|
|
504
|
+
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (id != id)"
|
|
505
|
+
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
506
|
+
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (id = id)"
|
|
507
|
+
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
specify "should handle all types of IN/NOT IN queries with empty arrays" do
|
|
511
|
+
begin
|
|
512
|
+
Sequel.empty_array_handle_nulls = false
|
|
513
|
+
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
514
|
+
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
515
|
+
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
516
|
+
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
517
|
+
ensure
|
|
518
|
+
Sequel.empty_array_handle_nulls = true
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
513
522
|
specify "should handle all types of IN/NOT IN queries" do
|
|
514
523
|
@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
524
|
@dataset.filter(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id IN (1, 2))"
|
|
517
525
|
@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 != id1) AND (id2 != id2))"
|
|
519
526
|
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
|
|
520
527
|
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
|
|
521
528
|
|
|
522
529
|
@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
530
|
@dataset.exclude(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id NOT IN (1, 2))"
|
|
525
531
|
@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 (1 = 1)"
|
|
527
532
|
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
|
|
528
533
|
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
|
|
529
534
|
end
|
|
530
535
|
|
|
531
536
|
specify "should handle IN/NOT IN queries with multiple columns and an array where the database doesn't support it" do
|
|
532
537
|
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
533
|
-
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
534
538
|
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
535
|
-
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
536
539
|
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
537
540
|
end
|
|
538
541
|
|
|
539
542
|
specify "should handle IN/NOT IN queries with multiple columns and a dataset where the database doesn't support it" do
|
|
540
543
|
@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
|
|
544
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
545
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
549
546
|
@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)
|
|
547
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
552
548
|
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
553
|
-
|
|
549
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
554
550
|
end
|
|
555
551
|
|
|
556
552
|
specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it" do
|
|
557
553
|
@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
|
|
554
|
+
db = Sequel.mock
|
|
555
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
564
556
|
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
557
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
558
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
|
|
559
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
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
|
|
563
|
+
begin
|
|
564
|
+
Sequel.empty_array_handle_nulls = false
|
|
565
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
566
|
+
db = Sequel.mock
|
|
567
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
568
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
569
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
570
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
571
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
572
|
+
ensure
|
|
573
|
+
Sequel.empty_array_handle_nulls = true
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
specify "should handle IN/NOT IN queries for datasets with row_procs" do
|
|
578
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
579
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
580
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
581
|
+
d1.row_proc = proc{|h| Object.new}
|
|
582
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
583
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
584
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
585
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
569
586
|
end
|
|
570
587
|
|
|
571
588
|
specify "should accept a subquery for an EXISTS clause" do
|
|
@@ -601,10 +618,18 @@ describe "Dataset#where" do
|
|
|
601
618
|
end
|
|
602
619
|
|
|
603
620
|
specify "should accept true and false as arguments" do
|
|
604
|
-
@dataset.filter(true).sql.should ==
|
|
605
|
-
|
|
606
|
-
@dataset.filter(false).sql.should ==
|
|
607
|
-
|
|
621
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE 't'"
|
|
622
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE 't'"
|
|
623
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
624
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
specify "should use boolean expression if dataset does not support where true/false" do
|
|
628
|
+
def @dataset.supports_where_true?() false end
|
|
629
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
630
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
631
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
632
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
608
633
|
end
|
|
609
634
|
|
|
610
635
|
specify "should allow the use of multiple arguments" do
|
|
@@ -658,33 +683,25 @@ describe "Dataset#or" do
|
|
|
658
683
|
end
|
|
659
684
|
|
|
660
685
|
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))'
|
|
686
|
+
@d1.or(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
|
663
687
|
end
|
|
664
688
|
|
|
665
689
|
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))'
|
|
690
|
+
@d1.or('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
|
691
|
+
@d1.or(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
670
692
|
end
|
|
671
693
|
|
|
672
694
|
specify "should accept blocks passed to filter" do
|
|
673
|
-
@d1.or{:yy.sql_number > 3}.sql.should ==
|
|
674
|
-
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
695
|
+
@d1.or{:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
675
696
|
end
|
|
676
697
|
|
|
677
698
|
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))'
|
|
699
|
+
@d1.filter(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
700
|
+
@d1.or(:y => 2).filter(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
683
701
|
end
|
|
684
702
|
|
|
685
703
|
specify "should allow the use of blocks and arguments simultaneously" do
|
|
686
|
-
@d1.or(:zz.sql_number < 3){:yy.sql_number > 3}.sql.should ==
|
|
687
|
-
'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
|
704
|
+
@d1.or(:zz.sql_number < 3){:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
|
688
705
|
end
|
|
689
706
|
end
|
|
690
707
|
|
|
@@ -697,34 +714,25 @@ describe "Dataset#and" do
|
|
|
697
714
|
specify "should raise if no filter exists" do
|
|
698
715
|
proc {@dataset.and(:a => 1)}.should raise_error(Sequel::Error)
|
|
699
716
|
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"
|
|
717
|
+
@dataset.where(:a => 1).group(:t).and(:b => 2).sql.should == "SELECT * FROM test WHERE ((a = 1) AND (b = 2)) GROUP BY t"
|
|
702
718
|
end
|
|
703
719
|
|
|
704
720
|
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))'
|
|
721
|
+
@d1.and(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
|
707
722
|
end
|
|
708
723
|
|
|
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))'
|
|
724
|
+
specify "should accept different types of filters" do
|
|
725
|
+
@d1.and('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
|
726
|
+
@d1.and(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
715
727
|
end
|
|
716
728
|
|
|
717
729
|
specify "should accept blocks passed to filter" do
|
|
718
|
-
@d1.and {:yy.sql_number > 3}.sql.should ==
|
|
719
|
-
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
730
|
+
@d1.and {:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
720
731
|
end
|
|
721
732
|
|
|
722
733
|
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))'
|
|
734
|
+
@d1.or(:y => 2).and(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
735
|
+
@d1.and(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
728
736
|
end
|
|
729
737
|
end
|
|
730
738
|
|
|
@@ -734,8 +742,11 @@ describe "Dataset#exclude" do
|
|
|
734
742
|
end
|
|
735
743
|
|
|
736
744
|
specify "should correctly negate the expression when one condition is given" do
|
|
737
|
-
@dataset.exclude(:region=>'Asia').select_sql.should ==
|
|
738
|
-
|
|
745
|
+
@dataset.exclude(:region=>'Asia').select_sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
specify "should affect the having clause if having clause is already used" do
|
|
749
|
+
@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
750
|
end
|
|
740
751
|
|
|
741
752
|
specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
|
|
@@ -745,30 +756,46 @@ describe "Dataset#exclude" do
|
|
|
745
756
|
end
|
|
746
757
|
|
|
747
758
|
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')"
|
|
759
|
+
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
750
760
|
end
|
|
751
761
|
|
|
752
762
|
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')"
|
|
763
|
+
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
755
764
|
end
|
|
756
765
|
|
|
757
766
|
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'))"
|
|
767
|
+
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
|
760
768
|
end
|
|
761
769
|
|
|
762
770
|
specify "should support proc expressions" do
|
|
763
|
-
@dataset.exclude{:id.sql_number < 6}.sql.should ==
|
|
764
|
-
'SELECT * FROM test WHERE (id >= 6)'
|
|
771
|
+
@dataset.exclude{:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE (id >= 6)'
|
|
765
772
|
end
|
|
766
773
|
|
|
767
774
|
specify "should allow the use of blocks and arguments simultaneously" do
|
|
768
|
-
@dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should ==
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
775
|
+
@dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id < 7) OR (id > 11) OR (id >= 6))'
|
|
776
|
+
@dataset.exclude([:id, 1], [:x, 3]){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id != 1) OR (x != 3) OR (id >= 6))'
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
describe "Dataset#exclude_where" do
|
|
781
|
+
before do
|
|
782
|
+
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
specify "should correctly negate the expression and add it to the where clause" do
|
|
786
|
+
@dataset.exclude_where(:region=>'Asia').sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
787
|
+
@dataset.exclude_where(:region=>'Asia').exclude_where(:region=>'NA').sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (region != 'NA'))"
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
specify "should affect the where clause even if having clause is already used" do
|
|
791
|
+
@dataset.group_and_count(:name).having{count > 2}.exclude_where(:region=>'Asia').sql.should ==
|
|
792
|
+
"SELECT name, count(*) AS count FROM test WHERE (region != 'Asia') GROUP BY name HAVING (count > 2)"
|
|
793
|
+
end
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
describe "Dataset#exclude_having" do
|
|
797
|
+
specify "should correctly negate the expression and add it to the having clause" do
|
|
798
|
+
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
799
|
end
|
|
773
800
|
end
|
|
774
801
|
|
|
@@ -794,9 +821,6 @@ describe "Dataset#having" do
|
|
|
794
821
|
before do
|
|
795
822
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
796
823
|
@grouped = @dataset.group(:region).select(:region, :sum.sql_function(:population), :avg.sql_function(:gdp))
|
|
797
|
-
@d1 = @grouped.having('sum(population) > 10')
|
|
798
|
-
@d2 = @grouped.having(:region => 'Asia')
|
|
799
|
-
@columns = "region, sum(population), avg(gdp)"
|
|
800
824
|
end
|
|
801
825
|
|
|
802
826
|
specify "should just clone if given an empty argument" do
|
|
@@ -806,18 +830,15 @@ describe "Dataset#having" do
|
|
|
806
830
|
end
|
|
807
831
|
|
|
808
832
|
specify "should affect select statements" do
|
|
809
|
-
@
|
|
810
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
833
|
+
@grouped.having('sum(population) > 10').select_sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
811
834
|
end
|
|
812
835
|
|
|
813
836
|
specify "should support proc expressions" do
|
|
814
|
-
@grouped.having {:sum.sql_function(:population) > 10}.sql.should ==
|
|
815
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
837
|
+
@grouped.having {:sum.sql_function(:population) > 10}.sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
816
838
|
end
|
|
817
839
|
|
|
818
840
|
specify "should work with and on the having clause" do
|
|
819
|
-
@grouped.having( :a.sql_number > 1 ).and( :b.sql_number < 2 ).sql.should ==
|
|
820
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
|
|
841
|
+
@grouped.having( :a.sql_number > 1 ).and( :b.sql_number < 2 ).sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
|
|
821
842
|
end
|
|
822
843
|
end
|
|
823
844
|
|
|
@@ -848,7 +869,7 @@ describe "a grouped dataset" do
|
|
|
848
869
|
end
|
|
849
870
|
|
|
850
871
|
specify "should format the right statement for counting (as a subquery)" do
|
|
851
|
-
db =
|
|
872
|
+
db = Sequel.mock
|
|
852
873
|
db[:test].select(:name).group(:name).count
|
|
853
874
|
db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT name FROM test GROUP BY name) AS t1 LIMIT 1"]
|
|
854
875
|
end
|
|
@@ -856,7 +877,7 @@ end
|
|
|
856
877
|
|
|
857
878
|
describe "Dataset#group_by" do
|
|
858
879
|
before do
|
|
859
|
-
@dataset = Sequel
|
|
880
|
+
@dataset = Sequel.mock[:test].group_by(:type_id)
|
|
860
881
|
end
|
|
861
882
|
|
|
862
883
|
specify "should raise when trying to generate an update statement" do
|
|
@@ -868,45 +889,102 @@ describe "Dataset#group_by" do
|
|
|
868
889
|
end
|
|
869
890
|
|
|
870
891
|
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)"
|
|
892
|
+
@dataset.select_sql.should == "SELECT * FROM test GROUP BY type_id"
|
|
893
|
+
@dataset.group_by(:a, :b).select_sql.should == "SELECT * FROM test GROUP BY a, b"
|
|
894
|
+
@dataset.group_by(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
877
895
|
end
|
|
878
896
|
|
|
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"
|
|
897
|
+
specify "should ungroup when passed nil or no arguments" do
|
|
898
|
+
@dataset.group_by.select_sql.should == "SELECT * FROM test"
|
|
899
|
+
@dataset.group_by(nil).select_sql.should == "SELECT * FROM test"
|
|
884
900
|
end
|
|
885
901
|
|
|
886
902
|
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"
|
|
903
|
+
@dataset.group_by(:a).group_by(:b).select_sql.should == "SELECT * FROM test GROUP BY b"
|
|
904
|
+
@dataset.group_by(:a, :b).group_by.select_sql.should == "SELECT * FROM test"
|
|
891
905
|
end
|
|
892
906
|
|
|
893
907
|
specify "should be aliased as #group" do
|
|
894
|
-
@dataset.group(:type_id=>nil).select_sql.should ==
|
|
895
|
-
|
|
908
|
+
@dataset.group(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
specify "should take a virtual row block" do
|
|
912
|
+
@dataset.group{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
913
|
+
@dataset.group_by{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
914
|
+
@dataset.group{[type_id > 1, type_id < 2]}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1), (type_id < 2)"
|
|
915
|
+
@dataset.group(:foo){type_id > 1}.sql.should == "SELECT * FROM test GROUP BY foo, (type_id > 1)"
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
specify "should support a #group_rollup method if the database supports it" do
|
|
919
|
+
@dataset.meta_def(:supports_group_rollup?){true}
|
|
920
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id)"
|
|
921
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id, b)"
|
|
922
|
+
@dataset.meta_def(:uses_with_rollup?){true}
|
|
923
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY type_id WITH ROLLUP"
|
|
924
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY type_id, b WITH ROLLUP"
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
specify "should support a #group_cube method if the database supports it" do
|
|
928
|
+
@dataset.meta_def(:supports_group_cube?){true}
|
|
929
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id)"
|
|
930
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id, b)"
|
|
931
|
+
@dataset.meta_def(:uses_with_rollup?){true}
|
|
932
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY type_id WITH CUBE"
|
|
933
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY type_id, b WITH CUBE"
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
specify "should have #group_cube and #group_rollup methods raise an Error if not supported it" do
|
|
937
|
+
proc{@dataset.group(:type_id).group_rollup}.should raise_error(Sequel::Error)
|
|
938
|
+
proc{@dataset.group(:type_id).group_cube}.should raise_error(Sequel::Error)
|
|
896
939
|
end
|
|
897
940
|
end
|
|
898
941
|
|
|
899
942
|
describe "Dataset#as" do
|
|
900
943
|
specify "should set up an alias" do
|
|
901
944
|
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'
|
|
945
|
+
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
|
904
946
|
end
|
|
905
947
|
end
|
|
906
948
|
|
|
907
949
|
describe "Dataset#literal" do
|
|
908
950
|
before do
|
|
909
|
-
@
|
|
951
|
+
@ds = Sequel::Database.new.dataset
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
specify "should convert qualified symbol notation into dot notation" do
|
|
955
|
+
@ds.literal(:abc__def).should == 'abc.def'
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
specify "should convert AS symbol notation into SQL AS notation" do
|
|
959
|
+
@ds.literal(:xyz___x).should == 'xyz AS x'
|
|
960
|
+
@ds.literal(:abc__def___x).should == 'abc.def AS x'
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
specify "should support names with digits" do
|
|
964
|
+
@ds.literal(:abc2).should == 'abc2'
|
|
965
|
+
@ds.literal(:xx__yy3).should == 'xx.yy3'
|
|
966
|
+
@ds.literal(:ab34__temp3_4ax).should == 'ab34.temp3_4ax'
|
|
967
|
+
@ds.literal(:x1___y2).should == 'x1 AS y2'
|
|
968
|
+
@ds.literal(:abc2__def3___ggg4).should == 'abc2.def3 AS ggg4'
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
specify "should support upper case and lower case" do
|
|
972
|
+
@ds.literal(:ABC).should == 'ABC'
|
|
973
|
+
@ds.literal(:Zvashtoy__aBcD).should == 'Zvashtoy.aBcD'
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
specify "should support spaces inside column names" do
|
|
977
|
+
@ds.quote_identifiers = true
|
|
978
|
+
@ds.literal(:"AB C").should == '"AB C"'
|
|
979
|
+
@ds.literal(:"Zvas htoy__aB cD").should == '"Zvas htoy"."aB cD"'
|
|
980
|
+
@ds.literal(:"aB cD___XX XX").should == '"aB cD" AS "XX XX"'
|
|
981
|
+
@ds.literal(:"Zva shtoy__aB cD___XX XX").should == '"Zva shtoy"."aB cD" AS "XX XX"'
|
|
982
|
+
end
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
describe "Dataset#literal" do
|
|
986
|
+
before do
|
|
987
|
+
@dataset = Sequel::Database.new.from(:test)
|
|
910
988
|
end
|
|
911
989
|
|
|
912
990
|
specify "should escape strings properly" do
|
|
@@ -914,9 +992,9 @@ describe "Dataset#literal" do
|
|
|
914
992
|
@dataset.literal('a"x"bc').should == "'a\"x\"bc'"
|
|
915
993
|
@dataset.literal("a'bc").should == "'a''bc'"
|
|
916
994
|
@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
|
|
995
|
+
@dataset.literal("a\\bc").should == "'a\\bc'"
|
|
996
|
+
@dataset.literal("a\\\\bc").should == "'a\\\\bc'"
|
|
997
|
+
@dataset.literal("a\\'bc").should == "'a\\''bc'"
|
|
920
998
|
end
|
|
921
999
|
|
|
922
1000
|
specify "should escape blobs as strings by default" do
|
|
@@ -944,6 +1022,21 @@ describe "Dataset#literal" do
|
|
|
944
1022
|
@dataset.literal(:"items__na#m$e").should == "items.na#m$e"
|
|
945
1023
|
end
|
|
946
1024
|
|
|
1025
|
+
specify "should call sql_literal_append with dataset and sql on type if not natively supported and the object responds to it" do
|
|
1026
|
+
@a = Class.new do
|
|
1027
|
+
def sql_literal_append(ds, sql)
|
|
1028
|
+
sql << "called #{ds.blah}"
|
|
1029
|
+
end
|
|
1030
|
+
def sql_literal(ds)
|
|
1031
|
+
"not called #{ds.blah}"
|
|
1032
|
+
end
|
|
1033
|
+
end
|
|
1034
|
+
def @dataset.blah
|
|
1035
|
+
"ds"
|
|
1036
|
+
end
|
|
1037
|
+
@dataset.literal(@a.new).should == "called ds"
|
|
1038
|
+
end
|
|
1039
|
+
|
|
947
1040
|
specify "should call sql_literal with dataset on type if not natively supported and the object responds to it" do
|
|
948
1041
|
@a = Class.new do
|
|
949
1042
|
def sql_literal(ds)
|
|
@@ -965,6 +1058,12 @@ describe "Dataset#literal" do
|
|
|
965
1058
|
d.literal(d).should == "(#{d.sql})"
|
|
966
1059
|
end
|
|
967
1060
|
|
|
1061
|
+
specify "should literalize Sequel::SQLTime properly" do
|
|
1062
|
+
t = Sequel::SQLTime.now
|
|
1063
|
+
s = t.strftime("'%H:%M:%S")
|
|
1064
|
+
@dataset.literal(t).should == "#{s}.#{sprintf('%06i', t.usec)}'"
|
|
1065
|
+
end
|
|
1066
|
+
|
|
968
1067
|
specify "should literalize Time properly" do
|
|
969
1068
|
t = Time.now
|
|
970
1069
|
s = t.strftime("'%Y-%m-%d %H:%M:%S")
|
|
@@ -1041,10 +1140,9 @@ describe "Dataset#literal" do
|
|
|
1041
1140
|
end
|
|
1042
1141
|
|
|
1043
1142
|
specify "should not modify literal strings" do
|
|
1143
|
+
@dataset.quote_identifiers = true
|
|
1044
1144
|
@dataset.literal('col1 + 2'.lit).should == 'col1 + 2'
|
|
1045
|
-
|
|
1046
|
-
@dataset.update_sql(:a => 'a + 2'.lit).should ==
|
|
1047
|
-
'UPDATE test SET a = a + 2'
|
|
1145
|
+
@dataset.update_sql(Sequel::SQL::Identifier.new('a'.lit) => 'a + 2'.lit).should == 'UPDATE "test" SET a = a + 2'
|
|
1048
1146
|
end
|
|
1049
1147
|
|
|
1050
1148
|
specify "should literalize BigDecimal instances correctly" do
|
|
@@ -1054,6 +1152,17 @@ describe "Dataset#literal" do
|
|
|
1054
1152
|
@dataset.literal(BigDecimal.new("-Infinity")).should == "'-Infinity'"
|
|
1055
1153
|
end
|
|
1056
1154
|
|
|
1155
|
+
specify "should literalize PlaceholderLiteralStrings correctly" do
|
|
1156
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new('? = ?', [1, 2])).should == '1 = 2'
|
|
1157
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new('? = ?', [1, 2], true)).should == '(1 = 2)'
|
|
1158
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(':a = :b', :a=>1, :b=>2)).should == '1 = 2'
|
|
1159
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(':a = :b', {:a=>1, :b=>2}, true)).should == '(1 = 2)'
|
|
1160
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = ', ''], [1, 2])).should == '1 = 2'
|
|
1161
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = ', ''], [1, 2], true)).should == '(1 = 2)'
|
|
1162
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = '], [1, 2])).should == '1 = 2'
|
|
1163
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = '], [1, 2], true)).should == '(1 = 2)'
|
|
1164
|
+
end
|
|
1165
|
+
|
|
1057
1166
|
specify "should raise an Error if the object can't be literalized" do
|
|
1058
1167
|
proc{@dataset.literal(Object.new)}.should raise_error(Sequel::Error)
|
|
1059
1168
|
end
|
|
@@ -1069,35 +1178,36 @@ describe "Dataset#from" do
|
|
|
1069
1178
|
end
|
|
1070
1179
|
|
|
1071
1180
|
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"
|
|
1181
|
+
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should == "SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
|
|
1074
1182
|
end
|
|
1075
1183
|
|
|
1076
1184
|
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"
|
|
1185
|
+
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
|
|
1079
1186
|
|
|
1080
1187
|
d1 = @dataset.from(:a).group(:b)
|
|
1081
1188
|
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"
|
|
1189
|
+
@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
1190
|
end
|
|
1086
1191
|
|
|
1087
1192
|
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"
|
|
1193
|
+
@dataset.from(:a => :b).sql.should == "SELECT * FROM a AS b"
|
|
1194
|
+
@dataset.from(:a => 'b').sql.should == "SELECT * FROM a AS b"
|
|
1195
|
+
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
|
|
1096
1196
|
end
|
|
1097
1197
|
|
|
1098
1198
|
specify "should always use a subquery if given a dataset" do
|
|
1099
|
-
@dataset.from(@dataset.from(:a)).select_sql.should ==
|
|
1100
|
-
|
|
1199
|
+
@dataset.from(@dataset.from(:a)).select_sql.should == "SELECT * FROM (SELECT * FROM a) AS t1"
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
specify "should treat string arguments as identifiers" do
|
|
1203
|
+
@dataset.quote_identifiers = true
|
|
1204
|
+
@dataset.from('a').select_sql.should == "SELECT * FROM \"a\""
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
specify "should not treat literal strings or blobs as identifiers" do
|
|
1208
|
+
@dataset.quote_identifiers = true
|
|
1209
|
+
@dataset.from('a'.lit).select_sql.should == "SELECT * FROM a"
|
|
1210
|
+
@dataset.from('a'.to_sequel_blob).select_sql.should == "SELECT * FROM 'a'"
|
|
1101
1211
|
end
|
|
1102
1212
|
|
|
1103
1213
|
specify "should remove all FROM tables if called with no arguments" do
|
|
@@ -1105,32 +1215,31 @@ describe "Dataset#from" do
|
|
|
1105
1215
|
end
|
|
1106
1216
|
|
|
1107
1217
|
specify "should accept sql functions" do
|
|
1108
|
-
@dataset.from(:abc.sql_function(:def)).select_sql.should ==
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
@dataset.from(:a.sql_function(:i)).select_sql.should ==
|
|
1112
|
-
"SELECT * FROM a(i)"
|
|
1218
|
+
@dataset.from(:abc.sql_function(:def)).select_sql.should == "SELECT * FROM abc(def)"
|
|
1219
|
+
@dataset.from(:a.sql_function(:i)).select_sql.should == "SELECT * FROM a(i)"
|
|
1113
1220
|
end
|
|
1114
1221
|
|
|
1115
1222
|
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
|
-
|
|
1223
|
+
@dataset.from(:abc__def).select_sql.should == "SELECT * FROM abc.def"
|
|
1224
|
+
@dataset.from(:a_b__c).select_sql.should == "SELECT * FROM a_b.c"
|
|
1225
|
+
@dataset.from(:'#__#').select_sql.should == 'SELECT * FROM #.#'
|
|
1226
|
+
@dataset.from(:abc__def___d).select_sql.should == "SELECT * FROM abc.def AS d"
|
|
1227
|
+
@dataset.from(:a_b__d_e___f_g).select_sql.should == "SELECT * FROM a_b.d_e AS f_g"
|
|
1228
|
+
@dataset.from(:'#__#___#').select_sql.should == 'SELECT * FROM #.# AS #'
|
|
1229
|
+
@dataset.from(:abc___def).select_sql.should == "SELECT * FROM abc AS def"
|
|
1230
|
+
@dataset.from(:a_b___c_d).select_sql.should == "SELECT * FROM a_b AS c_d"
|
|
1231
|
+
@dataset.from(:'#___#').select_sql.should == 'SELECT * FROM # AS #'
|
|
1232
|
+
end
|
|
1233
|
+
|
|
1234
|
+
specify "should not handle :foo__schema__table___alias specially" do
|
|
1235
|
+
@dataset.from(:foo__schema__table___alias).select_sql.should == "SELECT * FROM foo.schema__table AS alias"
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
1239
|
+
@dataset.meta_def(:supports_cte?){true}
|
|
1240
|
+
@dataset.meta_def(:supports_cte_in_subselect?){false}
|
|
1241
|
+
@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'
|
|
1242
|
+
@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
1243
|
end
|
|
1135
1244
|
end
|
|
1136
1245
|
|
|
@@ -1147,39 +1256,39 @@ describe "Dataset#select" do
|
|
|
1147
1256
|
specify "should accept symbols and literal strings" do
|
|
1148
1257
|
@d.select('aaa'.lit).sql.should == 'SELECT aaa FROM test'
|
|
1149
1258
|
@d.select(:a, 'b'.lit).sql.should == 'SELECT a, b FROM test'
|
|
1150
|
-
@d.select(:test__cc, 'test.d AS e'.lit).sql.should ==
|
|
1151
|
-
|
|
1152
|
-
@d.select(
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
@d.select(:test.*).sql.should ==
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
@d.select(:
|
|
1161
|
-
'SELECT test.name AS n FROM test'
|
|
1259
|
+
@d.select(:test__cc, 'test.d AS e'.lit).sql.should == 'SELECT test.cc, test.d AS e FROM test'
|
|
1260
|
+
@d.select('test.d AS e'.lit, :test__cc).sql.should == 'SELECT test.d AS e, test.cc FROM test'
|
|
1261
|
+
@d.select(:test__name___n).sql.should == 'SELECT test.name AS n FROM test'
|
|
1262
|
+
end
|
|
1263
|
+
|
|
1264
|
+
specify "should accept ColumnAlls" do
|
|
1265
|
+
@d.select(:test.*).sql.should == 'SELECT test.* FROM test'
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
specify "should accept QualifiedIdentifiers" do
|
|
1269
|
+
@d.select(:test__name.as(:n)).sql.should == 'SELECT test.name AS n FROM test'
|
|
1162
1270
|
end
|
|
1163
1271
|
|
|
1164
1272
|
specify "should use the wildcard if no arguments are given" do
|
|
1165
1273
|
@d.select.sql.should == 'SELECT * FROM test'
|
|
1166
1274
|
end
|
|
1167
1275
|
|
|
1276
|
+
specify "should handle array condition specifiers that are aliased" do
|
|
1277
|
+
@d.select(Sequel.as([[:b, :c]], :n)).sql.should == 'SELECT (b = c) AS n FROM test'
|
|
1278
|
+
end
|
|
1279
|
+
|
|
1168
1280
|
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/
|
|
1281
|
+
@d.select(:name => 'n', :__ggh => 'age').sql.should =~ /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
|
1171
1282
|
end
|
|
1172
1283
|
|
|
1173
|
-
specify "should
|
|
1284
|
+
specify "should override the previous select option" do
|
|
1174
1285
|
@d.select!(:a, :b, :c).select.sql.should == 'SELECT * FROM test'
|
|
1175
1286
|
@d.select!(:price).select(:name).sql.should == 'SELECT name FROM test'
|
|
1176
1287
|
end
|
|
1177
1288
|
|
|
1178
1289
|
specify "should accept arbitrary objects and literalize them correctly" do
|
|
1179
1290
|
@d.select(1, :a, 't').sql.should == "SELECT 1, a, 't' FROM test"
|
|
1180
|
-
|
|
1181
1291
|
@d.select(nil, :sum.sql_function(:t), :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
|
|
1182
|
-
|
|
1183
1292
|
@d.select(nil, 1, :x => :y).sql.should == "SELECT NULL, 1, x AS y FROM test"
|
|
1184
1293
|
end
|
|
1185
1294
|
|
|
@@ -1198,6 +1307,27 @@ describe "Dataset#select" do
|
|
|
1198
1307
|
end
|
|
1199
1308
|
end
|
|
1200
1309
|
|
|
1310
|
+
describe "Dataset#select_group" do
|
|
1311
|
+
before do
|
|
1312
|
+
@d = Sequel::Dataset.new(nil).from(:test)
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
specify "should set both SELECT and GROUP" do
|
|
1316
|
+
@d.select_group(:name).sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1317
|
+
@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'
|
|
1318
|
+
end
|
|
1319
|
+
|
|
1320
|
+
specify "should remove from both SELECT and GROUP if no arguments" do
|
|
1321
|
+
@d.select_group(:name).select_group.sql.should == 'SELECT * FROM test'
|
|
1322
|
+
end
|
|
1323
|
+
|
|
1324
|
+
specify "should accept virtual row blocks" do
|
|
1325
|
+
@d.select_group{name}.sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1326
|
+
@d.select_group{[name, f(v).as(a)]}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1327
|
+
@d.select_group(:name){f(v).as(a)}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1328
|
+
end
|
|
1329
|
+
end
|
|
1330
|
+
|
|
1201
1331
|
describe "Dataset#select_all" do
|
|
1202
1332
|
before do
|
|
1203
1333
|
@d = Sequel::Dataset.new(nil).from(:test)
|
|
@@ -1207,9 +1337,43 @@ describe "Dataset#select_all" do
|
|
|
1207
1337
|
@d.select_all.sql.should == 'SELECT * FROM test'
|
|
1208
1338
|
end
|
|
1209
1339
|
|
|
1210
|
-
specify "should
|
|
1340
|
+
specify "should override the previous select option" do
|
|
1211
1341
|
@d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
|
|
1212
1342
|
end
|
|
1343
|
+
|
|
1344
|
+
specify "should select all columns in a table if given an argument" do
|
|
1345
|
+
@d.select_all(:test).sql.should == 'SELECT test.* FROM test'
|
|
1346
|
+
end
|
|
1347
|
+
|
|
1348
|
+
specify "should select all columns all tables if given a multiple arguments" do
|
|
1349
|
+
@d.select_all(:test, :foo).sql.should == 'SELECT test.*, foo.* FROM test'
|
|
1350
|
+
end
|
|
1351
|
+
|
|
1352
|
+
specify "should work correctly with qualified symbols" do
|
|
1353
|
+
@d.select_all(:sch__test).sql.should == 'SELECT sch.test.* FROM test'
|
|
1354
|
+
end
|
|
1355
|
+
|
|
1356
|
+
specify "should work correctly with aliased symbols" do
|
|
1357
|
+
@d.select_all(:test___al).sql.should == 'SELECT al.* FROM test'
|
|
1358
|
+
@d.select_all(:sch__test___al).sql.should == 'SELECT al.* FROM test'
|
|
1359
|
+
end
|
|
1360
|
+
|
|
1361
|
+
specify "should work correctly with SQL::Identifiers" do
|
|
1362
|
+
@d.select_all(:test.identifier).sql.should == 'SELECT test.* FROM test'
|
|
1363
|
+
end
|
|
1364
|
+
|
|
1365
|
+
specify "should work correctly with SQL::QualifiedIdentifier" do
|
|
1366
|
+
@d.select_all(:test.qualify(:sch)).sql.should == 'SELECT sch.test.* FROM test'
|
|
1367
|
+
end
|
|
1368
|
+
|
|
1369
|
+
specify "should work correctly with SQL::AliasedExpressions" do
|
|
1370
|
+
@d.select_all(:test.as(:al)).sql.should == 'SELECT al.* FROM test'
|
|
1371
|
+
end
|
|
1372
|
+
|
|
1373
|
+
specify "should work correctly with SQL::JoinClauses" do
|
|
1374
|
+
d = @d.cross_join(:foo).cross_join(:test___al)
|
|
1375
|
+
@d.select_all(*d.opts[:join]).sql.should == 'SELECT foo.*, al.* FROM test'
|
|
1376
|
+
end
|
|
1213
1377
|
end
|
|
1214
1378
|
|
|
1215
1379
|
describe "Dataset#select_more" do
|
|
@@ -1254,6 +1418,14 @@ describe "Dataset#select_append" do
|
|
|
1254
1418
|
@d.select(:a).select_append{|o| o.b}.sql.should == 'SELECT a, b FROM test'
|
|
1255
1419
|
@d.select(:a.*).select_append(:b.*){b(1)}.sql.should == 'SELECT a.*, b.*, b(1) FROM test'
|
|
1256
1420
|
end
|
|
1421
|
+
|
|
1422
|
+
specify "should select from all from and join tables if SELECT *, column not supported" do
|
|
1423
|
+
@d.meta_def(:supports_select_all_and_column?){false}
|
|
1424
|
+
@d.select_append(:b).sql.should == 'SELECT test.*, b FROM test'
|
|
1425
|
+
@d.from(:test, :c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test, c'
|
|
1426
|
+
@d.cross_join(:c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test CROSS JOIN c'
|
|
1427
|
+
@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'
|
|
1428
|
+
end
|
|
1257
1429
|
end
|
|
1258
1430
|
|
|
1259
1431
|
describe "Dataset#order" do
|
|
@@ -1262,38 +1434,31 @@ describe "Dataset#order" do
|
|
|
1262
1434
|
end
|
|
1263
1435
|
|
|
1264
1436
|
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'
|
|
1437
|
+
@dataset.order(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1267
1438
|
end
|
|
1268
1439
|
|
|
1269
1440
|
specify "should accept multiple arguments" do
|
|
1270
|
-
@dataset.order(:name, :price.desc).sql.should ==
|
|
1271
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1441
|
+
@dataset.order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1272
1442
|
end
|
|
1273
1443
|
|
|
1274
1444
|
specify "should accept :nulls options for asc and desc" do
|
|
1275
|
-
@dataset.order(:name.asc(:nulls=>:last), :price.desc(:nulls=>:first)).sql.should ==
|
|
1276
|
-
'SELECT * FROM test ORDER BY name ASC NULLS LAST, price DESC NULLS FIRST'
|
|
1445
|
+
@dataset.order(:name.asc(:nulls=>:last), :price.desc(:nulls=>:first)).sql.should == 'SELECT * FROM test ORDER BY name ASC NULLS LAST, price DESC NULLS FIRST'
|
|
1277
1446
|
end
|
|
1278
1447
|
|
|
1279
|
-
specify "should
|
|
1280
|
-
@dataset.order(:name).order(:stamp).sql.should ==
|
|
1281
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1448
|
+
specify "should override a previous ordering" do
|
|
1449
|
+
@dataset.order(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1282
1450
|
end
|
|
1283
1451
|
|
|
1284
1452
|
specify "should accept a literal string" do
|
|
1285
|
-
@dataset.order('dada ASC'.lit).sql.should ==
|
|
1286
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1453
|
+
@dataset.order('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1287
1454
|
end
|
|
1288
1455
|
|
|
1289
1456
|
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)'
|
|
1457
|
+
@dataset.order(:name=>nil).sql.should == 'SELECT * FROM test ORDER BY (name IS NULL)'
|
|
1292
1458
|
end
|
|
1293
1459
|
|
|
1294
1460
|
specify "should accept a nil to remove ordering" do
|
|
1295
|
-
@dataset.order(:bah).order(nil).sql.should ==
|
|
1296
|
-
'SELECT * FROM test'
|
|
1461
|
+
@dataset.order(:bah).order(nil).sql.should == 'SELECT * FROM test'
|
|
1297
1462
|
end
|
|
1298
1463
|
|
|
1299
1464
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1355,6 +1520,13 @@ describe "Dataset#with_sql" do
|
|
|
1355
1520
|
specify "should keep row_proc" do
|
|
1356
1521
|
@dataset.with_sql('SELECT 1 FROM test').row_proc.should == @dataset.row_proc
|
|
1357
1522
|
end
|
|
1523
|
+
|
|
1524
|
+
specify "should work with method symbols and arguments" do
|
|
1525
|
+
@dataset.with_sql(:delete_sql).sql.should == 'DELETE FROM test'
|
|
1526
|
+
@dataset.with_sql(:insert_sql, :b=>1).sql.should == 'INSERT INTO test (b) VALUES (1)'
|
|
1527
|
+
@dataset.with_sql(:update_sql, :b=>1).sql.should == 'UPDATE test SET b = 1'
|
|
1528
|
+
end
|
|
1529
|
+
|
|
1358
1530
|
end
|
|
1359
1531
|
|
|
1360
1532
|
describe "Dataset#order_by" do
|
|
@@ -1363,28 +1535,23 @@ describe "Dataset#order_by" do
|
|
|
1363
1535
|
end
|
|
1364
1536
|
|
|
1365
1537
|
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'
|
|
1538
|
+
@dataset.order_by(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1368
1539
|
end
|
|
1369
1540
|
|
|
1370
1541
|
specify "should accept multiple arguments" do
|
|
1371
|
-
@dataset.order_by(:name, :price.desc).sql.should ==
|
|
1372
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1542
|
+
@dataset.order_by(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1373
1543
|
end
|
|
1374
1544
|
|
|
1375
|
-
specify "should
|
|
1376
|
-
@dataset.order_by(:name).order(:stamp).sql.should ==
|
|
1377
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1545
|
+
specify "should override a previous ordering" do
|
|
1546
|
+
@dataset.order_by(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1378
1547
|
end
|
|
1379
1548
|
|
|
1380
1549
|
specify "should accept a string" do
|
|
1381
|
-
@dataset.order_by('dada ASC'.lit).sql.should ==
|
|
1382
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1550
|
+
@dataset.order_by('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1383
1551
|
end
|
|
1384
1552
|
|
|
1385
1553
|
specify "should accept a nil to remove ordering" do
|
|
1386
|
-
@dataset.order_by(:bah).order_by(nil).sql.should ==
|
|
1387
|
-
'SELECT * FROM test'
|
|
1554
|
+
@dataset.order_by(:bah).order_by(nil).sql.should == 'SELECT * FROM test'
|
|
1388
1555
|
end
|
|
1389
1556
|
end
|
|
1390
1557
|
|
|
@@ -1417,13 +1584,11 @@ describe "Dataset#order_prepend" do
|
|
|
1417
1584
|
end
|
|
1418
1585
|
|
|
1419
1586
|
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'
|
|
1587
|
+
@dataset.order_prepend(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1422
1588
|
end
|
|
1423
1589
|
|
|
1424
1590
|
specify "should add to the beginning of a previous ordering" do
|
|
1425
|
-
@dataset.order(:name).order_prepend(:stamp.desc).sql.should ==
|
|
1426
|
-
'SELECT * FROM test ORDER BY stamp DESC, name'
|
|
1591
|
+
@dataset.order(:name).order_prepend(:stamp.desc).sql.should == 'SELECT * FROM test ORDER BY stamp DESC, name'
|
|
1427
1592
|
end
|
|
1428
1593
|
|
|
1429
1594
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1438,45 +1603,36 @@ describe "Dataset#reverse_order" do
|
|
|
1438
1603
|
end
|
|
1439
1604
|
|
|
1440
1605
|
specify "should use DESC as default order" do
|
|
1441
|
-
@dataset.reverse_order(:name).sql.should ==
|
|
1442
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1606
|
+
@dataset.reverse_order(:name).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1443
1607
|
end
|
|
1444
1608
|
|
|
1445
1609
|
specify "should invert the order given" do
|
|
1446
|
-
@dataset.reverse_order(:name.desc).sql.should ==
|
|
1447
|
-
'SELECT * FROM test ORDER BY name ASC'
|
|
1610
|
+
@dataset.reverse_order(:name.desc).sql.should == 'SELECT * FROM test ORDER BY name ASC'
|
|
1448
1611
|
end
|
|
1449
1612
|
|
|
1450
1613
|
specify "should invert the order for ASC expressions" do
|
|
1451
|
-
@dataset.reverse_order(:name.asc).sql.should ==
|
|
1452
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1614
|
+
@dataset.reverse_order(:name.asc).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1453
1615
|
end
|
|
1454
1616
|
|
|
1455
1617
|
specify "should accept multiple arguments" do
|
|
1456
|
-
@dataset.reverse_order(:name, :price.desc).sql.should ==
|
|
1457
|
-
'SELECT * FROM test ORDER BY name DESC, price ASC'
|
|
1618
|
+
@dataset.reverse_order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name DESC, price ASC'
|
|
1458
1619
|
end
|
|
1459
1620
|
|
|
1460
1621
|
specify "should handles NULLS ordering correctly when reversing" do
|
|
1461
|
-
@dataset.reverse_order(:name.asc(:nulls=>:first), :price.desc(:nulls=>:last)).sql.should ==
|
|
1462
|
-
'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
|
|
1622
|
+
@dataset.reverse_order(:name.asc(:nulls=>:first), :price.desc(:nulls=>:last)).sql.should == 'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
|
|
1463
1623
|
end
|
|
1464
1624
|
|
|
1465
1625
|
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'
|
|
1626
|
+
@dataset.order(:name).reverse_order.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1627
|
+
@dataset.order(:clumsy.desc, :fool).reverse_order.sql.should == 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
|
|
1470
1628
|
end
|
|
1471
1629
|
|
|
1472
1630
|
specify "should return an unordered dataset for a dataset with no order" do
|
|
1473
|
-
@dataset.unordered.reverse_order.sql.should ==
|
|
1474
|
-
'SELECT * FROM test'
|
|
1631
|
+
@dataset.unordered.reverse_order.sql.should == 'SELECT * FROM test'
|
|
1475
1632
|
end
|
|
1476
1633
|
|
|
1477
1634
|
specify "should have #reverse alias" do
|
|
1478
|
-
@dataset.order(:name).reverse.sql.should ==
|
|
1479
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1635
|
+
@dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1480
1636
|
end
|
|
1481
1637
|
end
|
|
1482
1638
|
|
|
@@ -1486,42 +1642,33 @@ describe "Dataset#limit" do
|
|
|
1486
1642
|
end
|
|
1487
1643
|
|
|
1488
1644
|
specify "should include a LIMIT clause in the select statement" do
|
|
1489
|
-
@dataset.limit(10).sql.should ==
|
|
1490
|
-
'SELECT * FROM test LIMIT 10'
|
|
1645
|
+
@dataset.limit(10).sql.should == 'SELECT * FROM test LIMIT 10'
|
|
1491
1646
|
end
|
|
1492
1647
|
|
|
1493
1648
|
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'
|
|
1649
|
+
@dataset.limit(3..7).sql.should == 'SELECT * FROM test LIMIT 5 OFFSET 3'
|
|
1650
|
+
@dataset.limit(3...7).sql.should == 'SELECT * FROM test LIMIT 4 OFFSET 3'
|
|
1499
1651
|
end
|
|
1500
1652
|
|
|
1501
1653
|
specify "should include an offset if a second argument is given" do
|
|
1502
|
-
@dataset.limit(6, 10).sql.should ==
|
|
1503
|
-
|
|
1504
|
-
end
|
|
1654
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 10'
|
|
1655
|
+
end
|
|
1505
1656
|
|
|
1506
1657
|
specify "should convert regular strings to integers" do
|
|
1507
|
-
@dataset.limit('6', 'a() - 1').sql.should ==
|
|
1508
|
-
'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1658
|
+
@dataset.limit('6', 'a() - 1').sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1509
1659
|
end
|
|
1510
1660
|
|
|
1511
1661
|
specify "should not convert literal strings to integers" do
|
|
1512
|
-
@dataset.limit('6'.lit, 'a() - 1'.lit).sql.should ==
|
|
1513
|
-
'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1662
|
+
@dataset.limit('6'.lit, 'a() - 1'.lit).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1514
1663
|
end
|
|
1515
1664
|
|
|
1516
1665
|
specify "should not convert other objects" do
|
|
1517
|
-
@dataset.limit(6, :a.sql_function - 1).sql.should ==
|
|
1518
|
-
'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1666
|
+
@dataset.limit(6, :a.sql_function - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1519
1667
|
end
|
|
1520
1668
|
|
|
1521
1669
|
specify "should work with fixed sql datasets" do
|
|
1522
1670
|
@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'
|
|
1671
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
|
1525
1672
|
end
|
|
1526
1673
|
|
|
1527
1674
|
specify "should raise an error if an invalid limit or offset is used" do
|
|
@@ -1535,15 +1682,20 @@ describe "Dataset#limit" do
|
|
|
1535
1682
|
end
|
|
1536
1683
|
|
|
1537
1684
|
describe "Dataset#naked" do
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1685
|
+
specify "should returned clone dataset without row_proc" do
|
|
1686
|
+
d = Sequel::Dataset.new(nil)
|
|
1687
|
+
d.row_proc = Proc.new{|r| r}
|
|
1688
|
+
d.naked.row_proc.should be_nil
|
|
1689
|
+
d.row_proc.should_not be_nil
|
|
1542
1690
|
end
|
|
1543
|
-
|
|
1691
|
+
end
|
|
1692
|
+
|
|
1693
|
+
describe "Dataset#naked!" do
|
|
1544
1694
|
specify "should remove any existing row_proc" do
|
|
1545
|
-
|
|
1546
|
-
|
|
1695
|
+
d = Sequel::Dataset.new(nil)
|
|
1696
|
+
d.row_proc = Proc.new{|r| r}
|
|
1697
|
+
d.naked!.row_proc.should be_nil
|
|
1698
|
+
d.row_proc.should be_nil
|
|
1547
1699
|
end
|
|
1548
1700
|
end
|
|
1549
1701
|
|
|
@@ -1571,38 +1723,42 @@ describe "Dataset#qualified_column_name" do
|
|
|
1571
1723
|
end
|
|
1572
1724
|
end
|
|
1573
1725
|
|
|
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)
|
|
1582
|
-
end
|
|
1583
|
-
end
|
|
1584
|
-
|
|
1585
1726
|
describe "Dataset#map" do
|
|
1586
1727
|
before do
|
|
1587
|
-
@d =
|
|
1728
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1588
1729
|
end
|
|
1589
1730
|
|
|
1590
1731
|
specify "should provide the usual functionality if no argument is given" do
|
|
1591
|
-
@d.map
|
|
1732
|
+
@d.map{|n| n[:a] + n[:b]}.should == [3, 7, 11]
|
|
1592
1733
|
end
|
|
1593
1734
|
|
|
1594
1735
|
specify "should map using #[column name] if column name is given" do
|
|
1595
1736
|
@d.map(:a).should == [1, 3, 5]
|
|
1596
1737
|
end
|
|
1597
1738
|
|
|
1739
|
+
specify "should support multiple column names if an array of column names is given" do
|
|
1740
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1741
|
+
end
|
|
1742
|
+
|
|
1743
|
+
specify "should not call the row_proc if an argument is given" do
|
|
1744
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1745
|
+
@d.map(:a).should == [1, 3, 5]
|
|
1746
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1747
|
+
end
|
|
1748
|
+
|
|
1749
|
+
specify "should call the row_proc if no argument is given" do
|
|
1750
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1751
|
+
@d.map{|n| n[:a] + n[:b]}.should == [6, 14, 22]
|
|
1752
|
+
end
|
|
1753
|
+
|
|
1598
1754
|
specify "should return the complete dataset values if nothing is given" do
|
|
1599
|
-
@d.map.to_a.should ==
|
|
1755
|
+
@d.map.to_a.should == [{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}]
|
|
1600
1756
|
end
|
|
1601
1757
|
end
|
|
1602
1758
|
|
|
1603
1759
|
describe "Dataset#to_hash" do
|
|
1604
1760
|
before do
|
|
1605
|
-
@d =
|
|
1761
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1606
1762
|
end
|
|
1607
1763
|
|
|
1608
1764
|
specify "should provide a hash with the first column as key and the second as value" do
|
|
@@ -1614,11 +1770,73 @@ describe "Dataset#to_hash" do
|
|
|
1614
1770
|
@d.to_hash(:a).should == {1 => {:a => 1, :b => 2}, 3 => {:a => 3, :b => 4}, 5 => {:a => 5, :b => 6}}
|
|
1615
1771
|
@d.to_hash(:b).should == {2 => {:a => 1, :b => 2}, 4 => {:a => 3, :b => 4}, 6 => {:a => 5, :b => 6}}
|
|
1616
1772
|
end
|
|
1773
|
+
|
|
1774
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1775
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1776
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1777
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1778
|
+
@d.to_hash([:a, :b]).should == {[1, 2] => {:a => 1, :b => 2}, [3, 4] => {:a => 3, :b => 4}, [5, 6] => {:a => 5, :b => 6}}
|
|
1779
|
+
end
|
|
1780
|
+
|
|
1781
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1782
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1783
|
+
@d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
|
|
1784
|
+
@d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
|
|
1785
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1786
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1787
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1788
|
+
end
|
|
1789
|
+
|
|
1790
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1791
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1792
|
+
@d.to_hash(:a).should == {2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12}}
|
|
1793
|
+
@d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
|
|
1794
|
+
@d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
|
|
1795
|
+
end
|
|
1796
|
+
end
|
|
1797
|
+
|
|
1798
|
+
describe "Dataset#to_hash_groups" do
|
|
1799
|
+
before do
|
|
1800
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 1, :b => 6}, {:a => 7, :b => 4}])[:items]
|
|
1801
|
+
end
|
|
1802
|
+
|
|
1803
|
+
specify "should provide a hash with the first column as key and the second as value" do
|
|
1804
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1805
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1806
|
+
end
|
|
1807
|
+
|
|
1808
|
+
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
|
|
1809
|
+
@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}]}
|
|
1810
|
+
@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}]}
|
|
1811
|
+
end
|
|
1812
|
+
|
|
1813
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1814
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1815
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1816
|
+
@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]]}
|
|
1817
|
+
@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}]}
|
|
1818
|
+
end
|
|
1819
|
+
|
|
1820
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1821
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1822
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1823
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1824
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1825
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1826
|
+
@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]]}
|
|
1827
|
+
end
|
|
1828
|
+
|
|
1829
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1830
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1831
|
+
@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}]}
|
|
1832
|
+
@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}]}
|
|
1833
|
+
@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}]}
|
|
1834
|
+
end
|
|
1617
1835
|
end
|
|
1618
1836
|
|
|
1619
1837
|
describe "Dataset#distinct" do
|
|
1620
1838
|
before do
|
|
1621
|
-
@db =
|
|
1839
|
+
@db = Sequel.mock
|
|
1622
1840
|
@dataset = @db[:test].select(:name)
|
|
1623
1841
|
end
|
|
1624
1842
|
|
|
@@ -1645,132 +1863,100 @@ end
|
|
|
1645
1863
|
|
|
1646
1864
|
describe "Dataset#count" do
|
|
1647
1865
|
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)
|
|
1866
|
+
@db = Sequel.mock(:fetch=>{:count=>1})
|
|
1867
|
+
@dataset = @db.from(:test).columns(:count)
|
|
1660
1868
|
end
|
|
1661
1869
|
|
|
1662
1870
|
specify "should format SQL properly" do
|
|
1663
1871
|
@dataset.count.should == 1
|
|
1664
|
-
@
|
|
1872
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
|
|
1665
1873
|
end
|
|
1666
1874
|
|
|
1667
1875
|
specify "should include the where clause if it's there" do
|
|
1668
1876
|
@dataset.filter(:abc.sql_number < 30).count.should == 1
|
|
1669
|
-
@
|
|
1877
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
|
|
1670
1878
|
end
|
|
1671
1879
|
|
|
1672
1880
|
specify "should count properly for datasets with fixed sql" do
|
|
1673
1881
|
@dataset.opts[:sql] = "select abc from xyz"
|
|
1674
1882
|
@dataset.count.should == 1
|
|
1675
|
-
@
|
|
1883
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
|
|
1676
1884
|
end
|
|
1677
1885
|
|
|
1678
1886
|
specify "should count properly when using UNION, INTERSECT, or EXCEPT" do
|
|
1679
1887
|
@dataset.union(@dataset).count.should == 1
|
|
1680
|
-
@
|
|
1888
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1681
1889
|
@dataset.intersect(@dataset).count.should == 1
|
|
1682
|
-
@
|
|
1890
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1683
1891
|
@dataset.except(@dataset).count.should == 1
|
|
1684
|
-
@
|
|
1892
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1685
1893
|
end
|
|
1686
1894
|
|
|
1687
1895
|
specify "should return limit if count is greater than it" do
|
|
1688
1896
|
@dataset.limit(5).count.should == 1
|
|
1689
|
-
@
|
|
1897
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"]
|
|
1690
1898
|
end
|
|
1691
1899
|
|
|
1692
1900
|
it "should work on a graphed_dataset" do
|
|
1693
1901
|
@dataset.should_receive(:columns).twice.and_return([:a])
|
|
1694
1902
|
@dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
|
|
1695
|
-
@
|
|
1903
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
1696
1904
|
end
|
|
1697
1905
|
|
|
1698
1906
|
specify "should not cache the columns value" do
|
|
1699
|
-
ds = @dataset.from(:blah)
|
|
1907
|
+
ds = @dataset.from(:blah).columns(:a)
|
|
1700
1908
|
ds.columns.should == [:a]
|
|
1701
1909
|
ds.count.should == 1
|
|
1702
|
-
@
|
|
1910
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM blah LIMIT 1']
|
|
1703
1911
|
ds.columns.should == [:a]
|
|
1704
1912
|
end
|
|
1705
1913
|
end
|
|
1706
1914
|
|
|
1707
|
-
|
|
1708
1915
|
describe "Dataset#group_and_count" do
|
|
1709
1916
|
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)
|
|
1917
|
+
@ds = Sequel::Dataset.new(nil).from(:test)
|
|
1721
1918
|
end
|
|
1722
1919
|
|
|
1723
1920
|
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"
|
|
1921
|
+
@ds.group_and_count(:name).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1726
1922
|
end
|
|
1727
1923
|
|
|
1728
1924
|
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"
|
|
1925
|
+
@ds.group_and_count(:a, :b).sql.should == "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
|
|
1731
1926
|
end
|
|
1732
1927
|
|
|
1733
1928
|
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"
|
|
1929
|
+
@ds.group_and_count(:name___n).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1930
|
+
@ds.group_and_count(:name__n).sql.should == "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
|
1738
1931
|
end
|
|
1739
1932
|
|
|
1740
1933
|
specify "should handle identifiers" do
|
|
1741
|
-
@ds.group_and_count(:name___n.identifier).sql.should ==
|
|
1742
|
-
"SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1934
|
+
@ds.group_and_count(:name___n.identifier).sql.should == "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1743
1935
|
end
|
|
1744
1936
|
|
|
1745
1937
|
specify "should handle literal strings" do
|
|
1746
|
-
@ds.group_and_count("name".lit).sql.should ==
|
|
1747
|
-
"SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1938
|
+
@ds.group_and_count("name".lit).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1748
1939
|
end
|
|
1749
1940
|
|
|
1750
1941
|
specify "should handle aliased expressions" do
|
|
1751
|
-
@ds.group_and_count(:name.as(:n)).sql.should ==
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1942
|
+
@ds.group_and_count(:name.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1943
|
+
@ds.group_and_count(:name.identifier.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1944
|
+
end
|
|
1945
|
+
|
|
1946
|
+
specify "should take a virtual row block" do
|
|
1947
|
+
@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)"
|
|
1948
|
+
@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)"
|
|
1949
|
+
@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
1950
|
end
|
|
1756
1951
|
end
|
|
1757
1952
|
|
|
1758
1953
|
describe "Dataset#empty?" do
|
|
1759
1954
|
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"
|
|
1955
|
+
db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
|
|
1956
|
+
db.from(:test).should_not be_empty
|
|
1957
|
+
db.sqls.should == ['SELECT 1 AS one FROM test LIMIT 1']
|
|
1958
|
+
db.from(:test).filter(false).should be_empty
|
|
1959
|
+
db.sqls.should == ["SELECT 1 AS one FROM test WHERE 'f' LIMIT 1"]
|
|
1774
1960
|
end
|
|
1775
1961
|
end
|
|
1776
1962
|
|
|
@@ -1817,9 +2003,9 @@ describe "Dataset#first_source_table" do
|
|
|
1817
2003
|
end
|
|
1818
2004
|
|
|
1819
2005
|
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 ==
|
|
2006
|
+
@ds.literal(@ds.from(:t___a).first_source_table).should == "t"
|
|
2007
|
+
@ds.literal(@ds.from(:s__t___a).first_source_table).should == "s.t"
|
|
2008
|
+
@ds.literal(@ds.from(:t.as(:a)).first_source_table).should == "t"
|
|
1823
2009
|
end
|
|
1824
2010
|
|
|
1825
2011
|
specify "should raise exception if table doesn't have a source" do
|
|
@@ -1849,25 +2035,31 @@ describe "Dataset#from_self" do
|
|
|
1849
2035
|
'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
|
|
1850
2036
|
end
|
|
1851
2037
|
|
|
1852
|
-
specify "should not options such as server" do
|
|
2038
|
+
specify "should not remove non-SQL options such as :server" do
|
|
1853
2039
|
@ds.server(:blah).from_self(:alias=>:some_name).opts[:server].should == :blah
|
|
1854
2040
|
end
|
|
1855
2041
|
|
|
2042
|
+
specify "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
|
|
2043
|
+
ds = Sequel::Dataset.new(nil)
|
|
2044
|
+
ds.meta_def(:supports_cte?){true}
|
|
2045
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2046
|
+
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'
|
|
2047
|
+
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'
|
|
2048
|
+
end
|
|
1856
2049
|
end
|
|
1857
2050
|
|
|
1858
2051
|
describe "Dataset#join_table" do
|
|
1859
2052
|
before do
|
|
1860
|
-
@d =
|
|
2053
|
+
@d = Sequel::Dataset.new(nil).from(:items)
|
|
1861
2054
|
@d.quote_identifiers = true
|
|
1862
2055
|
end
|
|
1863
2056
|
|
|
1864
2057
|
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")'
|
|
2058
|
+
@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
2059
|
end
|
|
1868
2060
|
|
|
1869
2061
|
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 ==
|
|
2062
|
+
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
|
1871
2063
|
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND ("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100))'
|
|
1872
2064
|
end
|
|
1873
2065
|
|
|
@@ -1877,45 +2069,30 @@ describe "Dataset#join_table" do
|
|
|
1877
2069
|
end
|
|
1878
2070
|
|
|
1879
2071
|
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"'
|
|
2072
|
+
@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
2073
|
end
|
|
1883
2074
|
|
|
1884
2075
|
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")'
|
|
2076
|
+
@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
2077
|
end
|
|
1888
2078
|
|
|
1889
2079
|
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")'
|
|
2080
|
+
@d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1892
2081
|
end
|
|
1893
2082
|
|
|
1894
2083
|
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"'
|
|
2084
|
+
@d.left_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2085
|
+
@d.right_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2086
|
+
@d.full_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2087
|
+
@d.inner_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2088
|
+
@d.left_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2089
|
+
@d.right_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2090
|
+
@d.full_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
2091
|
+
@d.natural_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2092
|
+
@d.natural_left_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
|
|
2093
|
+
@d.natural_right_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
|
|
2094
|
+
@d.natural_full_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
|
|
2095
|
+
@d.cross_join(:categories).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
1919
2096
|
end
|
|
1920
2097
|
|
|
1921
2098
|
specify "should raise an error if additional arguments are provided to join methods that don't take conditions" do
|
|
@@ -1935,95 +2112,68 @@ describe "Dataset#join_table" do
|
|
|
1935
2112
|
end
|
|
1936
2113
|
|
|
1937
2114
|
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")'
|
|
2115
|
+
@d.join_table(nil, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1940
2116
|
end
|
|
1941
2117
|
|
|
1942
2118
|
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")'
|
|
2119
|
+
@d.join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1945
2120
|
end
|
|
1946
2121
|
|
|
1947
2122
|
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")'
|
|
2123
|
+
@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
2124
|
end
|
|
1951
2125
|
|
|
1952
2126
|
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")'
|
|
2127
|
+
@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
2128
|
end
|
|
1956
2129
|
|
|
1957
2130
|
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")'
|
|
2131
|
+
@d.from('stats').join(:players.as(:p), {:id => :player_id}).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
|
1960
2132
|
end
|
|
1961
2133
|
|
|
1962
2134
|
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")'
|
|
2135
|
+
@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
2136
|
end
|
|
1968
2137
|
|
|
1969
2138
|
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")'
|
|
2139
|
+
@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
2140
|
end
|
|
1973
2141
|
|
|
1974
2142
|
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")'
|
|
2143
|
+
@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")'
|
|
2144
|
+
@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
2145
|
end
|
|
1980
2146
|
|
|
1981
2147
|
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")'
|
|
2148
|
+
@d.from(:s.as(:t)).join(: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
2149
|
end
|
|
1985
2150
|
|
|
1986
2151
|
specify "should support the :implicit_qualifier option" do
|
|
1987
|
-
@d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should ==
|
|
1988
|
-
'SELECT * FROM "stats" INNER JOIN "players" ON ("players"."id" = "p"."player_id")'
|
|
2152
|
+
@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")'
|
|
1989
2153
|
end
|
|
1990
2154
|
|
|
1991
2155
|
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))'
|
|
2156
|
+
@d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
|
2157
|
+
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
|
2158
|
+
@d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
|
2159
|
+
@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
2160
|
end
|
|
2001
2161
|
|
|
2002
2162
|
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)
|
|
2163
|
+
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.should raise_error(Sequel::Error)
|
|
2005
2164
|
end
|
|
2006
2165
|
|
|
2007
2166
|
specify "should support joining datasets" do
|
|
2008
2167
|
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
|
-
|
|
2168
|
+
@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
2169
|
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")'
|
|
2170
|
+
@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")'
|
|
2171
|
+
@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
2172
|
end
|
|
2021
2173
|
|
|
2022
2174
|
specify "should support joining datasets and aliasing the join" do
|
|
2023
2175
|
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")'
|
|
2176
|
+
@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
2177
|
end
|
|
2028
2178
|
|
|
2029
2179
|
specify "should support joining multiple datasets" do
|
|
@@ -2040,40 +2190,30 @@ describe "Dataset#join_table" do
|
|
|
2040
2190
|
specify "should support joining objects that respond to :table_name" do
|
|
2041
2191
|
ds = Object.new
|
|
2042
2192
|
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")'
|
|
2193
|
+
@d.join(ds, :item_id => :id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
|
|
2046
2194
|
end
|
|
2047
2195
|
|
|
2048
|
-
specify "should support using
|
|
2049
|
-
@d.join(:categories,
|
|
2050
|
-
'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
|
2196
|
+
specify "should support using an SQL String as the join condition" do
|
|
2197
|
+
@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
2198
|
end
|
|
2052
2199
|
|
|
2053
2200
|
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"'
|
|
2201
|
+
@d.join(:categories, :active).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
|
2056
2202
|
end
|
|
2057
2203
|
|
|
2058
2204
|
specify "should support using an expression as the join condition" do
|
|
2059
|
-
@d.join(:categories, :number.sql_number > 10).sql.should ==
|
|
2060
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2205
|
+
@d.join(:categories, :number.sql_number > 10).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2061
2206
|
end
|
|
2062
2207
|
|
|
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"'
|
|
2208
|
+
specify "should support natural and cross joins" do
|
|
2209
|
+
@d.join_table(:natural, :categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2210
|
+
@d.join_table(:cross, :categories, nil).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2211
|
+
@d.join_table(:natural, :categories, nil, :c).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
|
2070
2212
|
end
|
|
2071
2213
|
|
|
2072
2214
|
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")'
|
|
2215
|
+
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
|
|
2216
|
+
@d.join(:categories, [:id1, :id2]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
|
2077
2217
|
end
|
|
2078
2218
|
|
|
2079
2219
|
specify "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
|
|
@@ -2081,6 +2221,12 @@ describe "Dataset#join_table" do
|
|
|
2081
2221
|
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."id" = "items"."id")'
|
|
2082
2222
|
end
|
|
2083
2223
|
|
|
2224
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
2225
|
+
@d.meta_def(:supports_cte?){true}
|
|
2226
|
+
@d.meta_def(:supports_cte_in_subselect?){false}
|
|
2227
|
+
@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")'
|
|
2228
|
+
end
|
|
2229
|
+
|
|
2084
2230
|
specify "should raise an error if using an array of symbols with a block" do
|
|
2085
2231
|
proc{@d.join(:categories, [:id]){|j,lj,js|}}.should raise_error(Sequel::Error)
|
|
2086
2232
|
end
|
|
@@ -2135,27 +2281,21 @@ describe "Dataset#join_table" do
|
|
|
2135
2281
|
end
|
|
2136
2282
|
|
|
2137
2283
|
specify "should use the block result as the only condition if no condition is given" do
|
|
2138
|
-
@d.join(:categories){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should ==
|
|
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")'
|
|
2284
|
+
@d.join(:categories){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" = "items"."c")'
|
|
2285
|
+
@d.join(:categories){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" > "items"."c")'
|
|
2142
2286
|
end
|
|
2143
2287
|
|
|
2144
2288
|
specify "should combine the block conditions and argument conditions if both given" do
|
|
2145
|
-
@d.join(:categories, :a=>:d){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should ==
|
|
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"))'
|
|
2289
|
+
@d.join(:categories, :a=>:d){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" = "items"."c"))'
|
|
2290
|
+
@d.join(:categories, :a=>:d){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" > "items"."c"))'
|
|
2149
2291
|
end
|
|
2150
2292
|
|
|
2151
2293
|
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
|
-
'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2294
|
+
@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")'
|
|
2154
2295
|
@d.from(:items.as(:i)).join(:categories.as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
|
|
2155
2296
|
'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2156
2297
|
end
|
|
2157
2298
|
|
|
2158
|
-
|
|
2159
2299
|
specify "should not allow insert, update, delete, or truncate" do
|
|
2160
2300
|
proc{@d.join(:categories, :a=>:d).insert_sql}.should raise_error(Sequel::InvalidOperation)
|
|
2161
2301
|
proc{@d.join(:categories, :a=>:d).update_sql(:a=>1)}.should raise_error(Sequel::InvalidOperation)
|
|
@@ -2170,81 +2310,52 @@ describe "Dataset#join_table" do
|
|
|
2170
2310
|
end
|
|
2171
2311
|
|
|
2172
2312
|
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
2313
|
specify "should perform an update on the specified filter" do
|
|
2188
|
-
|
|
2189
|
-
|
|
2314
|
+
db = Sequel.mock
|
|
2315
|
+
ds = db[:items]
|
|
2316
|
+
ds[:a => 1] = {:x => 3}
|
|
2317
|
+
db.sqls.should == ['UPDATE items SET x = 3 WHERE (a = 1)']
|
|
2190
2318
|
end
|
|
2191
2319
|
end
|
|
2192
2320
|
|
|
2193
2321
|
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
2322
|
specify "should act as alias to #update" do
|
|
2209
|
-
|
|
2210
|
-
|
|
2323
|
+
db = Sequel.mock
|
|
2324
|
+
ds = db[:items]
|
|
2325
|
+
ds.set({:x => 3})
|
|
2326
|
+
db.sqls.should == ['UPDATE items SET x = 3']
|
|
2211
2327
|
end
|
|
2212
2328
|
end
|
|
2213
2329
|
|
|
2214
|
-
|
|
2215
2330
|
describe "Dataset#insert_multiple" do
|
|
2216
2331
|
before do
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
def insert(arg)
|
|
2220
|
-
@inserts ||= []
|
|
2221
|
-
@inserts << arg
|
|
2222
|
-
end
|
|
2223
|
-
end
|
|
2224
|
-
|
|
2225
|
-
@d = c.new(nil)
|
|
2332
|
+
@db = Sequel.mock(:autoid=>2)
|
|
2333
|
+
@ds = @db[:items]
|
|
2226
2334
|
end
|
|
2227
2335
|
|
|
2228
2336
|
specify "should insert all items in the supplied array" do
|
|
2229
|
-
@
|
|
2230
|
-
@
|
|
2337
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}])
|
|
2338
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('aa')",
|
|
2339
|
+
"INSERT INTO items VALUES (5)",
|
|
2340
|
+
"INSERT INTO items VALUES (3)",
|
|
2341
|
+
"INSERT INTO items (a) VALUES (2)"]
|
|
2231
2342
|
end
|
|
2232
2343
|
|
|
2233
2344
|
specify "should pass array items through the supplied block if given" do
|
|
2234
|
-
|
|
2235
|
-
@
|
|
2236
|
-
|
|
2345
|
+
@ds.insert_multiple(["inevitable", "hello", "the ticking clock"]){|i| i.gsub('l', 'r')}
|
|
2346
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('inevitabre')",
|
|
2347
|
+
"INSERT INTO items VALUES ('herro')",
|
|
2348
|
+
"INSERT INTO items VALUES ('the ticking crock')"]
|
|
2349
|
+
end
|
|
2350
|
+
|
|
2351
|
+
specify "should return array of inserted ids" do
|
|
2352
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}]).should == [2, 3, 4, 5]
|
|
2237
2353
|
end
|
|
2238
2354
|
end
|
|
2239
2355
|
|
|
2240
2356
|
describe "Dataset aggregate methods" do
|
|
2241
2357
|
before do
|
|
2242
|
-
|
|
2243
|
-
def fetch_rows(sql)
|
|
2244
|
-
yield({1 => sql})
|
|
2245
|
-
end
|
|
2246
|
-
end
|
|
2247
|
-
@d = c.new(nil).from(:test)
|
|
2358
|
+
@d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
|
|
2248
2359
|
end
|
|
2249
2360
|
|
|
2250
2361
|
specify "should include min" do
|
|
@@ -2278,116 +2389,88 @@ end
|
|
|
2278
2389
|
|
|
2279
2390
|
describe "Dataset#range" do
|
|
2280
2391
|
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)
|
|
2392
|
+
@db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
|
|
2393
|
+
@ds = @db[:test]
|
|
2292
2394
|
end
|
|
2293
2395
|
|
|
2294
2396
|
specify "should generate a correct SQL statement" do
|
|
2295
|
-
@
|
|
2296
|
-
@
|
|
2397
|
+
@ds.range(:stamp)
|
|
2398
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
|
|
2297
2399
|
|
|
2298
|
-
@
|
|
2299
|
-
@
|
|
2400
|
+
@ds.filter(:price.sql_number > 100).range(:stamp)
|
|
2401
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
|
|
2300
2402
|
end
|
|
2301
2403
|
|
|
2302
2404
|
specify "should return a range object" do
|
|
2303
|
-
@
|
|
2405
|
+
@ds.range(:tryme).should == (1..10)
|
|
2304
2406
|
end
|
|
2305
2407
|
|
|
2306
2408
|
specify "should use a subselect for the same conditions as count" do
|
|
2307
|
-
@
|
|
2308
|
-
@
|
|
2409
|
+
@ds.order(:stamp).limit(5).range(:stamp).should == (1..10)
|
|
2410
|
+
@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
2411
|
end
|
|
2310
2412
|
end
|
|
2311
2413
|
|
|
2312
2414
|
describe "Dataset#interval" do
|
|
2313
2415
|
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)
|
|
2416
|
+
@db = Sequel.mock(:fetch=>{:v => 1234})
|
|
2417
|
+
@ds = @db[:test]
|
|
2325
2418
|
end
|
|
2326
2419
|
|
|
2327
|
-
specify "should generate
|
|
2328
|
-
@
|
|
2329
|
-
@
|
|
2420
|
+
specify "should generate the correct SQL statement" do
|
|
2421
|
+
@ds.interval(:stamp)
|
|
2422
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"]
|
|
2330
2423
|
|
|
2331
|
-
@
|
|
2332
|
-
@
|
|
2333
|
-
end
|
|
2334
|
-
|
|
2335
|
-
specify "should return an integer" do
|
|
2336
|
-
@d.interval(:tryme).should == 1234
|
|
2424
|
+
@ds.filter(:price.sql_number > 100).interval(:stamp)
|
|
2425
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"]
|
|
2337
2426
|
end
|
|
2338
2427
|
|
|
2339
2428
|
specify "should use a subselect for the same conditions as count" do
|
|
2340
|
-
@
|
|
2341
|
-
@
|
|
2429
|
+
@ds.order(:stamp).limit(5).interval(:stamp).should == 1234
|
|
2430
|
+
@db.sqls.should == ['SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
|
|
2342
2431
|
end
|
|
2343
2432
|
end
|
|
2344
2433
|
|
|
2345
2434
|
describe "Dataset #first and #last" do
|
|
2346
2435
|
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)
|
|
2436
|
+
@db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
|
|
2437
|
+
@d = @db[:test]
|
|
2355
2438
|
end
|
|
2356
2439
|
|
|
2357
2440
|
specify "should return a single record if no argument is given" do
|
|
2358
|
-
@d.order(:a).first.should ==
|
|
2359
|
-
@d.order(:a).last.should ==
|
|
2441
|
+
@d.order(:a).first.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
|
|
2442
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2360
2443
|
end
|
|
2361
2444
|
|
|
2362
2445
|
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 ==
|
|
2446
|
+
@d.order(:a).first(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
|
|
2447
|
+
@d.order(:a).first('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
|
|
2448
|
+
@d.order(:a).last(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1'}
|
|
2449
|
+
@d.order(:a).last('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1'}
|
|
2367
2450
|
end
|
|
2368
2451
|
|
|
2369
2452
|
specify "should set the limit and return an array of records if the given number is > 1" do
|
|
2370
2453
|
i = rand(10) + 10
|
|
2371
|
-
r = @d.order(:a).first(i).should == [
|
|
2454
|
+
r = @d.order(:a).first(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
|
|
2372
2455
|
i = rand(10) + 10
|
|
2373
|
-
r = @d.order(:a).last(i).should == [
|
|
2456
|
+
r = @d.order(:a).last(i).should == [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
|
|
2374
2457
|
end
|
|
2375
2458
|
|
|
2376
2459
|
specify "should return the first matching record if a block is given without an argument" do
|
|
2377
|
-
@d.first{:z.sql_number > 26}.should ==
|
|
2378
|
-
@d.order(:name).last{:z.sql_number > 26}.should ==
|
|
2460
|
+
@d.first{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
|
|
2461
|
+
@d.order(:name).last{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1'}
|
|
2379
2462
|
end
|
|
2380
2463
|
|
|
2381
2464
|
specify "should combine block and standard argument filters if argument is not an Integer" do
|
|
2382
|
-
@d.first(:y=>25){:z.sql_number > 26}.should ==
|
|
2383
|
-
@d.order(:name).last('y = ?', 16){:z.sql_number > 26}.should ==
|
|
2465
|
+
@d.first(:y=>25){:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
|
|
2466
|
+
@d.order(:name).last('y = ?', 16){:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 16)) ORDER BY name DESC LIMIT 1'}
|
|
2384
2467
|
end
|
|
2385
2468
|
|
|
2386
2469
|
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
|
2387
2470
|
i = rand(10) + 10
|
|
2388
|
-
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [
|
|
2471
|
+
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
|
|
2389
2472
|
i = rand(10) + 10
|
|
2390
|
-
r = @d.order(:a).last(i){:z.sql_number > 26}.should == [
|
|
2473
|
+
r = @d.order(:a).last(i){:z.sql_number > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"}]
|
|
2391
2474
|
end
|
|
2392
2475
|
|
|
2393
2476
|
specify "#last should raise if no order is given" do
|
|
@@ -2398,10 +2481,10 @@ describe "Dataset #first and #last" do
|
|
|
2398
2481
|
end
|
|
2399
2482
|
|
|
2400
2483
|
specify "#last should invert the order" do
|
|
2401
|
-
@d.order(:a).last.
|
|
2402
|
-
@d.order(:b.desc).last.
|
|
2403
|
-
@d.order(:c, :d).last.
|
|
2404
|
-
@d.order(:e.desc, :f).last.
|
|
2484
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2485
|
+
@d.order(:b.desc).last.should == {:s=>'SELECT * FROM test ORDER BY b ASC LIMIT 1'}
|
|
2486
|
+
@d.order(:c, :d).last.should == {:s=>'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'}
|
|
2487
|
+
@d.order(:e.desc, :f).last.should == {:s=>'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'}
|
|
2405
2488
|
end
|
|
2406
2489
|
end
|
|
2407
2490
|
|
|
@@ -2412,55 +2495,37 @@ describe "Dataset compound operations" do
|
|
|
2412
2495
|
end
|
|
2413
2496
|
|
|
2414
2497
|
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"
|
|
2498
|
+
@a.union(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2499
|
+
@b.union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2500
|
+
@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
2501
|
end
|
|
2422
2502
|
|
|
2423
2503
|
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"
|
|
2504
|
+
@a.intersect(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2505
|
+
@b.intersect(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2506
|
+
@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
2507
|
end
|
|
2431
2508
|
|
|
2432
2509
|
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"
|
|
2510
|
+
@a.except(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2511
|
+
@b.except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2512
|
+
@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
2513
|
end
|
|
2440
2514
|
|
|
2441
2515
|
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"
|
|
2516
|
+
@a.union(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2517
|
+
@a.intersect(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2518
|
+
@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
2519
|
end
|
|
2449
2520
|
|
|
2450
2521
|
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)"
|
|
2522
|
+
@b.union(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
|
|
2523
|
+
@b.intersect(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
|
|
2524
|
+
@b.except(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
|
|
2457
2525
|
|
|
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)"
|
|
2526
|
+
@b.union(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
|
|
2527
|
+
@b.intersect(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2528
|
+
@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
2529
|
end
|
|
2465
2530
|
|
|
2466
2531
|
specify "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
|
|
@@ -2480,141 +2545,105 @@ describe "Dataset compound operations" do
|
|
|
2480
2545
|
end
|
|
2481
2546
|
|
|
2482
2547
|
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"
|
|
2548
|
+
@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"
|
|
2549
|
+
@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"
|
|
2550
|
+
@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
2551
|
end
|
|
2490
2552
|
|
|
2491
2553
|
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"
|
|
2554
|
+
@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"
|
|
2555
|
+
@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"
|
|
2556
|
+
@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
2557
|
end
|
|
2499
2558
|
|
|
2500
2559
|
specify "should order and limit properly when using UNION, INTERSECT, or EXCEPT" do
|
|
2501
2560
|
@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"
|
|
2561
|
+
@dataset.union(@dataset).limit(2).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
|
|
2562
|
+
@dataset.limit(2).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2563
|
+
@dataset.except(@dataset.limit(2)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
|
|
2564
|
+
|
|
2565
|
+
@dataset.union(@dataset).order(:num).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
|
|
2566
|
+
@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"
|
|
2567
|
+
@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
2568
|
|
|
2516
2569
|
@dataset.limit(2).order(:a).union(@dataset.limit(3).order(:b)).order(:c).limit(4).sql.should ==
|
|
2517
2570
|
"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
2571
|
end
|
|
2519
2572
|
|
|
2573
|
+
specify "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
|
|
2574
|
+
ds = Sequel::Dataset.new(nil)
|
|
2575
|
+
ds.meta_def(:supports_cte?){true}
|
|
2576
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2577
|
+
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'
|
|
2578
|
+
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'
|
|
2579
|
+
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'
|
|
2580
|
+
end
|
|
2520
2581
|
end
|
|
2521
2582
|
|
|
2522
2583
|
describe "Dataset#[]" do
|
|
2523
2584
|
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)
|
|
2585
|
+
@db = Sequel.mock(:fetch=>{1 => 2, 3 => 4})
|
|
2586
|
+
@d = @db[:items]
|
|
2537
2587
|
end
|
|
2538
2588
|
|
|
2539
2589
|
specify "should return a single record filtered according to the given conditions" do
|
|
2540
2590
|
@d[:name => 'didi'].should == {1 => 2, 3 => 4}
|
|
2541
|
-
@
|
|
2591
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (name = 'didi') LIMIT 1"]
|
|
2542
2592
|
|
|
2543
2593
|
@d[:id => 5..45].should == {1 => 2, 3 => 4}
|
|
2544
|
-
@
|
|
2594
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((id >= 5) AND (id <= 45)) LIMIT 1"]
|
|
2545
2595
|
end
|
|
2546
2596
|
end
|
|
2547
2597
|
|
|
2548
2598
|
describe "Dataset#single_record" do
|
|
2549
2599
|
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)
|
|
2600
|
+
@db = Sequel.mock
|
|
2561
2601
|
end
|
|
2562
2602
|
|
|
2563
2603
|
specify "should call each with a limit of 1 and return the record" do
|
|
2564
|
-
@
|
|
2604
|
+
@db.fetch = {:a=>1}
|
|
2605
|
+
@db[:test].single_record.should == {:a=>1}
|
|
2606
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2565
2607
|
end
|
|
2566
2608
|
|
|
2567
2609
|
specify "should return nil if no record is present" do
|
|
2568
|
-
@
|
|
2610
|
+
@db[:test].single_record.should be_nil
|
|
2611
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2569
2612
|
end
|
|
2570
2613
|
end
|
|
2571
2614
|
|
|
2572
2615
|
describe "Dataset#single_value" do
|
|
2573
2616
|
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)
|
|
2617
|
+
@db = Sequel.mock
|
|
2585
2618
|
end
|
|
2586
2619
|
|
|
2587
2620
|
specify "should call each and return the first value of the first record" do
|
|
2588
|
-
@
|
|
2621
|
+
@db.fetch = {:a=>1}
|
|
2622
|
+
@db[:test].single_value.should == 1
|
|
2623
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2589
2624
|
end
|
|
2590
2625
|
|
|
2591
2626
|
specify "should return nil if no records" do
|
|
2592
|
-
@
|
|
2627
|
+
@db[:test].single_value.should be_nil
|
|
2628
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2593
2629
|
end
|
|
2594
2630
|
|
|
2595
2631
|
it "should work on a graphed_dataset" do
|
|
2596
|
-
@
|
|
2597
|
-
@
|
|
2632
|
+
@db.fetch = {:a=>1}
|
|
2633
|
+
ds = @db[:test].columns(:a)
|
|
2634
|
+
ds.graph(ds, [:a], :table_alias=>:test2).single_value.should == 1
|
|
2635
|
+
@db.sqls.should == ['SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
2598
2636
|
end
|
|
2599
2637
|
end
|
|
2600
2638
|
|
|
2601
2639
|
describe "Dataset#get" do
|
|
2602
2640
|
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)
|
|
2641
|
+
@d = Sequel.mock(:fetch=>proc{|s| {:name=>s}})[:test]
|
|
2613
2642
|
end
|
|
2614
2643
|
|
|
2615
2644
|
specify "should select the specified column and fetch its value" do
|
|
2616
2645
|
@d.get(:name).should == "SELECT name FROM test LIMIT 1"
|
|
2617
|
-
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2646
|
+
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2618
2647
|
end
|
|
2619
2648
|
|
|
2620
2649
|
specify "should work with filters" do
|
|
@@ -2633,243 +2662,253 @@ describe "Dataset#get" do
|
|
|
2633
2662
|
specify "should raise an error if both a regular argument and block argument are used" do
|
|
2634
2663
|
proc{@d.get(:name){|o| o.x__b.as(:name)}}.should raise_error(Sequel::Error)
|
|
2635
2664
|
end
|
|
2665
|
+
|
|
2666
|
+
specify "should support false and nil values" do
|
|
2667
|
+
@d.get(false).should == "SELECT 'f' FROM test LIMIT 1"
|
|
2668
|
+
@d.get(nil).should == "SELECT NULL FROM test LIMIT 1"
|
|
2669
|
+
end
|
|
2636
2670
|
end
|
|
2637
2671
|
|
|
2638
2672
|
describe "Dataset#set_row_proc" do
|
|
2639
2673
|
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)
|
|
2674
|
+
@db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
|
|
2675
|
+
@dataset = @db[:items]
|
|
2676
|
+
@dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
|
|
2647
2677
|
end
|
|
2648
2678
|
|
|
2649
2679
|
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
2680
|
rows = @dataset.all
|
|
2653
|
-
rows.
|
|
2654
|
-
|
|
2655
|
-
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
|
2681
|
+
rows.map{|h| h[:der]}.should == [3, 4]
|
|
2682
|
+
@db.sqls.should == ['SELECT * FROM items']
|
|
2656
2683
|
end
|
|
2657
2684
|
|
|
2658
2685
|
specify "should be copied over when dataset is cloned" do
|
|
2659
|
-
@dataset.
|
|
2660
|
-
|
|
2661
|
-
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
|
2686
|
+
@dataset.filter(:a => 1).all.should == [{:a=>1, :der=>3}, {:a=>2, :der=>4}]
|
|
2662
2687
|
end
|
|
2663
2688
|
end
|
|
2664
2689
|
|
|
2665
2690
|
describe "Dataset#<<" do
|
|
2666
2691
|
before do
|
|
2667
|
-
@
|
|
2668
|
-
@d.meta_def(:insert) do |*args|
|
|
2669
|
-
1234567890
|
|
2670
|
-
end
|
|
2692
|
+
@db = Sequel.mock
|
|
2671
2693
|
end
|
|
2672
|
-
|
|
2694
|
+
|
|
2673
2695
|
specify "should call #insert" do
|
|
2674
|
-
|
|
2696
|
+
@db[:items] << {:name => 1}
|
|
2697
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)']
|
|
2698
|
+
end
|
|
2699
|
+
|
|
2700
|
+
specify "should be chainable" do
|
|
2701
|
+
@db[:items] << {:name => 1} << @db[:old_items].select(:name)
|
|
2702
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)', 'INSERT INTO items SELECT name FROM old_items']
|
|
2675
2703
|
end
|
|
2676
2704
|
end
|
|
2677
2705
|
|
|
2678
2706
|
describe "Dataset#columns" do
|
|
2679
2707
|
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}
|
|
2708
|
+
@dataset = Sequel.mock[:items]
|
|
2684
2709
|
end
|
|
2685
2710
|
|
|
2686
2711
|
specify "should return the value of @columns if @columns is not nil" do
|
|
2687
|
-
@dataset.columns
|
|
2688
|
-
@dataset.
|
|
2712
|
+
@dataset.columns(:a, :b, :c).columns.should == [:a, :b, :c]
|
|
2713
|
+
@dataset.db.sqls.should == []
|
|
2689
2714
|
end
|
|
2690
2715
|
|
|
2691
2716
|
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
|
-
|
|
2717
|
+
@dataset.db.columns = [:a]
|
|
2718
|
+
@dataset.columns.should == [:a]
|
|
2719
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2720
|
+
end
|
|
2721
|
+
|
|
2722
|
+
specify "should be cleared if you change the selected columns" do
|
|
2723
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2724
|
+
@dataset.columns.should == [:a]
|
|
2725
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2726
|
+
@dataset.columns.should == [:a]
|
|
2727
|
+
@dataset.db.sqls.should == []
|
|
2728
|
+
ds = @dataset.select{foo{}}
|
|
2729
|
+
ds.columns.should == [:b]
|
|
2730
|
+
@dataset.db.sqls.should == ['SELECT foo() FROM items LIMIT 1']
|
|
2731
|
+
end
|
|
2732
|
+
|
|
2733
|
+
specify "should be cleared if you change the FROM table" 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.from(:foo)
|
|
2738
|
+
ds.columns.should == [:b]
|
|
2739
|
+
@dataset.db.sqls.should == ['SELECT * FROM foo LIMIT 1']
|
|
2740
|
+
end
|
|
2741
|
+
|
|
2742
|
+
specify "should be cleared if you join a table to the dataset" do
|
|
2743
|
+
@dataset.db.columns = [[:a], [:a, :b]]
|
|
2744
|
+
@dataset.columns.should == [:a]
|
|
2745
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2746
|
+
ds = @dataset.cross_join(:foo)
|
|
2747
|
+
ds.columns.should == [:a, :b]
|
|
2748
|
+
@dataset.db.sqls.should == ['SELECT * FROM items CROSS JOIN foo LIMIT 1']
|
|
2749
|
+
end
|
|
2750
|
+
|
|
2751
|
+
specify "should be cleared if you set custom SQL for the dataset" do
|
|
2752
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2753
|
+
@dataset.columns.should == [:a]
|
|
2754
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2755
|
+
ds = @dataset.with_sql('SELECT b FROM foo')
|
|
2756
|
+
ds.columns.should == [:b]
|
|
2757
|
+
@dataset.db.sqls.should == ['SELECT b FROM foo']
|
|
2696
2758
|
end
|
|
2697
2759
|
|
|
2698
2760
|
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
|
2761
|
+
@dataset.db.columns = [:a]
|
|
2699
2762
|
@dataset.filter!(:b=>100).order!(:b).distinct!
|
|
2700
|
-
@dataset.columns
|
|
2701
|
-
@dataset.
|
|
2763
|
+
@dataset.columns.should == [:a]
|
|
2764
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2702
2765
|
end
|
|
2703
2766
|
end
|
|
2704
2767
|
|
|
2705
2768
|
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
2769
|
specify "should always attempt to get a record and return @columns" do
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2770
|
+
ds = Sequel.mock(:columns=>[[:a, :b, :c], [:d, :e, :f]])[:items]
|
|
2771
|
+
ds.columns!.should == [:a, :b, :c]
|
|
2772
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2773
|
+
ds.columns!.should == [:d, :e, :f]
|
|
2774
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2717
2775
|
end
|
|
2718
2776
|
end
|
|
2719
2777
|
|
|
2720
2778
|
describe "Dataset#import" do
|
|
2721
2779
|
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'}]
|
|
2780
|
+
@db = Sequel.mock
|
|
2781
|
+
@ds = @db[:items]
|
|
2743
2782
|
end
|
|
2744
2783
|
|
|
2784
|
+
specify "should return nil without a query if no values" do
|
|
2785
|
+
@ds.import(['x', 'y'], []).should == nil
|
|
2786
|
+
@db.sqls.should == []
|
|
2787
|
+
end
|
|
2788
|
+
|
|
2745
2789
|
specify "should accept string keys as column names" do
|
|
2746
2790
|
@ds.import(['x', 'y'], [[1, 2], [3, 4]])
|
|
2747
|
-
@db.sqls.should == [
|
|
2748
|
-
'BEGIN',
|
|
2791
|
+
@db.sqls.should == ['BEGIN',
|
|
2749
2792
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2750
2793
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2751
|
-
'COMMIT'
|
|
2752
|
-
]
|
|
2794
|
+
'COMMIT']
|
|
2753
2795
|
end
|
|
2754
2796
|
|
|
2755
2797
|
specify "should accept a columns array and a values array" do
|
|
2756
2798
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
2757
|
-
@db.sqls.should == [
|
|
2758
|
-
'BEGIN',
|
|
2799
|
+
@db.sqls.should == ['BEGIN',
|
|
2759
2800
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2760
2801
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2761
|
-
'COMMIT'
|
|
2762
|
-
]
|
|
2802
|
+
'COMMIT']
|
|
2763
2803
|
end
|
|
2764
2804
|
|
|
2765
2805
|
specify "should accept a columns array and a dataset" do
|
|
2766
|
-
@ds2 =
|
|
2806
|
+
@ds2 = @ds.from(:cats).filter(:purr => true).select(:a, :b)
|
|
2767
2807
|
|
|
2768
2808
|
@ds.import([:x, :y], @ds2)
|
|
2769
|
-
@db.sqls.should == [
|
|
2770
|
-
'BEGIN',
|
|
2809
|
+
@db.sqls.should == ['BEGIN',
|
|
2771
2810
|
"INSERT INTO items (x, y) SELECT a, b FROM cats WHERE (purr IS TRUE)",
|
|
2772
|
-
'COMMIT'
|
|
2773
|
-
]
|
|
2811
|
+
'COMMIT']
|
|
2774
2812
|
end
|
|
2775
2813
|
|
|
2776
2814
|
specify "should accept a columns array and a values array with :commit_every option" do
|
|
2777
2815
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 3)
|
|
2778
|
-
@db.sqls.should == [
|
|
2779
|
-
'BEGIN',
|
|
2816
|
+
@db.sqls.should == ['BEGIN',
|
|
2780
2817
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2781
2818
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2782
2819
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2783
|
-
'COMMIT'
|
|
2784
|
-
]
|
|
2820
|
+
'COMMIT']
|
|
2785
2821
|
end
|
|
2786
|
-
specify "should accept a columns array and a values array with slice option" do
|
|
2822
|
+
specify "should accept a columns array and a values array with :slice option" do
|
|
2787
2823
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
|
2788
|
-
@db.sqls.should == [
|
|
2789
|
-
'BEGIN',
|
|
2824
|
+
@db.sqls.should == ['BEGIN',
|
|
2790
2825
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2791
2826
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2792
2827
|
'COMMIT',
|
|
2793
2828
|
'BEGIN',
|
|
2794
2829
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2795
|
-
'COMMIT'
|
|
2796
|
-
]
|
|
2830
|
+
'COMMIT']
|
|
2797
2831
|
end
|
|
2798
2832
|
end
|
|
2799
2833
|
|
|
2800
2834
|
describe "Dataset#multi_insert" do
|
|
2801
2835
|
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
|
-
|
|
2836
|
+
@db = Sequel.mock(:servers=>{:s1=>{}})
|
|
2837
|
+
@ds = @db[:items]
|
|
2822
2838
|
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
|
2823
2839
|
end
|
|
2824
2840
|
|
|
2841
|
+
specify "should return nil without a query if no values" do
|
|
2842
|
+
@ds.multi_insert([]).should == nil
|
|
2843
|
+
@db.sqls.should == []
|
|
2844
|
+
end
|
|
2845
|
+
|
|
2825
2846
|
specify "should issue multiple insert statements inside a transaction" do
|
|
2826
2847
|
@ds.multi_insert(@list)
|
|
2827
|
-
@db.sqls.should == [
|
|
2828
|
-
'
|
|
2848
|
+
@db.sqls.should == ['BEGIN',
|
|
2849
|
+
"INSERT INTO items (name) VALUES ('abc')",
|
|
2850
|
+
"INSERT INTO items (name) VALUES ('def')",
|
|
2851
|
+
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2852
|
+
'COMMIT']
|
|
2853
|
+
end
|
|
2854
|
+
|
|
2855
|
+
specify "should respect :server option" do
|
|
2856
|
+
@ds.multi_insert(@list, :server=>:s1)
|
|
2857
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2858
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2859
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2860
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2861
|
+
'COMMIT -- s1']
|
|
2862
|
+
end
|
|
2863
|
+
|
|
2864
|
+
specify "should respect existing :server option on dataset" do
|
|
2865
|
+
@ds.server(:s1).multi_insert(@list)
|
|
2866
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2867
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2868
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2869
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2870
|
+
'COMMIT -- s1']
|
|
2871
|
+
end
|
|
2872
|
+
|
|
2873
|
+
specify "should respect :return=>:primary_key option" do
|
|
2874
|
+
@db.autoid = 1
|
|
2875
|
+
@ds.multi_insert(@list, :return=>:primary_key).should == [1, 2, 3]
|
|
2876
|
+
@db.sqls.should == ['BEGIN',
|
|
2829
2877
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2830
2878
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2831
2879
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2832
|
-
'COMMIT'
|
|
2833
|
-
]
|
|
2880
|
+
'COMMIT']
|
|
2834
2881
|
end
|
|
2835
2882
|
|
|
2836
2883
|
specify "should handle different formats for tables" do
|
|
2837
2884
|
@ds = @ds.from(:sch__tab)
|
|
2838
2885
|
@ds.multi_insert(@list)
|
|
2839
|
-
@db.sqls.should == [
|
|
2840
|
-
'BEGIN',
|
|
2886
|
+
@db.sqls.should == ['BEGIN',
|
|
2841
2887
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2842
2888
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2843
2889
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2844
|
-
'COMMIT'
|
|
2845
|
-
]
|
|
2846
|
-
@db.sqls.clear
|
|
2890
|
+
'COMMIT']
|
|
2847
2891
|
|
|
2848
2892
|
@ds = @ds.from(:tab.qualify(:sch))
|
|
2849
2893
|
@ds.multi_insert(@list)
|
|
2850
|
-
@db.sqls.should == [
|
|
2851
|
-
'BEGIN',
|
|
2894
|
+
@db.sqls.should == ['BEGIN',
|
|
2852
2895
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2853
2896
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2854
2897
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2855
|
-
'COMMIT'
|
|
2856
|
-
|
|
2857
|
-
@db.sqls.clear
|
|
2898
|
+
'COMMIT']
|
|
2899
|
+
|
|
2858
2900
|
@ds = @ds.from(:sch__tab.identifier)
|
|
2859
2901
|
@ds.multi_insert(@list)
|
|
2860
|
-
@db.sqls.should == [
|
|
2861
|
-
'BEGIN',
|
|
2902
|
+
@db.sqls.should == ['BEGIN',
|
|
2862
2903
|
"INSERT INTO sch__tab (name) VALUES ('abc')",
|
|
2863
2904
|
"INSERT INTO sch__tab (name) VALUES ('def')",
|
|
2864
2905
|
"INSERT INTO sch__tab (name) VALUES ('ghi')",
|
|
2865
|
-
'COMMIT'
|
|
2866
|
-
]
|
|
2906
|
+
'COMMIT']
|
|
2867
2907
|
end
|
|
2868
2908
|
|
|
2869
2909
|
specify "should accept the :commit_every option for committing every x records" do
|
|
2870
2910
|
@ds.multi_insert(@list, :commit_every => 1)
|
|
2871
|
-
@db.sqls.should == [
|
|
2872
|
-
'BEGIN',
|
|
2911
|
+
@db.sqls.should == ['BEGIN',
|
|
2873
2912
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2874
2913
|
'COMMIT',
|
|
2875
2914
|
'BEGIN',
|
|
@@ -2877,36 +2916,31 @@ describe "Dataset#multi_insert" do
|
|
|
2877
2916
|
'COMMIT',
|
|
2878
2917
|
'BEGIN',
|
|
2879
2918
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2880
|
-
'COMMIT'
|
|
2881
|
-
]
|
|
2919
|
+
'COMMIT']
|
|
2882
2920
|
end
|
|
2883
2921
|
|
|
2884
2922
|
specify "should accept the :slice option for committing every x records" do
|
|
2885
2923
|
@ds.multi_insert(@list, :slice => 2)
|
|
2886
|
-
@db.sqls.should == [
|
|
2887
|
-
'BEGIN',
|
|
2924
|
+
@db.sqls.should == ['BEGIN',
|
|
2888
2925
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2889
2926
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2890
2927
|
'COMMIT',
|
|
2891
2928
|
'BEGIN',
|
|
2892
2929
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2893
|
-
'COMMIT'
|
|
2894
|
-
]
|
|
2930
|
+
'COMMIT']
|
|
2895
2931
|
end
|
|
2896
2932
|
|
|
2897
2933
|
specify "should accept string keys as column names" do
|
|
2898
2934
|
@ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
|
|
2899
|
-
@db.sqls
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
'COMMIT'
|
|
2904
|
-
]
|
|
2935
|
+
sqls = @db.sqls
|
|
2936
|
+
["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls.slice!(1))
|
|
2937
|
+
["INSERT INTO items (x, y) VALUES (3, 4)", "INSERT INTO items (y, x) VALUES (4, 3)"].should include(sqls.slice!(1))
|
|
2938
|
+
sqls.should == ['BEGIN', 'COMMIT']
|
|
2905
2939
|
end
|
|
2906
2940
|
|
|
2907
2941
|
specify "should not do anything if no hashes are provided" do
|
|
2908
2942
|
@ds.multi_insert([])
|
|
2909
|
-
@db.sqls.should
|
|
2943
|
+
@db.sqls.should == []
|
|
2910
2944
|
end
|
|
2911
2945
|
end
|
|
2912
2946
|
|
|
@@ -2951,41 +2985,21 @@ describe "Dataset" do
|
|
|
2951
2985
|
end
|
|
2952
2986
|
|
|
2953
2987
|
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"
|
|
2988
|
+
@d.order!(:y).filter!(:y => 1).sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
|
2957
2989
|
end
|
|
2958
2990
|
end
|
|
2959
2991
|
|
|
2960
2992
|
describe "Dataset#to_csv" do
|
|
2961
2993
|
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} ]
|
|
2994
|
+
@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
2995
|
end
|
|
2980
2996
|
|
|
2981
2997
|
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"
|
|
2998
|
+
@ds.to_csv.should == "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2984
2999
|
end
|
|
2985
3000
|
|
|
2986
3001
|
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"
|
|
3002
|
+
@ds.to_csv(false).should == "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2989
3003
|
end
|
|
2990
3004
|
end
|
|
2991
3005
|
|
|
@@ -3083,66 +3097,40 @@ describe "Dataset#insert_sql" do
|
|
|
3083
3097
|
end
|
|
3084
3098
|
end
|
|
3085
3099
|
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
true
|
|
3100
|
+
describe "Dataset#inspect" do
|
|
3101
|
+
before do
|
|
3102
|
+
class ::InspectDataset < Sequel::Dataset; end
|
|
3090
3103
|
end
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
class DummyMummyDatabase < Sequel::Database
|
|
3094
|
-
attr_reader :sqls
|
|
3095
|
-
|
|
3096
|
-
def execute(sql)
|
|
3097
|
-
@sqls ||= []
|
|
3098
|
-
@sqls << sql
|
|
3104
|
+
after do
|
|
3105
|
+
Object.send(:remove_const, :InspectDataset) if defined?(::InspectDataset)
|
|
3099
3106
|
end
|
|
3100
|
-
|
|
3101
|
-
def transaction; yield; end
|
|
3102
3107
|
|
|
3103
|
-
|
|
3104
|
-
|
|
3108
|
+
specify "should include the class name and the corresponding SQL statement" do
|
|
3109
|
+
Sequel::Dataset.new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
3110
|
+
InspectDataset.new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3105
3111
|
end
|
|
3106
|
-
end
|
|
3107
3112
|
|
|
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]
|
|
3113
|
+
specify "should skip anonymous classes" do
|
|
3114
|
+
Class.new(Class.new(Sequel::Dataset)).new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
3115
|
+
Class.new(InspectDataset).new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3115
3116
|
end
|
|
3116
3117
|
end
|
|
3117
3118
|
|
|
3118
3119
|
describe "Dataset#all" do
|
|
3119
3120
|
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)
|
|
3121
|
+
@dataset = Sequel.mock(:fetch=>[{:x => 1, :y => 2}, {:x => 3, :y => 4}])[:items]
|
|
3128
3122
|
end
|
|
3129
3123
|
|
|
3130
3124
|
specify "should return an array with all records" do
|
|
3131
|
-
@dataset.all.should == [
|
|
3132
|
-
|
|
3133
|
-
{:x => 3, :y => 4},
|
|
3134
|
-
"SELECT * FROM items"
|
|
3135
|
-
]
|
|
3125
|
+
@dataset.all.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3126
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3136
3127
|
end
|
|
3137
3128
|
|
|
3138
3129
|
specify "should iterate over the array if a block is given" do
|
|
3139
3130
|
a = []
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
end
|
|
3144
|
-
|
|
3145
|
-
a.should == [1, 3, "SELECT * FROM items"]
|
|
3131
|
+
@dataset.all{|r| a << r.values_at(:x, :y)}.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3132
|
+
a.should == [[1, 2], [3, 4]]
|
|
3133
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3146
3134
|
end
|
|
3147
3135
|
end
|
|
3148
3136
|
|
|
@@ -3152,75 +3140,60 @@ describe "Dataset#grep" do
|
|
|
3152
3140
|
end
|
|
3153
3141
|
|
|
3154
3142
|
specify "should format a SQL filter correctly" do
|
|
3155
|
-
@ds.grep(:title, 'ruby').sql.should ==
|
|
3156
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3143
|
+
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3157
3144
|
end
|
|
3158
3145
|
|
|
3159
3146
|
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'))"
|
|
3147
|
+
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
|
3162
3148
|
end
|
|
3163
3149
|
|
|
3164
3150
|
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'))"
|
|
3151
|
+
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
|
3167
3152
|
end
|
|
3168
3153
|
|
|
3169
3154
|
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'))"
|
|
3155
|
+
@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
3156
|
end
|
|
3173
3157
|
|
|
3174
3158
|
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')))"
|
|
3159
|
+
@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
3160
|
end
|
|
3178
3161
|
|
|
3179
3162
|
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')))"
|
|
3163
|
+
@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
3164
|
end
|
|
3183
3165
|
|
|
3184
3166
|
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'))"
|
|
3167
|
+
@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
3168
|
end
|
|
3188
3169
|
|
|
3189
3170
|
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'))"
|
|
3171
|
+
@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
3172
|
end
|
|
3193
3173
|
|
|
3194
3174
|
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')))"
|
|
3175
|
+
@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
3176
|
end
|
|
3198
3177
|
|
|
3199
3178
|
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')))"
|
|
3179
|
+
@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
3180
|
end
|
|
3203
3181
|
|
|
3204
3182
|
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'))"
|
|
3183
|
+
@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
3184
|
end
|
|
3208
3185
|
|
|
3209
3186
|
specify "should support regexps though the database may not support it" do
|
|
3210
|
-
@ds.grep(:title, /ruby/).sql.should ==
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
|
|
3214
|
-
"SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
|
3187
|
+
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
|
3188
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
|
3215
3189
|
end
|
|
3216
3190
|
|
|
3217
3191
|
specify "should support searching against other columns" do
|
|
3218
|
-
@ds.grep(:title, :body).sql.should ==
|
|
3219
|
-
"SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3192
|
+
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3220
3193
|
end
|
|
3221
3194
|
end
|
|
3222
3195
|
|
|
3223
|
-
describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #execute" do
|
|
3196
|
+
describe "Dataset default #fetch_rows, #insert, #update, #delete, #with_sql_delete, #truncate, #execute" do
|
|
3224
3197
|
before do
|
|
3225
3198
|
@db = Sequel::Database.new
|
|
3226
3199
|
@ds = @db[:items]
|
|
@@ -3237,6 +3210,14 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3237
3210
|
@ds.delete
|
|
3238
3211
|
end
|
|
3239
3212
|
|
|
3213
|
+
specify "#with_sql_delete should execute delete SQL" do
|
|
3214
|
+
sql = 'DELETE FROM foo'
|
|
3215
|
+
@db.should_receive(:execute).once.with(sql, :server=>:default)
|
|
3216
|
+
@ds.with_sql_delete(sql)
|
|
3217
|
+
@db.should_receive(:execute_dui).once.with(sql, :server=>:default)
|
|
3218
|
+
@ds.with_sql_delete(sql)
|
|
3219
|
+
end
|
|
3220
|
+
|
|
3240
3221
|
specify "#insert should execute insert SQL" do
|
|
3241
3222
|
@db.should_receive(:execute).once.with('INSERT INTO items DEFAULT VALUES', :server=>:default)
|
|
3242
3223
|
@ds.insert([])
|
|
@@ -3260,6 +3241,7 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3260
3241
|
|
|
3261
3242
|
specify "#truncate should raise an InvalidOperation exception if the dataset is filtered" do
|
|
3262
3243
|
proc{@ds.filter(:a=>1).truncate}.should raise_error(Sequel::InvalidOperation)
|
|
3244
|
+
proc{@ds.having(:a=>1).truncate}.should raise_error(Sequel::InvalidOperation)
|
|
3263
3245
|
end
|
|
3264
3246
|
|
|
3265
3247
|
specify "#execute should execute the SQL on the database" do
|
|
@@ -3270,58 +3252,80 @@ end
|
|
|
3270
3252
|
|
|
3271
3253
|
describe "Dataset prepared statements and bound variables " do
|
|
3272
3254
|
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
|
|
3255
|
+
@db = Sequel.mock
|
|
3285
3256
|
@ds = @db[:items]
|
|
3257
|
+
@ds.meta_def(:insert_sql){|*v| "#{super(*v)}#{' RETURNING *' if opts.has_key?(:returning)}" }
|
|
3286
3258
|
end
|
|
3287
3259
|
|
|
3288
3260
|
specify "#call should take a type and bind hash and interpolate it" do
|
|
3261
|
+
@ds.filter(:num=>:$n).call(:each, :n=>1)
|
|
3289
3262
|
@ds.filter(:num=>:$n).call(:select, :n=>1)
|
|
3263
|
+
@ds.filter(:num=>:$n).call([:map, :a], :n=>1)
|
|
3264
|
+
@ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
|
|
3265
|
+
@ds.filter(:num=>:$n).call([:to_hash_groups, :a, :b], :n=>1)
|
|
3290
3266
|
@ds.filter(:num=>:$n).call(:first, :n=>1)
|
|
3291
3267
|
@ds.filter(:num=>:$n).call(:delete, :n=>1)
|
|
3292
3268
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
|
3293
3269
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
|
3294
|
-
@
|
|
3270
|
+
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
|
3271
|
+
@db.sqls.should == [
|
|
3272
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3273
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3274
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3275
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3276
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3295
3277
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3296
3278
|
'DELETE FROM items WHERE (num = 1)',
|
|
3297
3279
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3298
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3280
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3281
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3299
3282
|
end
|
|
3300
3283
|
|
|
3301
3284
|
specify "#prepare should take a type and name and store it in the database for later use with call" do
|
|
3302
3285
|
pss = []
|
|
3286
|
+
pss << @ds.filter(:num=>:$n).prepare(:each, :en)
|
|
3303
3287
|
pss << @ds.filter(:num=>:$n).prepare(:select, :sn)
|
|
3288
|
+
pss << @ds.filter(:num=>:$n).prepare([:map, :a], :sm)
|
|
3289
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
|
|
3290
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash_groups, :a, :b], :shg)
|
|
3304
3291
|
pss << @ds.filter(:num=>:$n).prepare(:first, :fn)
|
|
3305
3292
|
pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
|
|
3306
3293
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
|
3307
3294
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
|
3308
|
-
@
|
|
3309
|
-
[:
|
|
3295
|
+
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
|
3296
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :en, :fn, :in, :ins, :sh, :shg, :sm, :sn, :un]
|
|
3297
|
+
[:en, :sn, :sm, :sh, :shg, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3298
|
+
@db.call(:en, :n=>1){}
|
|
3310
3299
|
@db.call(:sn, :n=>1)
|
|
3300
|
+
@db.call(:sm, :n=>1)
|
|
3301
|
+
@db.call(:sh, :n=>1)
|
|
3302
|
+
@db.call(:shg, :n=>1)
|
|
3311
3303
|
@db.call(:fn, :n=>1)
|
|
3312
3304
|
@db.call(:dn, :n=>1)
|
|
3313
3305
|
@db.call(:un, :n=>1, :n2=>2)
|
|
3314
3306
|
@db.call(:in, :n=>1)
|
|
3315
|
-
@db.
|
|
3307
|
+
@db.call(:ins, :n=>1)
|
|
3308
|
+
@db.sqls.should == [
|
|
3309
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3310
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3311
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3312
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3313
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3316
3314
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3317
3315
|
'DELETE FROM items WHERE (num = 1)',
|
|
3318
3316
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3319
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3317
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3318
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3320
3319
|
end
|
|
3321
3320
|
|
|
3321
|
+
specify "#call should default to using :all if an invalid type is given" do
|
|
3322
|
+
@ds.filter(:num=>:$n).call(:select_all, :n=>1)
|
|
3323
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3324
|
+
end
|
|
3325
|
+
|
|
3322
3326
|
specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
|
|
3323
3327
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
|
3324
|
-
'<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3328
|
+
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3325
3329
|
end
|
|
3326
3330
|
|
|
3327
3331
|
specify "should handle literal strings" do
|
|
@@ -3329,6 +3333,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3329
3333
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3330
3334
|
end
|
|
3331
3335
|
|
|
3336
|
+
specify "should handle columns on prepared statements correctly" do
|
|
3337
|
+
@db.columns = [:num]
|
|
3338
|
+
@ds.meta_def(:select_where_sql){|sql| super(sql); sql << " OR #{columns.first} = 1" if opts[:where]}
|
|
3339
|
+
@ds.filter(:num=>:$n).prepare(:select, :sn).sql.should == 'SELECT * FROM items WHERE (num = $n) OR num = 1'
|
|
3340
|
+
@db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
3341
|
+
end
|
|
3342
|
+
|
|
3332
3343
|
specify "should handle datasets using static sql and placeholders" do
|
|
3333
3344
|
@db["SELECT * FROM items WHERE (num = ?)", :$n].call(:select, :n=>1)
|
|
3334
3345
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
@@ -3357,23 +3368,16 @@ end
|
|
|
3357
3368
|
|
|
3358
3369
|
describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3359
3370
|
before do
|
|
3360
|
-
@db = Sequel
|
|
3361
|
-
@db.meta_def(:sqls){@sqls||=[]}
|
|
3362
|
-
def @db.execute(sql, opts={})
|
|
3363
|
-
sqls << [sql, *opts[:arguments]]
|
|
3364
|
-
end
|
|
3371
|
+
@db = Sequel.mock
|
|
3365
3372
|
@ds = @db[:items].filter(:num=>:$n)
|
|
3366
|
-
def @ds.fetch_rows(sql, &block)
|
|
3367
|
-
execute(sql)
|
|
3368
|
-
end
|
|
3369
3373
|
def @ds.execute(sql, opts={}, &block)
|
|
3370
|
-
|
|
3374
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3371
3375
|
end
|
|
3372
|
-
def @ds.execute_dui(
|
|
3373
|
-
|
|
3376
|
+
def @ds.execute_dui(sql, opts={}, &block)
|
|
3377
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3374
3378
|
end
|
|
3375
|
-
def @ds.execute_insert(
|
|
3376
|
-
|
|
3379
|
+
def @ds.execute_insert(sql, opts={}, &block)
|
|
3380
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3377
3381
|
end
|
|
3378
3382
|
@ps = []
|
|
3379
3383
|
@ps << @ds.prepare(:select, :s)
|
|
@@ -3386,64 +3390,51 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
|
3386
3390
|
end
|
|
3387
3391
|
|
|
3388
3392
|
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 = ?)">'
|
|
3393
|
+
@ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
|
3390
3394
|
end
|
|
3391
3395
|
|
|
3392
|
-
specify "should
|
|
3396
|
+
specify "should submit the SQL to the database with placeholders and bind variables" do
|
|
3393
3397
|
@ps.each{|p| p.prepared_sql; p.call(:n=>1)}
|
|
3394
|
-
@db.sqls.should == [
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3398
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3399
|
+
"SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3400
|
+
"SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
|
|
3401
|
+
"DELETE FROM items WHERE (num = ?) -- args: [1]",
|
|
3402
|
+
"INSERT INTO items (num) VALUES (?) -- args: [1]",
|
|
3403
|
+
"UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
|
|
3404
|
+
end
|
|
3405
|
+
|
|
3406
|
+
specify "should handle unrecognized statement types as :all" do
|
|
3407
|
+
ps = @ds.prepare(:select_all, :s)
|
|
3408
|
+
ps.extend(Sequel::Dataset::UnnumberedArgumentMapper)
|
|
3409
|
+
ps.prepared_sql
|
|
3410
|
+
ps.call(:n=>1)
|
|
3411
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]"]
|
|
3401
3412
|
end
|
|
3402
3413
|
end
|
|
3403
3414
|
|
|
3404
3415
|
describe "Sequel::Dataset#server" do
|
|
3405
3416
|
specify "should set the server to use for the dataset" do
|
|
3406
|
-
@db = Sequel
|
|
3417
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}, :d=>{}, :u=>{}})
|
|
3407
3418
|
@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
3419
|
@ds.all
|
|
3416
3420
|
@ds.server(:i).insert(:a=>1)
|
|
3417
3421
|
@ds.server(:d).delete
|
|
3418
3422
|
@ds.server(:u).update(:a=>:a+1)
|
|
3419
|
-
sqls.should == [
|
|
3420
|
-
['INSERT INTO items (a) VALUES (1)', :i],
|
|
3421
|
-
['DELETE FROM items', :d],
|
|
3422
|
-
['UPDATE items SET a = (a + 1)', :u]]
|
|
3423
|
+
@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
3424
|
end
|
|
3424
3425
|
end
|
|
3425
3426
|
|
|
3426
3427
|
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
3428
|
specify "should yield a dataset for each server" do
|
|
3429
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}})
|
|
3430
|
+
@ds = @db[:items]
|
|
3440
3431
|
@ds.each_server do |ds|
|
|
3441
3432
|
ds.should be_a_kind_of(Sequel::Dataset)
|
|
3442
3433
|
ds.should_not == @ds
|
|
3443
3434
|
ds.sql.should == @ds.sql
|
|
3444
3435
|
ds.all
|
|
3445
3436
|
end
|
|
3446
|
-
@sqls.
|
|
3437
|
+
@db.sqls.sort.should == ['SELECT * FROM items', 'SELECT * FROM items -- i', 'SELECT * FROM items -- s']
|
|
3447
3438
|
end
|
|
3448
3439
|
end
|
|
3449
3440
|
|
|
@@ -3493,23 +3484,23 @@ end
|
|
|
3493
3484
|
|
|
3494
3485
|
describe "Sequel::Dataset#qualify" do
|
|
3495
3486
|
specify "should qualify to the given table" do
|
|
3496
|
-
|
|
3487
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3497
3488
|
end
|
|
3498
3489
|
|
|
3499
3490
|
specify "should qualify to the first source if no table if given" do
|
|
3500
|
-
|
|
3491
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
|
|
3501
3492
|
end
|
|
3502
3493
|
end
|
|
3503
3494
|
|
|
3504
3495
|
describe "Sequel::Dataset#qualify_to" do
|
|
3505
3496
|
specify "should qualify to the given table" do
|
|
3506
|
-
|
|
3497
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3507
3498
|
end
|
|
3508
3499
|
end
|
|
3509
3500
|
|
|
3510
3501
|
describe "Sequel::Dataset#qualify_to_first_source" do
|
|
3511
3502
|
before do
|
|
3512
|
-
@ds =
|
|
3503
|
+
@ds = Sequel::Database.new[:t]
|
|
3513
3504
|
end
|
|
3514
3505
|
|
|
3515
3506
|
specify "should qualify_to the first source" do
|
|
@@ -3519,13 +3510,11 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3519
3510
|
end
|
|
3520
3511
|
|
|
3521
3512
|
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'
|
|
3513
|
+
@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
3514
|
end
|
|
3525
3515
|
|
|
3526
3516
|
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'
|
|
3517
|
+
@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
3518
|
end
|
|
3530
3519
|
|
|
3531
3520
|
specify "should handle hashes in select option" do
|
|
@@ -3588,20 +3577,97 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3588
3577
|
@ds.filter(':a > :b', :a=>:c, :b=>1).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.c > 1)'
|
|
3589
3578
|
end
|
|
3590
3579
|
|
|
3580
|
+
specify "should handle SQL::Wrappers" do
|
|
3581
|
+
@ds.filter(Sequel::SQL::Wrapper.new(:a)).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE t.a'
|
|
3582
|
+
end
|
|
3583
|
+
|
|
3591
3584
|
specify "should handle SQL::WindowFunctions" do
|
|
3592
3585
|
@ds.meta_def(:supports_window_functions?){true}
|
|
3593
3586
|
@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
3587
|
end
|
|
3595
3588
|
|
|
3596
3589
|
specify "should handle all other objects by returning them unchanged" do
|
|
3597
|
-
@ds.select("a").filter{a(3)}.filter('blah').order('true'.lit).group('a > ?'.lit(1)).having(false).qualify_to_first_source.sql.should ==
|
|
3598
|
-
|
|
3590
|
+
@ds.select("a").filter{a(3)}.filter('blah').order('true'.lit).group('a > ?'.lit(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"
|
|
3591
|
+
end
|
|
3592
|
+
end
|
|
3593
|
+
|
|
3594
|
+
describe "Sequel::Dataset#unbind" do
|
|
3595
|
+
before do
|
|
3596
|
+
@ds = Sequel::Database.new[:t]
|
|
3597
|
+
@u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
|
|
3598
|
+
end
|
|
3599
|
+
|
|
3600
|
+
specify "should unbind values assigned to equality and inequality statements" do
|
|
3601
|
+
@ds.filter(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo = $foo)"
|
|
3602
|
+
@ds.exclude(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo != $foo)"
|
|
3603
|
+
@ds.filter{foo > 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo > $foo)"
|
|
3604
|
+
@ds.filter{foo >= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo >= $foo)"
|
|
3605
|
+
@ds.filter{foo < 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo < $foo)"
|
|
3606
|
+
@ds.filter{foo <= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo <= $foo)"
|
|
3607
|
+
end
|
|
3608
|
+
|
|
3609
|
+
specify "should return variables that could be used bound to recreate the previous query" do
|
|
3610
|
+
@ds.filter(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3611
|
+
@ds.exclude(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3612
|
+
end
|
|
3613
|
+
|
|
3614
|
+
specify "should handle numerics, strings, dates, times, and datetimes" do
|
|
3615
|
+
@u[@ds.filter(:foo=>1)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1}]
|
|
3616
|
+
@u[@ds.filter(:foo=>1.0)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1.0}]
|
|
3617
|
+
@u[@ds.filter(:foo=>BigDecimal.new('1.0'))].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>BigDecimal.new('1.0')}]
|
|
3618
|
+
@u[@ds.filter(:foo=>'a')].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>'a'}]
|
|
3619
|
+
@u[@ds.filter(:foo=>Date.today)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>Date.today}]
|
|
3620
|
+
t = Time.now
|
|
3621
|
+
@u[@ds.filter(:foo=>t)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>t}]
|
|
3622
|
+
dt = DateTime.now
|
|
3623
|
+
@u[@ds.filter(:foo=>dt)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>dt}]
|
|
3624
|
+
end
|
|
3625
|
+
|
|
3626
|
+
specify "should not unbind literal strings" do
|
|
3627
|
+
@u[@ds.filter(:foo=>'a'.lit)].should == ["SELECT * FROM t WHERE (foo = a)", {}]
|
|
3628
|
+
end
|
|
3629
|
+
|
|
3630
|
+
specify "should not unbind Identifiers, QualifiedIdentifiers, or Symbols used as booleans" do
|
|
3631
|
+
@u[@ds.filter(:foo).filter{bar}.filter{foo__bar}].should == ["SELECT * FROM t WHERE (foo AND bar AND foo.bar)", {}]
|
|
3632
|
+
end
|
|
3633
|
+
|
|
3634
|
+
specify "should not unbind for values it doesn't understand" do
|
|
3635
|
+
@u[@ds.filter(:foo=>Class.new{def sql_literal(ds) 'bar' end}.new)].should == ["SELECT * FROM t WHERE (foo = bar)", {}]
|
|
3636
|
+
end
|
|
3637
|
+
|
|
3638
|
+
specify "should handle QualifiedIdentifiers" do
|
|
3639
|
+
@u[@ds.filter{foo__bar > 1}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3640
|
+
end
|
|
3641
|
+
|
|
3642
|
+
specify "should handle wrapped objects" do
|
|
3643
|
+
@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}]
|
|
3644
|
+
end
|
|
3645
|
+
|
|
3646
|
+
specify "should handle deep nesting" do
|
|
3647
|
+
@u[@ds.filter{foo > 1}.and{bar < 2}.or(:baz=>3).and({~{:x=>4}=>true}.case(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}]
|
|
3648
|
+
end
|
|
3649
|
+
|
|
3650
|
+
specify "should handle JOIN ON" do
|
|
3651
|
+
@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}]
|
|
3652
|
+
end
|
|
3653
|
+
|
|
3654
|
+
specify "should raise an UnbindDuplicate exception if same variable is used with multiple different values" do
|
|
3655
|
+
proc{@ds.filter(:foo=>1).or(:foo=>2).unbind}.should raise_error(Sequel::UnbindDuplicate)
|
|
3656
|
+
end
|
|
3657
|
+
|
|
3658
|
+
specify "should handle case where the same variable has the same value in multiple places " do
|
|
3659
|
+
@u[@ds.filter(:foo=>1).or(:foo=>1)].should == ["SELECT * FROM t WHERE ((foo = $foo) OR (foo = $foo))", {:foo=>1}]
|
|
3660
|
+
end
|
|
3661
|
+
|
|
3662
|
+
specify "should raise Error for unhandled objects inside Identifiers and QualifiedIndentifiers" do
|
|
3663
|
+
proc{@ds.filter(Sequel::SQL::Identifier.new([]) > 1).unbind}.should raise_error(Sequel::Error)
|
|
3664
|
+
proc{@ds.filter{foo.qualify({}) > 1}.unbind}.should raise_error(Sequel::Error)
|
|
3599
3665
|
end
|
|
3600
3666
|
end
|
|
3601
3667
|
|
|
3602
3668
|
describe "Sequel::Dataset #with and #with_recursive" do
|
|
3603
3669
|
before do
|
|
3604
|
-
@db =
|
|
3670
|
+
@db = Sequel::Database.new
|
|
3605
3671
|
@ds = @db[:t]
|
|
3606
3672
|
end
|
|
3607
3673
|
|
|
@@ -3633,56 +3699,72 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
|
3633
3699
|
proc{@ds.with(:t, @db[:x], :args=>[:b])}.should raise_error(Sequel::Error)
|
|
3634
3700
|
proc{@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c])}.should raise_error(Sequel::Error)
|
|
3635
3701
|
end
|
|
3702
|
+
|
|
3703
|
+
specify "#with should work on insert, update, and delete statements if they support it" do
|
|
3704
|
+
[:insert, :update, :delete].each do |m|
|
|
3705
|
+
@ds.meta_def(:"#{m}_clause_methods"){[:"#{m}_with_sql"] + super()}
|
|
3706
|
+
end
|
|
3707
|
+
@ds.with(:t, @db[:x]).insert_sql(1).should == 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
|
|
3708
|
+
@ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
|
|
3709
|
+
@ds.with(:t, @db[:x]).delete_sql.should == 'WITH t AS (SELECT * FROM x) DELETE FROM t'
|
|
3710
|
+
end
|
|
3711
|
+
|
|
3712
|
+
specify "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
|
|
3713
|
+
@ds.meta_def(:supports_cte?){true}
|
|
3714
|
+
@ds.meta_def(:supports_cte_in_subselect?){false}
|
|
3715
|
+
@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'
|
|
3716
|
+
@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'
|
|
3717
|
+
end
|
|
3636
3718
|
end
|
|
3637
3719
|
|
|
3638
3720
|
describe Sequel::SQL::Constants do
|
|
3639
3721
|
before do
|
|
3640
|
-
@db =
|
|
3722
|
+
@db = Sequel::Database.new
|
|
3641
3723
|
end
|
|
3642
3724
|
|
|
3643
3725
|
it "should have CURRENT_DATE" do
|
|
3644
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_DATE) == 'CURRENT_DATE'
|
|
3645
|
-
@db.literal(Sequel::CURRENT_DATE) == 'CURRENT_DATE'
|
|
3726
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_DATE).should == 'CURRENT_DATE'
|
|
3727
|
+
@db.literal(Sequel::CURRENT_DATE).should == 'CURRENT_DATE'
|
|
3646
3728
|
end
|
|
3647
3729
|
|
|
3648
3730
|
it "should have CURRENT_TIME" do
|
|
3649
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_TIME) == 'CURRENT_TIME'
|
|
3650
|
-
@db.literal(Sequel::CURRENT_TIME) == 'CURRENT_TIME'
|
|
3731
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_TIME).should == 'CURRENT_TIME'
|
|
3732
|
+
@db.literal(Sequel::CURRENT_TIME).should == 'CURRENT_TIME'
|
|
3651
3733
|
end
|
|
3652
3734
|
|
|
3653
3735
|
it "should have CURRENT_TIMESTAMP" do
|
|
3654
|
-
@db.literal(Sequel::SQL::Constants::CURRENT_TIMESTAMP) == 'CURRENT_TIMESTAMP'
|
|
3655
|
-
@db.literal(Sequel::CURRENT_TIMESTAMP) == 'CURRENT_TIMESTAMP'
|
|
3736
|
+
@db.literal(Sequel::SQL::Constants::CURRENT_TIMESTAMP).should == 'CURRENT_TIMESTAMP'
|
|
3737
|
+
@db.literal(Sequel::CURRENT_TIMESTAMP).should == 'CURRENT_TIMESTAMP'
|
|
3656
3738
|
end
|
|
3657
3739
|
|
|
3658
3740
|
it "should have NULL" do
|
|
3659
|
-
@db.literal(Sequel::SQL::Constants::NULL) == 'NULL'
|
|
3660
|
-
@db.literal(Sequel::NULL) == 'NULL'
|
|
3741
|
+
@db.literal(Sequel::SQL::Constants::NULL).should == 'NULL'
|
|
3742
|
+
@db.literal(Sequel::NULL).should == 'NULL'
|
|
3661
3743
|
end
|
|
3662
3744
|
|
|
3663
3745
|
it "should have NOTNULL" do
|
|
3664
|
-
@db.literal(Sequel::SQL::Constants::NOTNULL) == 'NOT NULL'
|
|
3665
|
-
@db.literal(Sequel::NOTNULL) == 'NOT NULL'
|
|
3746
|
+
@db.literal(Sequel::SQL::Constants::NOTNULL).should == 'NOT NULL'
|
|
3747
|
+
@db.literal(Sequel::NOTNULL).should == 'NOT NULL'
|
|
3666
3748
|
end
|
|
3667
3749
|
|
|
3668
3750
|
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) == '
|
|
3751
|
+
@db.literal(Sequel::SQL::Constants::TRUE).should == "'t'"
|
|
3752
|
+
@db.literal(Sequel::TRUE).should == "'t'"
|
|
3753
|
+
@db.literal(Sequel::SQL::Constants::SQLTRUE).should == "'t'"
|
|
3754
|
+
@db.literal(Sequel::SQLTRUE).should == "'t'"
|
|
3673
3755
|
end
|
|
3674
3756
|
|
|
3675
3757
|
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) == '
|
|
3758
|
+
@db.literal(Sequel::SQL::Constants::FALSE).should == "'f'"
|
|
3759
|
+
@db.literal(Sequel::FALSE).should == "'f'"
|
|
3760
|
+
@db.literal(Sequel::SQL::Constants::SQLFALSE).should == "'f'"
|
|
3761
|
+
@db.literal(Sequel::SQLFALSE).should == "'f'"
|
|
3680
3762
|
end
|
|
3681
3763
|
end
|
|
3682
3764
|
|
|
3683
3765
|
describe "Sequel timezone support" do
|
|
3684
3766
|
before do
|
|
3685
|
-
@db =
|
|
3767
|
+
@db = Sequel::Database.new
|
|
3686
3768
|
@dataset = @db.dataset
|
|
3687
3769
|
@dataset.meta_def(:supports_timestamp_timezones?){true}
|
|
3688
3770
|
@dataset.meta_def(:supports_timestamp_usecs?){false}
|
|
@@ -3717,6 +3799,30 @@ describe "Sequel timezone support" do
|
|
|
3717
3799
|
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3718
3800
|
end
|
|
3719
3801
|
|
|
3802
|
+
specify "should have Database#timezone override Sequel.database_timezone" do
|
|
3803
|
+
Sequel.database_timezone = :local
|
|
3804
|
+
@db.timezone = :utc
|
|
3805
|
+
|
|
3806
|
+
t = Time.now
|
|
3807
|
+
s = t.getutc.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3808
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3809
|
+
|
|
3810
|
+
t = DateTime.now
|
|
3811
|
+
s = t.new_offset(0).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3812
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3813
|
+
|
|
3814
|
+
Sequel.database_timezone = :utc
|
|
3815
|
+
@db.timezone = :local
|
|
3816
|
+
|
|
3817
|
+
t = Time.now.utc
|
|
3818
|
+
s = t.getlocal.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3819
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3820
|
+
|
|
3821
|
+
t = DateTime.now.new_offset(0)
|
|
3822
|
+
s = t.new_offset(DateTime.now.offset).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3823
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3824
|
+
end
|
|
3825
|
+
|
|
3720
3826
|
specify "should handle converting database timestamps into application timestamps" do
|
|
3721
3827
|
Sequel.database_timezone = :utc
|
|
3722
3828
|
Sequel.application_timezone = :local
|
|
@@ -3827,13 +3933,7 @@ end
|
|
|
3827
3933
|
|
|
3828
3934
|
describe "Sequel::Dataset#select_map" do
|
|
3829
3935
|
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
|
|
3936
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3837
3937
|
end
|
|
3838
3938
|
|
|
3839
3939
|
specify "should do select and map in one step" do
|
|
@@ -3846,6 +3946,12 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3846
3946
|
@ds.db.sqls.should == ['SELECT a.b FROM t']
|
|
3847
3947
|
end
|
|
3848
3948
|
|
|
3949
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
3950
|
+
proc{@ds.select_map([:a.sql_function, :b])}.should raise_error(Sequel::Error)
|
|
3951
|
+
proc{@ds.select_map(:a.sql_function){b}}.should raise_error(Sequel::Error)
|
|
3952
|
+
proc{@ds.select_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
3953
|
+
end
|
|
3954
|
+
|
|
3849
3955
|
specify "should handle implicit aliases in arguments" do
|
|
3850
3956
|
@ds.select_map(:a___b).should == [1, 2]
|
|
3851
3957
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
@@ -3856,21 +3962,47 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3856
3962
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
3857
3963
|
end
|
|
3858
3964
|
|
|
3965
|
+
specify "should handle identifiers with strings" do
|
|
3966
|
+
@ds.select_map([Sequel::SQL::Identifier.new('c'), :c]).should == [[1, 1], [2, 2]]
|
|
3967
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3968
|
+
end
|
|
3969
|
+
|
|
3859
3970
|
specify "should accept a block" do
|
|
3860
3971
|
@ds.select_map{a(t__c)}.should == [1, 2]
|
|
3861
3972
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t']
|
|
3862
3973
|
end
|
|
3974
|
+
|
|
3975
|
+
specify "should accept a block with an array of columns" do
|
|
3976
|
+
@ds.select_map{[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
3977
|
+
@ds.db.sqls.should == ['SELECT a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3978
|
+
end
|
|
3979
|
+
|
|
3980
|
+
specify "should accept a block with a column" do
|
|
3981
|
+
@ds.select_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
3982
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t']
|
|
3983
|
+
end
|
|
3984
|
+
|
|
3985
|
+
specify "should accept a block and array of arguments" do
|
|
3986
|
+
@ds.select_map([:c, :c]){[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
3987
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3988
|
+
end
|
|
3989
|
+
|
|
3990
|
+
specify "should handle an array of columns" do
|
|
3991
|
+
@ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3992
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3993
|
+
@ds.select_map([:d.as(:c), :c.qualify(:b), :c.identifier, :c.identifier.qualify(:b), :a__c, :a__d___c]).should == [[1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2]]
|
|
3994
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
|
|
3995
|
+
end
|
|
3996
|
+
|
|
3997
|
+
specify "should handle an array with a single element" do
|
|
3998
|
+
@ds.select_map([:c]).should == [[1], [2]]
|
|
3999
|
+
@ds.db.sqls.should == ['SELECT c FROM t']
|
|
4000
|
+
end
|
|
3863
4001
|
end
|
|
3864
4002
|
|
|
3865
4003
|
describe "Sequel::Dataset#select_order_map" do
|
|
3866
4004
|
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
|
|
4005
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3874
4006
|
end
|
|
3875
4007
|
|
|
3876
4008
|
specify "should do select and map in one step" do
|
|
@@ -3883,6 +4015,12 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3883
4015
|
@ds.db.sqls.should == ['SELECT a.b FROM t ORDER BY a.b']
|
|
3884
4016
|
end
|
|
3885
4017
|
|
|
4018
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
4019
|
+
proc{@ds.select_order_map([:a.sql_function, :b])}.should raise_error(Sequel::Error)
|
|
4020
|
+
proc{@ds.select_order_map(:a.sql_function){b}}.should raise_error(Sequel::Error)
|
|
4021
|
+
proc{@ds.select_order_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
4022
|
+
end
|
|
4023
|
+
|
|
3886
4024
|
specify "should handle implicit aliases in arguments" do
|
|
3887
4025
|
@ds.select_order_map(:a___b).should == [1, 2]
|
|
3888
4026
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
@@ -3898,55 +4036,160 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3898
4036
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
3899
4037
|
end
|
|
3900
4038
|
|
|
4039
|
+
specify "should handle OrderedExpressions" do
|
|
4040
|
+
@ds.select_order_map(:a.desc).should == [1, 2]
|
|
4041
|
+
@ds.db.sqls.should == ['SELECT a FROM t ORDER BY a DESC']
|
|
4042
|
+
end
|
|
4043
|
+
|
|
3901
4044
|
specify "should accept a block" do
|
|
3902
4045
|
@ds.select_order_map{a(t__c)}.should == [1, 2]
|
|
3903
4046
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t ORDER BY a(t.c)']
|
|
3904
4047
|
end
|
|
4048
|
+
|
|
4049
|
+
specify "should accept a block with an array of columns" do
|
|
4050
|
+
@ds.select_order_map{[c.desc, a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
4051
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c DESC, a(t.c)']
|
|
4052
|
+
end
|
|
4053
|
+
|
|
4054
|
+
specify "should accept a block with a column" do
|
|
4055
|
+
@ds.select_order_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
4056
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c, a(t.c)']
|
|
4057
|
+
end
|
|
4058
|
+
|
|
4059
|
+
specify "should accept a block and array of arguments" do
|
|
4060
|
+
@ds.select_order_map([:c, :c]){[a(t__c).as(c), c.desc]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
4061
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, c FROM t ORDER BY c, c, a(t.c), c DESC']
|
|
4062
|
+
end
|
|
4063
|
+
|
|
4064
|
+
specify "should handle an array of columns" do
|
|
4065
|
+
@ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
4066
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
|
|
4067
|
+
@ds.select_order_map([:d.as(:c), :c.qualify(:b), :c.identifier, :c.identifier.qualify(:b), :c.identifier.qualify(:b).desc, :a__c, :a__d___c.desc]).should == [[1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2]]
|
|
4068
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, b.c, a.c, a.d AS c FROM t ORDER BY d, b.c, c, b.c, b.c DESC, a.c, a.d DESC']
|
|
4069
|
+
end
|
|
4070
|
+
|
|
4071
|
+
specify "should handle an array with a single element" do
|
|
4072
|
+
@ds.select_order_map([:c]).should == [[1], [2]]
|
|
4073
|
+
@ds.db.sqls.should == ['SELECT c FROM t ORDER BY c']
|
|
4074
|
+
end
|
|
3905
4075
|
end
|
|
3906
4076
|
|
|
3907
4077
|
describe "Sequel::Dataset#select_hash" do
|
|
3908
4078
|
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
|
|
4079
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4080
|
+
@ds = @db[:t]
|
|
3918
4081
|
end
|
|
3919
4082
|
|
|
3920
|
-
specify "should do select and
|
|
3921
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4083
|
+
specify "should do select and to_hash in one step" do
|
|
3922
4084
|
@ds.select_hash(:a, :b).should == {1=>2, 3=>4}
|
|
3923
4085
|
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3924
4086
|
end
|
|
3925
4087
|
|
|
3926
4088
|
specify "should handle implicit qualifiers in arguments" do
|
|
3927
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3928
4089
|
@ds.select_hash(:t__a, :t__b).should == {1=>2, 3=>4}
|
|
3929
4090
|
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3930
4091
|
end
|
|
3931
4092
|
|
|
3932
4093
|
specify "should handle implicit aliases in arguments" do
|
|
3933
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3934
4094
|
@ds.select_hash(:c___a, :d___b).should == {1=>2, 3=>4}
|
|
3935
4095
|
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
3936
4096
|
end
|
|
3937
4097
|
|
|
3938
4098
|
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
3939
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3940
4099
|
@ds.select_hash(:t__c___a, :t__d___b).should == {1=>2, 3=>4}
|
|
3941
4100
|
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
3942
4101
|
end
|
|
4102
|
+
|
|
4103
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
4104
|
+
@ds.select_hash(:a.identifier, :b.identifier).should == {1=>2, 3=>4}
|
|
4105
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4106
|
+
end
|
|
4107
|
+
|
|
4108
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
4109
|
+
@ds.select_hash(:a.qualify(:t), :b.identifier.qualify(:t)).should == {1=>2, 3=>4}
|
|
4110
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4111
|
+
end
|
|
4112
|
+
|
|
4113
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
4114
|
+
@ds.select_hash(:c.as(:a), :t.as(:b)).should == {1=>2, 3=>4}
|
|
4115
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
4116
|
+
end
|
|
4117
|
+
|
|
4118
|
+
specify "should work with arrays of columns" do
|
|
4119
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
4120
|
+
@ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [4, 6]=>5}
|
|
4121
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
4122
|
+
@ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 4=>[5, 6]}
|
|
4123
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
4124
|
+
@ds.select_hash([:a, :b], [:b, :c]).should == {[1, 2]=>[2, 3], [4, 5]=>[5, 6]}
|
|
4125
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
4126
|
+
end
|
|
4127
|
+
|
|
4128
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
4129
|
+
proc{@ds.select_hash(:c.as(:a), :b.sql_function)}.should raise_error(Sequel::Error)
|
|
4130
|
+
end
|
|
4131
|
+
end
|
|
4132
|
+
|
|
4133
|
+
describe "Sequel::Dataset#select_hash_groups" do
|
|
4134
|
+
before do
|
|
4135
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4136
|
+
@ds = @db[:t]
|
|
4137
|
+
end
|
|
4138
|
+
|
|
4139
|
+
specify "should do select and to_hash in one step" do
|
|
4140
|
+
@ds.select_hash_groups(:a, :b).should == {1=>[2], 3=>[4]}
|
|
4141
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4142
|
+
end
|
|
4143
|
+
|
|
4144
|
+
specify "should handle implicit qualifiers in arguments" do
|
|
4145
|
+
@ds.select_hash_groups(:t__a, :t__b).should == {1=>[2], 3=>[4]}
|
|
4146
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4147
|
+
end
|
|
4148
|
+
|
|
4149
|
+
specify "should handle implicit aliases in arguments" do
|
|
4150
|
+
@ds.select_hash_groups(:c___a, :d___b).should == {1=>[2], 3=>[4]}
|
|
4151
|
+
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
4152
|
+
end
|
|
4153
|
+
|
|
4154
|
+
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
4155
|
+
@ds.select_hash_groups(:t__c___a, :t__d___b).should == {1=>[2], 3=>[4]}
|
|
4156
|
+
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
4157
|
+
end
|
|
4158
|
+
|
|
4159
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
4160
|
+
@ds.select_hash_groups(:a.identifier, :b.identifier).should == {1=>[2], 3=>[4]}
|
|
4161
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4162
|
+
end
|
|
4163
|
+
|
|
4164
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
4165
|
+
@ds.select_hash_groups(:a.qualify(:t), :b.identifier.qualify(:t)).should == {1=>[2], 3=>[4]}
|
|
4166
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4167
|
+
end
|
|
4168
|
+
|
|
4169
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
4170
|
+
@ds.select_hash_groups(:c.as(:a), :t.as(:b)).should == {1=>[2], 3=>[4]}
|
|
4171
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
4172
|
+
end
|
|
4173
|
+
|
|
4174
|
+
specify "should work with arrays of columns" do
|
|
4175
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
4176
|
+
@ds.select_hash_groups([:a, :c], :b).should == {[1, 3]=>[2], [4, 6]=>[5]}
|
|
4177
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
4178
|
+
@ds.select_hash_groups(:a, [:b, :c]).should == {1=>[[2, 3]], 4=>[[5, 6]]}
|
|
4179
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
4180
|
+
@ds.select_hash_groups([:a, :b], [:b, :c]).should == {[1, 2]=>[[2, 3]], [4, 5]=>[[5, 6]]}
|
|
4181
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
4182
|
+
end
|
|
4183
|
+
|
|
4184
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
4185
|
+
proc{@ds.select_hash_groups(:c.as(:a), :b.sql_function)}.should raise_error(Sequel::Error)
|
|
4186
|
+
end
|
|
3943
4187
|
end
|
|
3944
4188
|
|
|
3945
4189
|
describe "Modifying joined datasets" do
|
|
3946
4190
|
before do
|
|
3947
|
-
@ds =
|
|
4191
|
+
@ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
|
|
3948
4192
|
@ds.meta_def(:supports_modifying_joins?){true}
|
|
3949
|
-
@ds.db.reset
|
|
3950
4193
|
end
|
|
3951
4194
|
|
|
3952
4195
|
specify "should allow deleting from joined datasets" do
|
|
@@ -3962,7 +4205,7 @@ end
|
|
|
3962
4205
|
|
|
3963
4206
|
describe "Dataset#lock_style and for_update" do
|
|
3964
4207
|
before do
|
|
3965
|
-
@ds =
|
|
4208
|
+
@ds = Sequel::Dataset.new(nil).from(:t)
|
|
3966
4209
|
end
|
|
3967
4210
|
|
|
3968
4211
|
specify "#for_update should use FOR UPDATE" do
|
|
@@ -3977,3 +4220,89 @@ describe "Dataset#lock_style and for_update" do
|
|
|
3977
4220
|
@ds.lock_style("FOR SHARE").sql.should == "SELECT * FROM t FOR SHARE"
|
|
3978
4221
|
end
|
|
3979
4222
|
end
|
|
4223
|
+
|
|
4224
|
+
describe "Custom ASTTransformer" do
|
|
4225
|
+
specify "should transform given objects" do
|
|
4226
|
+
c = Class.new(Sequel::ASTTransformer) do
|
|
4227
|
+
def v(s)
|
|
4228
|
+
(s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
|
|
4229
|
+
end
|
|
4230
|
+
end.new
|
|
4231
|
+
ds = Sequel::Dataset.new(nil).from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
|
4232
|
+
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)'
|
|
4233
|
+
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)'
|
|
4234
|
+
end
|
|
4235
|
+
end
|
|
4236
|
+
|
|
4237
|
+
describe "Dataset#returning" do
|
|
4238
|
+
before do
|
|
4239
|
+
@ds = Sequel.mock(:fetch=>proc{|s| {:foo=>s}})[:t].returning(:foo)
|
|
4240
|
+
@pr = proc do
|
|
4241
|
+
[:insert, :update, :delete].each do |m|
|
|
4242
|
+
@ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_returning_sql"]}
|
|
4243
|
+
end
|
|
4244
|
+
end
|
|
4245
|
+
end
|
|
4246
|
+
|
|
4247
|
+
specify "should use RETURNING clause in the SQL if the dataset supports it" do
|
|
4248
|
+
@pr.call
|
|
4249
|
+
@ds.delete_sql.should == "DELETE FROM t RETURNING foo"
|
|
4250
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1) RETURNING foo"
|
|
4251
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1 RETURNING foo"
|
|
4252
|
+
end
|
|
4253
|
+
|
|
4254
|
+
specify "should not use RETURNING clause in the SQL if the dataset does not support it" do
|
|
4255
|
+
@ds.delete_sql.should == "DELETE FROM t"
|
|
4256
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1)"
|
|
4257
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1"
|
|
4258
|
+
end
|
|
4259
|
+
|
|
4260
|
+
specify "should have insert, update, and delete yield to blocks if RETURNING is used" do
|
|
4261
|
+
@pr.call
|
|
4262
|
+
h = {}
|
|
4263
|
+
@ds.delete{|r| h = r}
|
|
4264
|
+
h.should == {:foo=>"DELETE FROM t RETURNING foo"}
|
|
4265
|
+
@ds.insert(1){|r| h = r}
|
|
4266
|
+
h.should == {:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}
|
|
4267
|
+
@ds.update(:foo=>1){|r| h = r}
|
|
4268
|
+
h.should == {:foo=>"UPDATE t SET foo = 1 RETURNING foo"}
|
|
4269
|
+
end
|
|
4270
|
+
|
|
4271
|
+
specify "should have insert, update, and delete return arrays of hashes if RETURNING is used and a block is not given" do
|
|
4272
|
+
@pr.call
|
|
4273
|
+
h = {}
|
|
4274
|
+
@ds.delete.should == [{:foo=>"DELETE FROM t RETURNING foo"}]
|
|
4275
|
+
@ds.insert(1).should == [{:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}]
|
|
4276
|
+
@ds.update(:foo=>1).should == [{:foo=>"UPDATE t SET foo = 1 RETURNING foo"}]
|
|
4277
|
+
end
|
|
4278
|
+
end
|
|
4279
|
+
|
|
4280
|
+
describe "Dataset emulating bitwise operator support" do
|
|
4281
|
+
before do
|
|
4282
|
+
@ds = Sequel::Database.new.dataset
|
|
4283
|
+
@ds.quote_identifiers = true
|
|
4284
|
+
def @ds.complex_expression_sql_append(sql, op, args)
|
|
4285
|
+
sql << complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
|
4286
|
+
end
|
|
4287
|
+
end
|
|
4288
|
+
|
|
4289
|
+
it "should work with any numbers of arguments for operators" do
|
|
4290
|
+
@ds.select(Sequel::SQL::ComplexExpression.new(:&, :x)).sql.should == 'SELECT "x"'
|
|
4291
|
+
@ds.select(:x & 1).sql.should == 'SELECT bitand("x", 1)'
|
|
4292
|
+
@ds.select(:x & 1 & 2).sql.should == 'SELECT bitand(bitand("x", 1), 2)'
|
|
4293
|
+
end
|
|
4294
|
+
end
|
|
4295
|
+
|
|
4296
|
+
describe "Dataset feature defaults" do
|
|
4297
|
+
it "should not require aliases for recursive CTEs by default" do
|
|
4298
|
+
Sequel::Database.new.dataset.recursive_cte_requires_column_aliases?.should be_false
|
|
4299
|
+
end
|
|
4300
|
+
|
|
4301
|
+
it "should not require placeholder type specifiers by default" do
|
|
4302
|
+
Sequel::Database.new.dataset.requires_placeholder_type_specifiers?.should be_false
|
|
4303
|
+
end
|
|
4304
|
+
|
|
4305
|
+
it "offset use should be returning a separate row number column by default" do
|
|
4306
|
+
Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
|
|
4307
|
+
end
|
|
4308
|
+
end
|