sequel 3.21.0 → 3.31.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 +485 -3
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +249 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +89 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- 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/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +129 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -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 +5 -7
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -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 +45 -0
- data/lib/sequel/adapters/jdbc/derby.rb +247 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +56 -29
- data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
- data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
- data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +231 -78
- data/lib/sequel/adapters/mock.rb +335 -0
- data/lib/sequel/adapters/mysql.rb +82 -184
- data/lib/sequel/adapters/mysql2.rb +26 -25
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +1 -6
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +351 -53
- data/lib/sequel/adapters/postgres.rb +194 -33
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +321 -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 +231 -106
- data/lib/sequel/adapters/shared/mysql.rb +181 -63
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +231 -41
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +4 -7
- data/lib/sequel/adapters/shared/sqlite.rb +201 -57
- data/lib/sequel/adapters/sqlite.rb +29 -21
- data/lib/sequel/adapters/swift/mysql.rb +12 -7
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +160 -19
- 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 +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +104 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +231 -76
- data/lib/sequel/dataset/features.rb +91 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +48 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +665 -253
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- 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 +1020 -337
- data/lib/sequel/model/base.rb +414 -132
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -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/serialization.rb +88 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -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/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +109 -52
- 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/mssql_spec.rb +111 -29
- data/spec/adapters/mysql_spec.rb +135 -123
- data/spec/adapters/oracle_spec.rb +49 -77
- data/spec/adapters/postgres_spec.rb +267 -78
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +21 -30
- data/spec/core/database_spec.rb +788 -512
- data/spec/core/dataset_spec.rb +1073 -1053
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +419 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +114 -22
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +53 -0
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/migration_spec.rb +35 -32
- data/spec/extensions/named_timezones_spec.rb +23 -3
- data/spec/extensions/nested_attributes_spec.rb +97 -88
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- 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 +53 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +5 -8
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +72 -43
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +18 -29
- data/spec/extensions/spec_helper.rb +13 -61
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -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 +1 -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 +16 -4
- data/spec/integration/associations_test.rb +537 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +461 -65
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +212 -122
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +865 -662
- data/spec/model/base_spec.rb +275 -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 +309 -67
- data/spec/model/model_spec.rb +222 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +381 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +115 -73
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
|
|
@@ -232,6 +218,12 @@ describe "A simple dataset" do
|
|
|
232
218
|
@dataset.insert_sql.should == 'INSERT INTO test DEFAULT VALUES'
|
|
233
219
|
end
|
|
234
220
|
|
|
221
|
+
specify "should use a single column with a default value when the dataset doesn't support using insert statement with default values" do
|
|
222
|
+
@dataset.meta_def(:insert_supports_empty_values?){false}
|
|
223
|
+
@dataset.meta_def(:columns){[:a, :b]}
|
|
224
|
+
@dataset.insert_sql.should == 'INSERT INTO test (b) VALUES (DEFAULT)'
|
|
225
|
+
end
|
|
226
|
+
|
|
235
227
|
specify "should format an insert statement with hash" do
|
|
236
228
|
@dataset.insert_sql(:name => 'wxyz', :price => 342).
|
|
237
229
|
should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
|
|
@@ -245,8 +237,6 @@ describe "A simple dataset" do
|
|
|
245
237
|
end
|
|
246
238
|
|
|
247
239
|
specify "should format an insert statement with an object that respond_to? :values" do
|
|
248
|
-
dbb = Sequel::Database.new
|
|
249
|
-
|
|
250
240
|
v = Object.new
|
|
251
241
|
def v.values; {:a => 1}; end
|
|
252
242
|
|
|
@@ -261,29 +251,24 @@ describe "A simple dataset" do
|
|
|
261
251
|
end
|
|
262
252
|
|
|
263
253
|
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)"
|
|
254
|
+
@dataset.insert_sql(@dataset.from(:something).filter(:x => 2)).should == "INSERT INTO test SELECT * FROM something WHERE (x = 2)"
|
|
267
255
|
end
|
|
268
256
|
|
|
269
257
|
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)"
|
|
258
|
+
@dataset.insert_sql('a', 2, 6.5).should == "INSERT INTO test VALUES ('a', 2, 6.5)"
|
|
272
259
|
end
|
|
273
260
|
|
|
274
261
|
specify "should format an update statement" do
|
|
275
|
-
@dataset.update_sql(:name => 'abc').should ==
|
|
276
|
-
"UPDATE test SET name = 'abc'"
|
|
262
|
+
@dataset.update_sql(:name => 'abc').should == "UPDATE test SET name = 'abc'"
|
|
277
263
|
end
|
|
278
264
|
|
|
279
265
|
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"
|
|
266
|
+
@dataset.clone(:sql => 'xxx yyy zzz').select_sql.should == "xxx yyy zzz"
|
|
282
267
|
end
|
|
283
268
|
|
|
284
269
|
specify "should use the :sql option for all sql methods" do
|
|
285
270
|
sql = "X"
|
|
286
|
-
ds =
|
|
271
|
+
ds = @dataset.clone(:sql=>sql)
|
|
287
272
|
ds.sql.should == sql
|
|
288
273
|
ds.select_sql.should == sql
|
|
289
274
|
ds.insert_sql.should == sql
|
|
@@ -357,12 +342,12 @@ describe "Dataset#exists" do
|
|
|
357
342
|
@ds1.filter(@ds2.exists).sql.should ==
|
|
358
343
|
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
|
359
344
|
@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)))'
|
|
345
|
+
'SELECT * FROM test WHERE ((EXISTS (SELECT * FROM test WHERE (price < 100))) AND (EXISTS (SELECT * FROM test WHERE (price > 50))))'
|
|
361
346
|
end
|
|
362
347
|
|
|
363
348
|
specify "should work in select" do
|
|
364
349
|
@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'
|
|
350
|
+
'SELECT (EXISTS (SELECT * FROM test WHERE (price < 100))) AS a, (EXISTS (SELECT * FROM test WHERE (price > 50))) AS b FROM test'
|
|
366
351
|
end
|
|
367
352
|
end
|
|
368
353
|
|
|
@@ -418,7 +403,7 @@ describe "Dataset#where" do
|
|
|
418
403
|
b.should == a
|
|
419
404
|
end
|
|
420
405
|
|
|
421
|
-
specify "should not replace named placeholders that don't
|
|
406
|
+
specify "should not replace named placeholders that don't exist in the hash" do
|
|
422
407
|
@dataset.where('price < :price AND id in :ids', :price=>100).select_sql.should ==
|
|
423
408
|
"SELECT * FROM test WHERE (price < 100 AND id in :ids)"
|
|
424
409
|
end
|
|
@@ -538,34 +523,33 @@ describe "Dataset#where" do
|
|
|
538
523
|
|
|
539
524
|
specify "should handle IN/NOT IN queries with multiple columns and a dataset where the database doesn't support it" do
|
|
540
525
|
@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
|
|
526
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
527
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
549
528
|
@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)
|
|
529
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
552
530
|
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
553
|
-
|
|
531
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
554
532
|
end
|
|
555
533
|
|
|
556
534
|
specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it" do
|
|
557
535
|
@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
|
|
536
|
+
db = Sequel.mock
|
|
537
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
564
538
|
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
565
|
-
|
|
566
|
-
d1.instance_variable_set(:@sql_used, nil)
|
|
539
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
567
540
|
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
568
|
-
|
|
541
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
specify "should handle IN/NOT IN queries for datasets with row_procs" do
|
|
545
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
546
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
547
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
548
|
+
d1.row_proc = proc{|h| Object.new}
|
|
549
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
550
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
551
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
552
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
569
553
|
end
|
|
570
554
|
|
|
571
555
|
specify "should accept a subquery for an EXISTS clause" do
|
|
@@ -601,10 +585,18 @@ describe "Dataset#where" do
|
|
|
601
585
|
end
|
|
602
586
|
|
|
603
587
|
specify "should accept true and false as arguments" do
|
|
604
|
-
@dataset.filter(true).sql.should ==
|
|
605
|
-
|
|
606
|
-
@dataset.filter(false).sql.should ==
|
|
607
|
-
|
|
588
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE 't'"
|
|
589
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE 't'"
|
|
590
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
591
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
specify "should use boolean expression if dataset does not support where true/false" do
|
|
595
|
+
def @dataset.supports_where_true?() false end
|
|
596
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
597
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
598
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
599
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
608
600
|
end
|
|
609
601
|
|
|
610
602
|
specify "should allow the use of multiple arguments" do
|
|
@@ -658,33 +650,25 @@ describe "Dataset#or" do
|
|
|
658
650
|
end
|
|
659
651
|
|
|
660
652
|
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))'
|
|
653
|
+
@d1.or(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
|
663
654
|
end
|
|
664
655
|
|
|
665
656
|
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))'
|
|
657
|
+
@d1.or('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
|
658
|
+
@d1.or(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
670
659
|
end
|
|
671
660
|
|
|
672
661
|
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))'
|
|
662
|
+
@d1.or{:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
675
663
|
end
|
|
676
664
|
|
|
677
665
|
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))'
|
|
666
|
+
@d1.filter(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
667
|
+
@d1.or(:y => 2).filter(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
683
668
|
end
|
|
684
669
|
|
|
685
670
|
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)))'
|
|
671
|
+
@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
672
|
end
|
|
689
673
|
end
|
|
690
674
|
|
|
@@ -697,34 +681,25 @@ describe "Dataset#and" do
|
|
|
697
681
|
specify "should raise if no filter exists" do
|
|
698
682
|
proc {@dataset.and(:a => 1)}.should raise_error(Sequel::Error)
|
|
699
683
|
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"
|
|
684
|
+
@dataset.where(:a => 1).group(:t).and(:b => 2).sql == "SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
|
|
702
685
|
end
|
|
703
686
|
|
|
704
687
|
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))'
|
|
688
|
+
@d1.and(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
|
707
689
|
end
|
|
708
690
|
|
|
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))'
|
|
691
|
+
specify "should accept different types of filters" do
|
|
692
|
+
@d1.and('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
|
693
|
+
@d1.and(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
715
694
|
end
|
|
716
695
|
|
|
717
696
|
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))'
|
|
697
|
+
@d1.and {:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
720
698
|
end
|
|
721
699
|
|
|
722
700
|
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))'
|
|
701
|
+
@d1.or(:y => 2).and(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
702
|
+
@d1.and(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
728
703
|
end
|
|
729
704
|
end
|
|
730
705
|
|
|
@@ -734,8 +709,11 @@ describe "Dataset#exclude" do
|
|
|
734
709
|
end
|
|
735
710
|
|
|
736
711
|
specify "should correctly negate the expression when one condition is given" do
|
|
737
|
-
@dataset.exclude(:region=>'Asia').select_sql.should ==
|
|
738
|
-
|
|
712
|
+
@dataset.exclude(:region=>'Asia').select_sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
specify "should affect the having clause if having clause is already used" do
|
|
716
|
+
@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
717
|
end
|
|
740
718
|
|
|
741
719
|
specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
|
|
@@ -745,30 +723,46 @@ describe "Dataset#exclude" do
|
|
|
745
723
|
end
|
|
746
724
|
|
|
747
725
|
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')"
|
|
726
|
+
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
750
727
|
end
|
|
751
728
|
|
|
752
729
|
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')"
|
|
730
|
+
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
755
731
|
end
|
|
756
732
|
|
|
757
733
|
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'))"
|
|
734
|
+
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
|
760
735
|
end
|
|
761
736
|
|
|
762
737
|
specify "should support proc expressions" do
|
|
763
|
-
@dataset.exclude{:id.sql_number < 6}.sql.should ==
|
|
764
|
-
'SELECT * FROM test WHERE (id >= 6)'
|
|
738
|
+
@dataset.exclude{:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE (id >= 6)'
|
|
765
739
|
end
|
|
766
740
|
|
|
767
741
|
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
|
-
|
|
742
|
+
@dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id < 7) OR (id > 11) OR (id >= 6))'
|
|
743
|
+
@dataset.exclude([:id, 1], [:x, 3]){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id != 1) OR (x != 3) OR (id >= 6))'
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
describe "Dataset#exclude_where" do
|
|
748
|
+
before do
|
|
749
|
+
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
specify "should correctly negate the expression and add it to the where clause" do
|
|
753
|
+
@dataset.exclude_where(:region=>'Asia').sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
754
|
+
@dataset.exclude_where(:region=>'Asia').exclude_where(:region=>'NA').sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (region != 'NA'))"
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
specify "should affect the where clause even if having clause is already used" do
|
|
758
|
+
@dataset.group_and_count(:name).having{count > 2}.exclude_where(:region=>'Asia').sql.should ==
|
|
759
|
+
"SELECT name, count(*) AS count FROM test WHERE (region != 'Asia') GROUP BY name HAVING (count > 2)"
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
describe "Dataset#exclude_having" do
|
|
764
|
+
specify "should correctly negate the expression and add it to the having clause" do
|
|
765
|
+
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
766
|
end
|
|
773
767
|
end
|
|
774
768
|
|
|
@@ -794,9 +788,6 @@ describe "Dataset#having" do
|
|
|
794
788
|
before do
|
|
795
789
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
796
790
|
@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
791
|
end
|
|
801
792
|
|
|
802
793
|
specify "should just clone if given an empty argument" do
|
|
@@ -806,18 +797,15 @@ describe "Dataset#having" do
|
|
|
806
797
|
end
|
|
807
798
|
|
|
808
799
|
specify "should affect select statements" do
|
|
809
|
-
@
|
|
810
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
800
|
+
@grouped.having('sum(population) > 10').select_sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
811
801
|
end
|
|
812
802
|
|
|
813
803
|
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)"
|
|
804
|
+
@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
805
|
end
|
|
817
806
|
|
|
818
807
|
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))"
|
|
808
|
+
@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
809
|
end
|
|
822
810
|
end
|
|
823
811
|
|
|
@@ -848,7 +836,7 @@ describe "a grouped dataset" do
|
|
|
848
836
|
end
|
|
849
837
|
|
|
850
838
|
specify "should format the right statement for counting (as a subquery)" do
|
|
851
|
-
db =
|
|
839
|
+
db = Sequel.mock
|
|
852
840
|
db[:test].select(:name).group(:name).count
|
|
853
841
|
db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT name FROM test GROUP BY name) AS t1 LIMIT 1"]
|
|
854
842
|
end
|
|
@@ -856,7 +844,7 @@ end
|
|
|
856
844
|
|
|
857
845
|
describe "Dataset#group_by" do
|
|
858
846
|
before do
|
|
859
|
-
@dataset = Sequel
|
|
847
|
+
@dataset = Sequel.mock[:test].group_by(:type_id)
|
|
860
848
|
end
|
|
861
849
|
|
|
862
850
|
specify "should raise when trying to generate an update statement" do
|
|
@@ -868,45 +856,60 @@ describe "Dataset#group_by" do
|
|
|
868
856
|
end
|
|
869
857
|
|
|
870
858
|
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)"
|
|
859
|
+
@dataset.select_sql.should == "SELECT * FROM test GROUP BY type_id"
|
|
860
|
+
@dataset.group_by(:a, :b).select_sql.should == "SELECT * FROM test GROUP BY a, b"
|
|
861
|
+
@dataset.group_by(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
877
862
|
end
|
|
878
863
|
|
|
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"
|
|
864
|
+
specify "should ungroup when passed nil or no arguments" do
|
|
865
|
+
@dataset.group_by.select_sql.should == "SELECT * FROM test"
|
|
866
|
+
@dataset.group_by(nil).select_sql.should == "SELECT * FROM test"
|
|
884
867
|
end
|
|
885
868
|
|
|
886
869
|
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"
|
|
870
|
+
@dataset.group_by(:a).group_by(:b).select_sql.should == "SELECT * FROM test GROUP BY b"
|
|
871
|
+
@dataset.group_by(:a, :b).group_by.select_sql.should == "SELECT * FROM test"
|
|
891
872
|
end
|
|
892
873
|
|
|
893
874
|
specify "should be aliased as #group" do
|
|
894
|
-
@dataset.group(:type_id=>nil).select_sql.should ==
|
|
895
|
-
|
|
875
|
+
@dataset.group(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
specify "should take a virtual row block" do
|
|
879
|
+
@dataset.group{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
880
|
+
@dataset.group_by{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
881
|
+
@dataset.group{[type_id > 1, type_id < 2]}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1), (type_id < 2)"
|
|
882
|
+
@dataset.group(:foo){type_id > 1}.sql.should == "SELECT * FROM test GROUP BY foo, (type_id > 1)"
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
specify "should support a #group_rollup method if the database supports it" do
|
|
886
|
+
@dataset.meta_def(:supports_group_rollup?){true}
|
|
887
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id)"
|
|
888
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id, b)"
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
specify "should support a #group_cube method if the database supports it" do
|
|
892
|
+
@dataset.meta_def(:supports_group_cube?){true}
|
|
893
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id)"
|
|
894
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id, b)"
|
|
895
|
+
end
|
|
896
|
+
|
|
897
|
+
specify "should have #group_cube and #group_rollup methods raise an Error if not supported it" do
|
|
898
|
+
proc{@dataset.group(:type_id).group_rollup}.should raise_error(Sequel::Error)
|
|
899
|
+
proc{@dataset.group(:type_id).group_cube}.should raise_error(Sequel::Error)
|
|
896
900
|
end
|
|
897
901
|
end
|
|
898
902
|
|
|
899
903
|
describe "Dataset#as" do
|
|
900
904
|
specify "should set up an alias" do
|
|
901
905
|
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'
|
|
906
|
+
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
|
904
907
|
end
|
|
905
908
|
end
|
|
906
909
|
|
|
907
910
|
describe "Dataset#literal" do
|
|
908
911
|
before do
|
|
909
|
-
@dataset = Sequel::
|
|
912
|
+
@dataset = Sequel::Database.new.from(:test)
|
|
910
913
|
end
|
|
911
914
|
|
|
912
915
|
specify "should escape strings properly" do
|
|
@@ -944,6 +947,21 @@ describe "Dataset#literal" do
|
|
|
944
947
|
@dataset.literal(:"items__na#m$e").should == "items.na#m$e"
|
|
945
948
|
end
|
|
946
949
|
|
|
950
|
+
specify "should call sql_literal_append with dataset and sql on type if not natively supported and the object responds to it" do
|
|
951
|
+
@a = Class.new do
|
|
952
|
+
def sql_literal_append(ds, sql)
|
|
953
|
+
sql << "called #{ds.blah}"
|
|
954
|
+
end
|
|
955
|
+
def sql_literal(ds)
|
|
956
|
+
"not called #{ds.blah}"
|
|
957
|
+
end
|
|
958
|
+
end
|
|
959
|
+
def @dataset.blah
|
|
960
|
+
"ds"
|
|
961
|
+
end
|
|
962
|
+
@dataset.literal(@a.new).should == "called ds"
|
|
963
|
+
end
|
|
964
|
+
|
|
947
965
|
specify "should call sql_literal with dataset on type if not natively supported and the object responds to it" do
|
|
948
966
|
@a = Class.new do
|
|
949
967
|
def sql_literal(ds)
|
|
@@ -965,6 +983,12 @@ describe "Dataset#literal" do
|
|
|
965
983
|
d.literal(d).should == "(#{d.sql})"
|
|
966
984
|
end
|
|
967
985
|
|
|
986
|
+
specify "should literalize Sequel::SQLTime properly" do
|
|
987
|
+
t = Sequel::SQLTime.now
|
|
988
|
+
s = t.strftime("'%H:%M:%S")
|
|
989
|
+
@dataset.literal(t).should == "#{s}.#{sprintf('%06i', t.usec)}'"
|
|
990
|
+
end
|
|
991
|
+
|
|
968
992
|
specify "should literalize Time properly" do
|
|
969
993
|
t = Time.now
|
|
970
994
|
s = t.strftime("'%Y-%m-%d %H:%M:%S")
|
|
@@ -1041,10 +1065,9 @@ describe "Dataset#literal" do
|
|
|
1041
1065
|
end
|
|
1042
1066
|
|
|
1043
1067
|
specify "should not modify literal strings" do
|
|
1068
|
+
@dataset.quote_identifiers = true
|
|
1044
1069
|
@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'
|
|
1070
|
+
@dataset.update_sql(Sequel::SQL::Identifier.new('a'.lit) => 'a + 2'.lit).should == 'UPDATE "test" SET a = a + 2'
|
|
1048
1071
|
end
|
|
1049
1072
|
|
|
1050
1073
|
specify "should literalize BigDecimal instances correctly" do
|
|
@@ -1069,35 +1092,25 @@ describe "Dataset#from" do
|
|
|
1069
1092
|
end
|
|
1070
1093
|
|
|
1071
1094
|
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"
|
|
1095
|
+
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should == "SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
|
|
1074
1096
|
end
|
|
1075
1097
|
|
|
1076
1098
|
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"
|
|
1099
|
+
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
|
|
1079
1100
|
|
|
1080
1101
|
d1 = @dataset.from(:a).group(:b)
|
|
1081
1102
|
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"
|
|
1103
|
+
@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
1104
|
end
|
|
1086
1105
|
|
|
1087
1106
|
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"
|
|
1107
|
+
@dataset.from(:a => :b).sql.should == "SELECT * FROM a AS b"
|
|
1108
|
+
@dataset.from(:a => 'b').sql.should == "SELECT * FROM a AS b"
|
|
1109
|
+
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
|
|
1096
1110
|
end
|
|
1097
1111
|
|
|
1098
1112
|
specify "should always use a subquery if given a dataset" do
|
|
1099
|
-
@dataset.from(@dataset.from(:a)).select_sql.should ==
|
|
1100
|
-
"SELECT * FROM (SELECT * FROM a) AS t1"
|
|
1113
|
+
@dataset.from(@dataset.from(:a)).select_sql.should == "SELECT * FROM (SELECT * FROM a) AS t1"
|
|
1101
1114
|
end
|
|
1102
1115
|
|
|
1103
1116
|
specify "should remove all FROM tables if called with no arguments" do
|
|
@@ -1105,32 +1118,31 @@ describe "Dataset#from" do
|
|
|
1105
1118
|
end
|
|
1106
1119
|
|
|
1107
1120
|
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)"
|
|
1121
|
+
@dataset.from(:abc.sql_function(:def)).select_sql.should == "SELECT * FROM abc(def)"
|
|
1122
|
+
@dataset.from(:a.sql_function(:i)).select_sql.should == "SELECT * FROM a(i)"
|
|
1113
1123
|
end
|
|
1114
1124
|
|
|
1115
1125
|
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
|
-
|
|
1126
|
+
@dataset.from(:abc__def).select_sql.should == "SELECT * FROM abc.def"
|
|
1127
|
+
@dataset.from(:a_b__c).select_sql.should == "SELECT * FROM a_b.c"
|
|
1128
|
+
@dataset.from(:'#__#').select_sql.should == 'SELECT * FROM #.#'
|
|
1129
|
+
@dataset.from(:abc__def___d).select_sql.should == "SELECT * FROM abc.def AS d"
|
|
1130
|
+
@dataset.from(:a_b__d_e___f_g).select_sql.should == "SELECT * FROM a_b.d_e AS f_g"
|
|
1131
|
+
@dataset.from(:'#__#___#').select_sql.should == 'SELECT * FROM #.# AS #'
|
|
1132
|
+
@dataset.from(:abc___def).select_sql.should == "SELECT * FROM abc AS def"
|
|
1133
|
+
@dataset.from(:a_b___c_d).select_sql.should == "SELECT * FROM a_b AS c_d"
|
|
1134
|
+
@dataset.from(:'#___#').select_sql.should == 'SELECT * FROM # AS #'
|
|
1135
|
+
end
|
|
1136
|
+
|
|
1137
|
+
specify "should not handle :foo__schema__table___alias specially" do
|
|
1138
|
+
@dataset.from(:foo__schema__table___alias).select_sql.should == "SELECT * FROM foo.schema__table AS alias"
|
|
1139
|
+
end
|
|
1140
|
+
|
|
1141
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
1142
|
+
@dataset.meta_def(:supports_cte?){true}
|
|
1143
|
+
@dataset.meta_def(:supports_cte_in_subselect?){false}
|
|
1144
|
+
@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'
|
|
1145
|
+
@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
1146
|
end
|
|
1135
1147
|
end
|
|
1136
1148
|
|
|
@@ -1147,18 +1159,17 @@ describe "Dataset#select" do
|
|
|
1147
1159
|
specify "should accept symbols and literal strings" do
|
|
1148
1160
|
@d.select('aaa'.lit).sql.should == 'SELECT aaa FROM test'
|
|
1149
1161
|
@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'
|
|
1162
|
+
@d.select(:test__cc, 'test.d AS e'.lit).sql.should == 'SELECT test.cc, test.d AS e FROM test'
|
|
1163
|
+
@d.select('test.d AS e'.lit, :test__cc).sql.should == 'SELECT test.d AS e, test.cc FROM test'
|
|
1164
|
+
@d.select(:test__name___n).sql.should == 'SELECT test.name AS n FROM test'
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
specify "should accept ColumnAlls" do
|
|
1168
|
+
@d.select(:test.*).sql.should == 'SELECT test.* FROM test'
|
|
1169
|
+
end
|
|
1170
|
+
|
|
1171
|
+
specify "should accept QualifiedIdentifiers" do
|
|
1172
|
+
@d.select(:test__name.as(:n)).sql.should == 'SELECT test.name AS n FROM test'
|
|
1162
1173
|
end
|
|
1163
1174
|
|
|
1164
1175
|
specify "should use the wildcard if no arguments are given" do
|
|
@@ -1166,20 +1177,17 @@ describe "Dataset#select" do
|
|
|
1166
1177
|
end
|
|
1167
1178
|
|
|
1168
1179
|
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/
|
|
1180
|
+
@d.select(:name => 'n', :__ggh => 'age').sql.should =~ /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
|
1171
1181
|
end
|
|
1172
1182
|
|
|
1173
|
-
specify "should
|
|
1183
|
+
specify "should override the previous select option" do
|
|
1174
1184
|
@d.select!(:a, :b, :c).select.sql.should == 'SELECT * FROM test'
|
|
1175
1185
|
@d.select!(:price).select(:name).sql.should == 'SELECT name FROM test'
|
|
1176
1186
|
end
|
|
1177
1187
|
|
|
1178
1188
|
specify "should accept arbitrary objects and literalize them correctly" do
|
|
1179
1189
|
@d.select(1, :a, 't').sql.should == "SELECT 1, a, 't' FROM test"
|
|
1180
|
-
|
|
1181
1190
|
@d.select(nil, :sum.sql_function(:t), :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
|
|
1182
|
-
|
|
1183
1191
|
@d.select(nil, 1, :x => :y).sql.should == "SELECT NULL, 1, x AS y FROM test"
|
|
1184
1192
|
end
|
|
1185
1193
|
|
|
@@ -1198,6 +1206,27 @@ describe "Dataset#select" do
|
|
|
1198
1206
|
end
|
|
1199
1207
|
end
|
|
1200
1208
|
|
|
1209
|
+
describe "Dataset#select_group" do
|
|
1210
|
+
before do
|
|
1211
|
+
@d = Sequel::Dataset.new(nil).from(:test)
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
specify "should set both SELECT and GROUP" do
|
|
1215
|
+
@d.select_group(:name).sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1216
|
+
@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'
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
specify "should remove from both SELECT and GROUP if no arguments" do
|
|
1220
|
+
@d.select_group(:name).select_group.sql.should == 'SELECT * FROM test'
|
|
1221
|
+
end
|
|
1222
|
+
|
|
1223
|
+
specify "should accept virtual row blocks" do
|
|
1224
|
+
@d.select_group{name}.sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1225
|
+
@d.select_group{[name, f(v).as(a)]}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1226
|
+
@d.select_group(:name){f(v).as(a)}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1227
|
+
end
|
|
1228
|
+
end
|
|
1229
|
+
|
|
1201
1230
|
describe "Dataset#select_all" do
|
|
1202
1231
|
before do
|
|
1203
1232
|
@d = Sequel::Dataset.new(nil).from(:test)
|
|
@@ -1207,9 +1236,43 @@ describe "Dataset#select_all" do
|
|
|
1207
1236
|
@d.select_all.sql.should == 'SELECT * FROM test'
|
|
1208
1237
|
end
|
|
1209
1238
|
|
|
1210
|
-
specify "should
|
|
1239
|
+
specify "should override the previous select option" do
|
|
1211
1240
|
@d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
|
|
1212
1241
|
end
|
|
1242
|
+
|
|
1243
|
+
specify "should select all columns in a table if given an argument" do
|
|
1244
|
+
@d.select_all(:test).sql.should == 'SELECT test.* FROM test'
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
specify "should select all columns all tables if given a multiple arguments" do
|
|
1248
|
+
@d.select_all(:test, :foo).sql.should == 'SELECT test.*, foo.* FROM test'
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
specify "should work correctly with qualified symbols" do
|
|
1252
|
+
@d.select_all(:sch__test).sql.should == 'SELECT sch.test.* FROM test'
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1255
|
+
specify "should work correctly with aliased symbols" do
|
|
1256
|
+
@d.select_all(:test___al).sql.should == 'SELECT al.* FROM test'
|
|
1257
|
+
@d.select_all(:sch__test___al).sql.should == 'SELECT al.* FROM test'
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
specify "should work correctly with SQL::Identifiers" do
|
|
1261
|
+
@d.select_all(:test.identifier).sql.should == 'SELECT test.* FROM test'
|
|
1262
|
+
end
|
|
1263
|
+
|
|
1264
|
+
specify "should work correctly with SQL::QualifiedIdentifier" do
|
|
1265
|
+
@d.select_all(:test.qualify(:sch)).sql.should == 'SELECT sch.test.* FROM test'
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
specify "should work correctly with SQL::AliasedExpressions" do
|
|
1269
|
+
@d.select_all(:test.as(:al)).sql.should == 'SELECT al.* FROM test'
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
specify "should work correctly with SQL::JoinClauses" do
|
|
1273
|
+
d = @d.cross_join(:foo).cross_join(:test___al)
|
|
1274
|
+
@d.select_all(*d.opts[:join]).sql.should == 'SELECT foo.*, al.* FROM test'
|
|
1275
|
+
end
|
|
1213
1276
|
end
|
|
1214
1277
|
|
|
1215
1278
|
describe "Dataset#select_more" do
|
|
@@ -1254,6 +1317,14 @@ describe "Dataset#select_append" do
|
|
|
1254
1317
|
@d.select(:a).select_append{|o| o.b}.sql.should == 'SELECT a, b FROM test'
|
|
1255
1318
|
@d.select(:a.*).select_append(:b.*){b(1)}.sql.should == 'SELECT a.*, b.*, b(1) FROM test'
|
|
1256
1319
|
end
|
|
1320
|
+
|
|
1321
|
+
specify "should select from all from and join tables if SELECT *, column not supported" do
|
|
1322
|
+
@d.meta_def(:supports_select_all_and_column?){false}
|
|
1323
|
+
@d.select_append(:b).sql.should == 'SELECT test.*, b FROM test'
|
|
1324
|
+
@d.from(:test, :c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test, c'
|
|
1325
|
+
@d.cross_join(:c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test CROSS JOIN c'
|
|
1326
|
+
@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'
|
|
1327
|
+
end
|
|
1257
1328
|
end
|
|
1258
1329
|
|
|
1259
1330
|
describe "Dataset#order" do
|
|
@@ -1262,38 +1333,31 @@ describe "Dataset#order" do
|
|
|
1262
1333
|
end
|
|
1263
1334
|
|
|
1264
1335
|
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'
|
|
1336
|
+
@dataset.order(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1267
1337
|
end
|
|
1268
1338
|
|
|
1269
1339
|
specify "should accept multiple arguments" do
|
|
1270
|
-
@dataset.order(:name, :price.desc).sql.should ==
|
|
1271
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1340
|
+
@dataset.order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1272
1341
|
end
|
|
1273
1342
|
|
|
1274
1343
|
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'
|
|
1344
|
+
@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
1345
|
end
|
|
1278
1346
|
|
|
1279
|
-
specify "should
|
|
1280
|
-
@dataset.order(:name).order(:stamp).sql.should ==
|
|
1281
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1347
|
+
specify "should override a previous ordering" do
|
|
1348
|
+
@dataset.order(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1282
1349
|
end
|
|
1283
1350
|
|
|
1284
1351
|
specify "should accept a literal string" do
|
|
1285
|
-
@dataset.order('dada ASC'.lit).sql.should ==
|
|
1286
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1352
|
+
@dataset.order('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1287
1353
|
end
|
|
1288
1354
|
|
|
1289
1355
|
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)'
|
|
1356
|
+
@dataset.order(:name=>nil).sql.should == 'SELECT * FROM test ORDER BY (name IS NULL)'
|
|
1292
1357
|
end
|
|
1293
1358
|
|
|
1294
1359
|
specify "should accept a nil to remove ordering" do
|
|
1295
|
-
@dataset.order(:bah).order(nil).sql.should ==
|
|
1296
|
-
'SELECT * FROM test'
|
|
1360
|
+
@dataset.order(:bah).order(nil).sql.should == 'SELECT * FROM test'
|
|
1297
1361
|
end
|
|
1298
1362
|
|
|
1299
1363
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1355,6 +1419,13 @@ describe "Dataset#with_sql" do
|
|
|
1355
1419
|
specify "should keep row_proc" do
|
|
1356
1420
|
@dataset.with_sql('SELECT 1 FROM test').row_proc.should == @dataset.row_proc
|
|
1357
1421
|
end
|
|
1422
|
+
|
|
1423
|
+
specify "should work with method symbols and arguments" do
|
|
1424
|
+
@dataset.with_sql(:delete_sql).sql.should == 'DELETE FROM test'
|
|
1425
|
+
@dataset.with_sql(:insert_sql, :b=>1).sql.should == 'INSERT INTO test (b) VALUES (1)'
|
|
1426
|
+
@dataset.with_sql(:update_sql, :b=>1).sql.should == 'UPDATE test SET b = 1'
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1358
1429
|
end
|
|
1359
1430
|
|
|
1360
1431
|
describe "Dataset#order_by" do
|
|
@@ -1363,28 +1434,23 @@ describe "Dataset#order_by" do
|
|
|
1363
1434
|
end
|
|
1364
1435
|
|
|
1365
1436
|
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'
|
|
1437
|
+
@dataset.order_by(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1368
1438
|
end
|
|
1369
1439
|
|
|
1370
1440
|
specify "should accept multiple arguments" do
|
|
1371
|
-
@dataset.order_by(:name, :price.desc).sql.should ==
|
|
1372
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1441
|
+
@dataset.order_by(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1373
1442
|
end
|
|
1374
1443
|
|
|
1375
|
-
specify "should
|
|
1376
|
-
@dataset.order_by(:name).order(:stamp).sql.should ==
|
|
1377
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1444
|
+
specify "should override a previous ordering" do
|
|
1445
|
+
@dataset.order_by(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1378
1446
|
end
|
|
1379
1447
|
|
|
1380
1448
|
specify "should accept a string" do
|
|
1381
|
-
@dataset.order_by('dada ASC'.lit).sql.should ==
|
|
1382
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1449
|
+
@dataset.order_by('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1383
1450
|
end
|
|
1384
1451
|
|
|
1385
1452
|
specify "should accept a nil to remove ordering" do
|
|
1386
|
-
@dataset.order_by(:bah).order_by(nil).sql.should ==
|
|
1387
|
-
'SELECT * FROM test'
|
|
1453
|
+
@dataset.order_by(:bah).order_by(nil).sql.should == 'SELECT * FROM test'
|
|
1388
1454
|
end
|
|
1389
1455
|
end
|
|
1390
1456
|
|
|
@@ -1417,13 +1483,11 @@ describe "Dataset#order_prepend" do
|
|
|
1417
1483
|
end
|
|
1418
1484
|
|
|
1419
1485
|
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'
|
|
1486
|
+
@dataset.order_prepend(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1422
1487
|
end
|
|
1423
1488
|
|
|
1424
1489
|
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'
|
|
1490
|
+
@dataset.order(:name).order_prepend(:stamp.desc).sql.should == 'SELECT * FROM test ORDER BY stamp DESC, name'
|
|
1427
1491
|
end
|
|
1428
1492
|
|
|
1429
1493
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1438,45 +1502,36 @@ describe "Dataset#reverse_order" do
|
|
|
1438
1502
|
end
|
|
1439
1503
|
|
|
1440
1504
|
specify "should use DESC as default order" do
|
|
1441
|
-
@dataset.reverse_order(:name).sql.should ==
|
|
1442
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1505
|
+
@dataset.reverse_order(:name).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1443
1506
|
end
|
|
1444
1507
|
|
|
1445
1508
|
specify "should invert the order given" do
|
|
1446
|
-
@dataset.reverse_order(:name.desc).sql.should ==
|
|
1447
|
-
'SELECT * FROM test ORDER BY name ASC'
|
|
1509
|
+
@dataset.reverse_order(:name.desc).sql.should == 'SELECT * FROM test ORDER BY name ASC'
|
|
1448
1510
|
end
|
|
1449
1511
|
|
|
1450
1512
|
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'
|
|
1513
|
+
@dataset.reverse_order(:name.asc).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1453
1514
|
end
|
|
1454
1515
|
|
|
1455
1516
|
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'
|
|
1517
|
+
@dataset.reverse_order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name DESC, price ASC'
|
|
1458
1518
|
end
|
|
1459
1519
|
|
|
1460
1520
|
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'
|
|
1521
|
+
@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
1522
|
end
|
|
1464
1523
|
|
|
1465
1524
|
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'
|
|
1525
|
+
@dataset.order(:name).reverse_order.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1526
|
+
@dataset.order(:clumsy.desc, :fool).reverse_order.sql.should == 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
|
|
1470
1527
|
end
|
|
1471
1528
|
|
|
1472
1529
|
specify "should return an unordered dataset for a dataset with no order" do
|
|
1473
|
-
@dataset.unordered.reverse_order.sql.should ==
|
|
1474
|
-
'SELECT * FROM test'
|
|
1530
|
+
@dataset.unordered.reverse_order.sql.should == 'SELECT * FROM test'
|
|
1475
1531
|
end
|
|
1476
1532
|
|
|
1477
1533
|
specify "should have #reverse alias" do
|
|
1478
|
-
@dataset.order(:name).reverse.sql.should ==
|
|
1479
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1534
|
+
@dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1480
1535
|
end
|
|
1481
1536
|
end
|
|
1482
1537
|
|
|
@@ -1486,42 +1541,33 @@ describe "Dataset#limit" do
|
|
|
1486
1541
|
end
|
|
1487
1542
|
|
|
1488
1543
|
specify "should include a LIMIT clause in the select statement" do
|
|
1489
|
-
@dataset.limit(10).sql.should ==
|
|
1490
|
-
'SELECT * FROM test LIMIT 10'
|
|
1544
|
+
@dataset.limit(10).sql.should == 'SELECT * FROM test LIMIT 10'
|
|
1491
1545
|
end
|
|
1492
1546
|
|
|
1493
1547
|
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'
|
|
1548
|
+
@dataset.limit(3..7).sql.should == 'SELECT * FROM test LIMIT 5 OFFSET 3'
|
|
1549
|
+
@dataset.limit(3...7).sql.should == 'SELECT * FROM test LIMIT 4 OFFSET 3'
|
|
1499
1550
|
end
|
|
1500
1551
|
|
|
1501
1552
|
specify "should include an offset if a second argument is given" do
|
|
1502
|
-
@dataset.limit(6, 10).sql.should ==
|
|
1503
|
-
|
|
1504
|
-
end
|
|
1553
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 10'
|
|
1554
|
+
end
|
|
1505
1555
|
|
|
1506
1556
|
specify "should convert regular strings to integers" do
|
|
1507
|
-
@dataset.limit('6', 'a() - 1').sql.should ==
|
|
1508
|
-
'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1557
|
+
@dataset.limit('6', 'a() - 1').sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1509
1558
|
end
|
|
1510
1559
|
|
|
1511
1560
|
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'
|
|
1561
|
+
@dataset.limit('6'.lit, 'a() - 1'.lit).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1514
1562
|
end
|
|
1515
1563
|
|
|
1516
1564
|
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)'
|
|
1565
|
+
@dataset.limit(6, :a.sql_function - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1519
1566
|
end
|
|
1520
1567
|
|
|
1521
1568
|
specify "should work with fixed sql datasets" do
|
|
1522
1569
|
@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'
|
|
1570
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
|
1525
1571
|
end
|
|
1526
1572
|
|
|
1527
1573
|
specify "should raise an error if an invalid limit or offset is used" do
|
|
@@ -1535,15 +1581,10 @@ describe "Dataset#limit" do
|
|
|
1535
1581
|
end
|
|
1536
1582
|
|
|
1537
1583
|
describe "Dataset#naked" do
|
|
1538
|
-
before do
|
|
1539
|
-
@d1 = Sequel::Dataset.new(nil, {1 => 2, 3 => 4})
|
|
1540
|
-
@d2 = @d1.clone
|
|
1541
|
-
@d2.row_proc = Proc.new{|r| r}
|
|
1542
|
-
end
|
|
1543
|
-
|
|
1544
1584
|
specify "should remove any existing row_proc" do
|
|
1545
|
-
|
|
1546
|
-
|
|
1585
|
+
d = Sequel::Dataset.new(nil)
|
|
1586
|
+
d.row_proc = Proc.new{|r| r}
|
|
1587
|
+
d.naked.row_proc.should be_nil
|
|
1547
1588
|
end
|
|
1548
1589
|
end
|
|
1549
1590
|
|
|
@@ -1571,38 +1612,42 @@ describe "Dataset#qualified_column_name" do
|
|
|
1571
1612
|
end
|
|
1572
1613
|
end
|
|
1573
1614
|
|
|
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
1615
|
describe "Dataset#map" do
|
|
1586
1616
|
before do
|
|
1587
|
-
@d =
|
|
1617
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1588
1618
|
end
|
|
1589
1619
|
|
|
1590
1620
|
specify "should provide the usual functionality if no argument is given" do
|
|
1591
|
-
@d.map
|
|
1621
|
+
@d.map{|n| n[:a] + n[:b]}.should == [3, 7, 11]
|
|
1592
1622
|
end
|
|
1593
1623
|
|
|
1594
1624
|
specify "should map using #[column name] if column name is given" do
|
|
1595
1625
|
@d.map(:a).should == [1, 3, 5]
|
|
1596
1626
|
end
|
|
1597
1627
|
|
|
1628
|
+
specify "should support multiple column names if an array of column names is given" do
|
|
1629
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
specify "should not call the row_proc if an argument is given" do
|
|
1633
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1634
|
+
@d.map(:a).should == [1, 3, 5]
|
|
1635
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1636
|
+
end
|
|
1637
|
+
|
|
1638
|
+
specify "should call the row_proc if no argument is given" do
|
|
1639
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1640
|
+
@d.map{|n| n[:a] + n[:b]}.should == [6, 14, 22]
|
|
1641
|
+
end
|
|
1642
|
+
|
|
1598
1643
|
specify "should return the complete dataset values if nothing is given" do
|
|
1599
|
-
@d.map.to_a.should ==
|
|
1644
|
+
@d.map.to_a.should == [{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}]
|
|
1600
1645
|
end
|
|
1601
1646
|
end
|
|
1602
1647
|
|
|
1603
1648
|
describe "Dataset#to_hash" do
|
|
1604
1649
|
before do
|
|
1605
|
-
@d =
|
|
1650
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1606
1651
|
end
|
|
1607
1652
|
|
|
1608
1653
|
specify "should provide a hash with the first column as key and the second as value" do
|
|
@@ -1614,11 +1659,35 @@ describe "Dataset#to_hash" do
|
|
|
1614
1659
|
@d.to_hash(:a).should == {1 => {:a => 1, :b => 2}, 3 => {:a => 3, :b => 4}, 5 => {:a => 5, :b => 6}}
|
|
1615
1660
|
@d.to_hash(:b).should == {2 => {:a => 1, :b => 2}, 4 => {:a => 3, :b => 4}, 6 => {:a => 5, :b => 6}}
|
|
1616
1661
|
end
|
|
1662
|
+
|
|
1663
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1664
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1665
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1666
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1667
|
+
@d.to_hash([:a, :b]).should == {[1, 2] => {:a => 1, :b => 2}, [3, 4] => {:a => 3, :b => 4}, [5, 6] => {:a => 5, :b => 6}}
|
|
1668
|
+
end
|
|
1669
|
+
|
|
1670
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1671
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1672
|
+
@d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
|
|
1673
|
+
@d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
|
|
1674
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1675
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1676
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1677
|
+
end
|
|
1678
|
+
|
|
1679
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1680
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1681
|
+
@d.to_hash(:a).should == {2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12}}
|
|
1682
|
+
@d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
|
|
1683
|
+
@d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
|
|
1684
|
+
end
|
|
1685
|
+
|
|
1617
1686
|
end
|
|
1618
1687
|
|
|
1619
1688
|
describe "Dataset#distinct" do
|
|
1620
1689
|
before do
|
|
1621
|
-
@db =
|
|
1690
|
+
@db = Sequel.mock
|
|
1622
1691
|
@dataset = @db[:test].select(:name)
|
|
1623
1692
|
end
|
|
1624
1693
|
|
|
@@ -1645,132 +1714,100 @@ end
|
|
|
1645
1714
|
|
|
1646
1715
|
describe "Dataset#count" do
|
|
1647
1716
|
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)
|
|
1717
|
+
@db = Sequel.mock(:fetch=>{:count=>1})
|
|
1718
|
+
@dataset = @db.from(:test).columns(:count)
|
|
1660
1719
|
end
|
|
1661
1720
|
|
|
1662
1721
|
specify "should format SQL properly" do
|
|
1663
1722
|
@dataset.count.should == 1
|
|
1664
|
-
@
|
|
1723
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
|
|
1665
1724
|
end
|
|
1666
1725
|
|
|
1667
1726
|
specify "should include the where clause if it's there" do
|
|
1668
1727
|
@dataset.filter(:abc.sql_number < 30).count.should == 1
|
|
1669
|
-
@
|
|
1728
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
|
|
1670
1729
|
end
|
|
1671
1730
|
|
|
1672
1731
|
specify "should count properly for datasets with fixed sql" do
|
|
1673
1732
|
@dataset.opts[:sql] = "select abc from xyz"
|
|
1674
1733
|
@dataset.count.should == 1
|
|
1675
|
-
@
|
|
1734
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
|
|
1676
1735
|
end
|
|
1677
1736
|
|
|
1678
1737
|
specify "should count properly when using UNION, INTERSECT, or EXCEPT" do
|
|
1679
1738
|
@dataset.union(@dataset).count.should == 1
|
|
1680
|
-
@
|
|
1739
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1681
1740
|
@dataset.intersect(@dataset).count.should == 1
|
|
1682
|
-
@
|
|
1741
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1683
1742
|
@dataset.except(@dataset).count.should == 1
|
|
1684
|
-
@
|
|
1743
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1685
1744
|
end
|
|
1686
1745
|
|
|
1687
1746
|
specify "should return limit if count is greater than it" do
|
|
1688
1747
|
@dataset.limit(5).count.should == 1
|
|
1689
|
-
@
|
|
1748
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"]
|
|
1690
1749
|
end
|
|
1691
1750
|
|
|
1692
1751
|
it "should work on a graphed_dataset" do
|
|
1693
1752
|
@dataset.should_receive(:columns).twice.and_return([:a])
|
|
1694
1753
|
@dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
|
|
1695
|
-
@
|
|
1754
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
1696
1755
|
end
|
|
1697
1756
|
|
|
1698
1757
|
specify "should not cache the columns value" do
|
|
1699
|
-
ds = @dataset.from(:blah)
|
|
1758
|
+
ds = @dataset.from(:blah).columns(:a)
|
|
1700
1759
|
ds.columns.should == [:a]
|
|
1701
1760
|
ds.count.should == 1
|
|
1702
|
-
@
|
|
1761
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM blah LIMIT 1']
|
|
1703
1762
|
ds.columns.should == [:a]
|
|
1704
1763
|
end
|
|
1705
1764
|
end
|
|
1706
1765
|
|
|
1707
|
-
|
|
1708
1766
|
describe "Dataset#group_and_count" do
|
|
1709
1767
|
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)
|
|
1768
|
+
@ds = Sequel::Dataset.new(nil).from(:test)
|
|
1721
1769
|
end
|
|
1722
1770
|
|
|
1723
1771
|
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"
|
|
1772
|
+
@ds.group_and_count(:name).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1726
1773
|
end
|
|
1727
1774
|
|
|
1728
1775
|
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"
|
|
1776
|
+
@ds.group_and_count(:a, :b).sql.should == "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
|
|
1731
1777
|
end
|
|
1732
1778
|
|
|
1733
1779
|
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"
|
|
1780
|
+
@ds.group_and_count(:name___n).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1781
|
+
@ds.group_and_count(:name__n).sql.should == "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
|
1738
1782
|
end
|
|
1739
1783
|
|
|
1740
1784
|
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"
|
|
1785
|
+
@ds.group_and_count(:name___n.identifier).sql.should == "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1743
1786
|
end
|
|
1744
1787
|
|
|
1745
1788
|
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"
|
|
1789
|
+
@ds.group_and_count("name".lit).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1748
1790
|
end
|
|
1749
1791
|
|
|
1750
1792
|
specify "should handle aliased expressions" do
|
|
1751
|
-
@ds.group_and_count(:name.as(:n)).sql.should ==
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1793
|
+
@ds.group_and_count(:name.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1794
|
+
@ds.group_and_count(:name.identifier.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1795
|
+
end
|
|
1796
|
+
|
|
1797
|
+
specify "should take a virtual row block" do
|
|
1798
|
+
@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)"
|
|
1799
|
+
@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)"
|
|
1800
|
+
@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
1801
|
end
|
|
1756
1802
|
end
|
|
1757
1803
|
|
|
1758
1804
|
describe "Dataset#empty?" do
|
|
1759
1805
|
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"
|
|
1806
|
+
db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
|
|
1807
|
+
db.from(:test).should_not be_empty
|
|
1808
|
+
db.sqls.should == ['SELECT 1 AS one FROM test LIMIT 1']
|
|
1809
|
+
db.from(:test).filter(false).should be_empty
|
|
1810
|
+
db.sqls.should == ["SELECT 1 AS one FROM test WHERE 'f' LIMIT 1"]
|
|
1774
1811
|
end
|
|
1775
1812
|
end
|
|
1776
1813
|
|
|
@@ -1817,9 +1854,9 @@ describe "Dataset#first_source_table" do
|
|
|
1817
1854
|
end
|
|
1818
1855
|
|
|
1819
1856
|
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 ==
|
|
1857
|
+
@ds.literal(@ds.from(:t___a).first_source_table).should == "t"
|
|
1858
|
+
@ds.literal(@ds.from(:s__t___a).first_source_table).should == "s.t"
|
|
1859
|
+
@ds.literal(@ds.from(:t.as(:a)).first_source_table).should == "t"
|
|
1823
1860
|
end
|
|
1824
1861
|
|
|
1825
1862
|
specify "should raise exception if table doesn't have a source" do
|
|
@@ -1849,25 +1886,31 @@ describe "Dataset#from_self" do
|
|
|
1849
1886
|
'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
|
|
1850
1887
|
end
|
|
1851
1888
|
|
|
1852
|
-
specify "should not options such as server" do
|
|
1889
|
+
specify "should not remove non-SQL options such as :server" do
|
|
1853
1890
|
@ds.server(:blah).from_self(:alias=>:some_name).opts[:server].should == :blah
|
|
1854
1891
|
end
|
|
1855
1892
|
|
|
1893
|
+
specify "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
|
|
1894
|
+
ds = Sequel::Dataset.new(nil)
|
|
1895
|
+
ds.meta_def(:supports_cte?){true}
|
|
1896
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
1897
|
+
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'
|
|
1898
|
+
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'
|
|
1899
|
+
end
|
|
1856
1900
|
end
|
|
1857
1901
|
|
|
1858
1902
|
describe "Dataset#join_table" do
|
|
1859
1903
|
before do
|
|
1860
|
-
@d =
|
|
1904
|
+
@d = Sequel::Dataset.new(nil).from(:items)
|
|
1861
1905
|
@d.quote_identifiers = true
|
|
1862
1906
|
end
|
|
1863
1907
|
|
|
1864
1908
|
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")'
|
|
1909
|
+
@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
1910
|
end
|
|
1868
1911
|
|
|
1869
1912
|
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 ==
|
|
1913
|
+
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
|
1871
1914
|
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND ("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100))'
|
|
1872
1915
|
end
|
|
1873
1916
|
|
|
@@ -1877,45 +1920,30 @@ describe "Dataset#join_table" do
|
|
|
1877
1920
|
end
|
|
1878
1921
|
|
|
1879
1922
|
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"'
|
|
1923
|
+
@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
1924
|
end
|
|
1883
1925
|
|
|
1884
1926
|
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")'
|
|
1927
|
+
@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
1928
|
end
|
|
1888
1929
|
|
|
1889
1930
|
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")'
|
|
1931
|
+
@d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1892
1932
|
end
|
|
1893
1933
|
|
|
1894
1934
|
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"'
|
|
1935
|
+
@d.left_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1936
|
+
@d.right_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1937
|
+
@d.full_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1938
|
+
@d.inner_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1939
|
+
@d.left_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1940
|
+
@d.right_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1941
|
+
@d.full_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1942
|
+
@d.natural_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
1943
|
+
@d.natural_left_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
|
|
1944
|
+
@d.natural_right_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
|
|
1945
|
+
@d.natural_full_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
|
|
1946
|
+
@d.cross_join(:categories).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
1919
1947
|
end
|
|
1920
1948
|
|
|
1921
1949
|
specify "should raise an error if additional arguments are provided to join methods that don't take conditions" do
|
|
@@ -1935,95 +1963,68 @@ describe "Dataset#join_table" do
|
|
|
1935
1963
|
end
|
|
1936
1964
|
|
|
1937
1965
|
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")'
|
|
1966
|
+
@d.join_table(nil, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1940
1967
|
end
|
|
1941
1968
|
|
|
1942
1969
|
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")'
|
|
1970
|
+
@d.join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1945
1971
|
end
|
|
1946
1972
|
|
|
1947
1973
|
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")'
|
|
1974
|
+
@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
1975
|
end
|
|
1951
1976
|
|
|
1952
1977
|
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")'
|
|
1978
|
+
@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
1979
|
end
|
|
1956
1980
|
|
|
1957
1981
|
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")'
|
|
1982
|
+
@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
1983
|
end
|
|
1961
1984
|
|
|
1962
1985
|
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")'
|
|
1986
|
+
@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
1987
|
end
|
|
1968
1988
|
|
|
1969
1989
|
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")'
|
|
1990
|
+
@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
1991
|
end
|
|
1973
1992
|
|
|
1974
1993
|
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")'
|
|
1994
|
+
@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")'
|
|
1995
|
+
@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
1996
|
end
|
|
1980
1997
|
|
|
1981
1998
|
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")'
|
|
1999
|
+
@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
2000
|
end
|
|
1985
2001
|
|
|
1986
2002
|
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")'
|
|
2003
|
+
@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
2004
|
end
|
|
1990
2005
|
|
|
1991
2006
|
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))'
|
|
2007
|
+
@d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
|
2008
|
+
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
|
2009
|
+
@d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
|
2010
|
+
@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
2011
|
end
|
|
2001
2012
|
|
|
2002
2013
|
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)
|
|
2014
|
+
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.should raise_error(Sequel::Error)
|
|
2005
2015
|
end
|
|
2006
2016
|
|
|
2007
2017
|
specify "should support joining datasets" do
|
|
2008
2018
|
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
|
-
|
|
2019
|
+
@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
2020
|
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")'
|
|
2021
|
+
@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")'
|
|
2022
|
+
@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
2023
|
end
|
|
2021
2024
|
|
|
2022
2025
|
specify "should support joining datasets and aliasing the join" do
|
|
2023
2026
|
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")'
|
|
2027
|
+
@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
2028
|
end
|
|
2028
2029
|
|
|
2029
2030
|
specify "should support joining multiple datasets" do
|
|
@@ -2040,40 +2041,30 @@ describe "Dataset#join_table" do
|
|
|
2040
2041
|
specify "should support joining objects that respond to :table_name" do
|
|
2041
2042
|
ds = Object.new
|
|
2042
2043
|
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")'
|
|
2044
|
+
@d.join(ds, :item_id => :id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
|
|
2046
2045
|
end
|
|
2047
2046
|
|
|
2048
|
-
specify "should support using
|
|
2049
|
-
@d.join(:categories,
|
|
2050
|
-
'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
|
2047
|
+
specify "should support using an SQL String as the join condition" do
|
|
2048
|
+
@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
2049
|
end
|
|
2052
2050
|
|
|
2053
2051
|
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"'
|
|
2052
|
+
@d.join(:categories, :active).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
|
2056
2053
|
end
|
|
2057
2054
|
|
|
2058
2055
|
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)'
|
|
2056
|
+
@d.join(:categories, :number.sql_number > 10).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2061
2057
|
end
|
|
2062
2058
|
|
|
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"'
|
|
2059
|
+
specify "should support natural and cross joins" do
|
|
2060
|
+
@d.join_table(:natural, :categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2061
|
+
@d.join_table(:cross, :categories, nil).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2062
|
+
@d.join_table(:natural, :categories, nil, :c).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
|
2070
2063
|
end
|
|
2071
2064
|
|
|
2072
2065
|
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")'
|
|
2066
|
+
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
|
|
2067
|
+
@d.join(:categories, [:id1, :id2]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
|
2077
2068
|
end
|
|
2078
2069
|
|
|
2079
2070
|
specify "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
|
|
@@ -2081,6 +2072,12 @@ describe "Dataset#join_table" do
|
|
|
2081
2072
|
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."id" = "items"."id")'
|
|
2082
2073
|
end
|
|
2083
2074
|
|
|
2075
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
2076
|
+
@d.meta_def(:supports_cte?){true}
|
|
2077
|
+
@d.meta_def(:supports_cte_in_subselect?){false}
|
|
2078
|
+
@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")'
|
|
2079
|
+
end
|
|
2080
|
+
|
|
2084
2081
|
specify "should raise an error if using an array of symbols with a block" do
|
|
2085
2082
|
proc{@d.join(:categories, [:id]){|j,lj,js|}}.should raise_error(Sequel::Error)
|
|
2086
2083
|
end
|
|
@@ -2135,27 +2132,21 @@ describe "Dataset#join_table" do
|
|
|
2135
2132
|
end
|
|
2136
2133
|
|
|
2137
2134
|
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")'
|
|
2135
|
+
@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")'
|
|
2136
|
+
@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
2137
|
end
|
|
2143
2138
|
|
|
2144
2139
|
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"))'
|
|
2140
|
+
@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"))'
|
|
2141
|
+
@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
2142
|
end
|
|
2150
2143
|
|
|
2151
2144
|
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")'
|
|
2145
|
+
@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
2146
|
@d.from(:items.as(:i)).join(:categories.as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
|
|
2155
2147
|
'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2156
2148
|
end
|
|
2157
2149
|
|
|
2158
|
-
|
|
2159
2150
|
specify "should not allow insert, update, delete, or truncate" do
|
|
2160
2151
|
proc{@d.join(:categories, :a=>:d).insert_sql}.should raise_error(Sequel::InvalidOperation)
|
|
2161
2152
|
proc{@d.join(:categories, :a=>:d).update_sql(:a=>1)}.should raise_error(Sequel::InvalidOperation)
|
|
@@ -2170,81 +2161,52 @@ describe "Dataset#join_table" do
|
|
|
2170
2161
|
end
|
|
2171
2162
|
|
|
2172
2163
|
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
2164
|
specify "should perform an update on the specified filter" do
|
|
2188
|
-
|
|
2189
|
-
|
|
2165
|
+
db = Sequel.mock
|
|
2166
|
+
ds = db[:items]
|
|
2167
|
+
ds[:a => 1] = {:x => 3}
|
|
2168
|
+
db.sqls.should == ['UPDATE items SET x = 3 WHERE (a = 1)']
|
|
2190
2169
|
end
|
|
2191
2170
|
end
|
|
2192
2171
|
|
|
2193
2172
|
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
2173
|
specify "should act as alias to #update" do
|
|
2209
|
-
|
|
2210
|
-
|
|
2174
|
+
db = Sequel.mock
|
|
2175
|
+
ds = db[:items]
|
|
2176
|
+
ds.set({:x => 3})
|
|
2177
|
+
db.sqls.should == ['UPDATE items SET x = 3']
|
|
2211
2178
|
end
|
|
2212
2179
|
end
|
|
2213
2180
|
|
|
2214
|
-
|
|
2215
2181
|
describe "Dataset#insert_multiple" do
|
|
2216
2182
|
before do
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
def insert(arg)
|
|
2220
|
-
@inserts ||= []
|
|
2221
|
-
@inserts << arg
|
|
2222
|
-
end
|
|
2223
|
-
end
|
|
2224
|
-
|
|
2225
|
-
@d = c.new(nil)
|
|
2183
|
+
@db = Sequel.mock(:autoid=>2)
|
|
2184
|
+
@ds = @db[:items]
|
|
2226
2185
|
end
|
|
2227
2186
|
|
|
2228
2187
|
specify "should insert all items in the supplied array" do
|
|
2229
|
-
@
|
|
2230
|
-
@
|
|
2188
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}])
|
|
2189
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('aa')",
|
|
2190
|
+
"INSERT INTO items VALUES (5)",
|
|
2191
|
+
"INSERT INTO items VALUES (3)",
|
|
2192
|
+
"INSERT INTO items (a) VALUES (2)"]
|
|
2231
2193
|
end
|
|
2232
2194
|
|
|
2233
2195
|
specify "should pass array items through the supplied block if given" do
|
|
2234
|
-
|
|
2235
|
-
@
|
|
2236
|
-
|
|
2196
|
+
@ds.insert_multiple(["inevitable", "hello", "the ticking clock"]){|i| i.gsub('l', 'r')}
|
|
2197
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('inevitabre')",
|
|
2198
|
+
"INSERT INTO items VALUES ('herro')",
|
|
2199
|
+
"INSERT INTO items VALUES ('the ticking crock')"]
|
|
2200
|
+
end
|
|
2201
|
+
|
|
2202
|
+
specify "should return array of inserted ids" do
|
|
2203
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}]).should == [2, 3, 4, 5]
|
|
2237
2204
|
end
|
|
2238
2205
|
end
|
|
2239
2206
|
|
|
2240
2207
|
describe "Dataset aggregate methods" do
|
|
2241
2208
|
before do
|
|
2242
|
-
|
|
2243
|
-
def fetch_rows(sql)
|
|
2244
|
-
yield({1 => sql})
|
|
2245
|
-
end
|
|
2246
|
-
end
|
|
2247
|
-
@d = c.new(nil).from(:test)
|
|
2209
|
+
@d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
|
|
2248
2210
|
end
|
|
2249
2211
|
|
|
2250
2212
|
specify "should include min" do
|
|
@@ -2278,116 +2240,88 @@ end
|
|
|
2278
2240
|
|
|
2279
2241
|
describe "Dataset#range" do
|
|
2280
2242
|
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)
|
|
2243
|
+
@db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
|
|
2244
|
+
@ds = @db[:test]
|
|
2292
2245
|
end
|
|
2293
2246
|
|
|
2294
2247
|
specify "should generate a correct SQL statement" do
|
|
2295
|
-
@
|
|
2296
|
-
@
|
|
2248
|
+
@ds.range(:stamp)
|
|
2249
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
|
|
2297
2250
|
|
|
2298
|
-
@
|
|
2299
|
-
@
|
|
2251
|
+
@ds.filter(:price.sql_number > 100).range(:stamp)
|
|
2252
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
|
|
2300
2253
|
end
|
|
2301
2254
|
|
|
2302
2255
|
specify "should return a range object" do
|
|
2303
|
-
@
|
|
2256
|
+
@ds.range(:tryme).should == (1..10)
|
|
2304
2257
|
end
|
|
2305
2258
|
|
|
2306
2259
|
specify "should use a subselect for the same conditions as count" do
|
|
2307
|
-
@
|
|
2308
|
-
@
|
|
2260
|
+
@ds.order(:stamp).limit(5).range(:stamp).should == (1..10)
|
|
2261
|
+
@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
2262
|
end
|
|
2310
2263
|
end
|
|
2311
2264
|
|
|
2312
2265
|
describe "Dataset#interval" do
|
|
2313
2266
|
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)
|
|
2267
|
+
@db = Sequel.mock(:fetch=>{:v => 1234})
|
|
2268
|
+
@ds = @db[:test]
|
|
2325
2269
|
end
|
|
2326
2270
|
|
|
2327
|
-
specify "should generate
|
|
2328
|
-
@
|
|
2329
|
-
@
|
|
2271
|
+
specify "should generate the correct SQL statement" do
|
|
2272
|
+
@ds.interval(:stamp)
|
|
2273
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"]
|
|
2330
2274
|
|
|
2331
|
-
@
|
|
2332
|
-
@
|
|
2333
|
-
end
|
|
2334
|
-
|
|
2335
|
-
specify "should return an integer" do
|
|
2336
|
-
@d.interval(:tryme).should == 1234
|
|
2275
|
+
@ds.filter(:price.sql_number > 100).interval(:stamp)
|
|
2276
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"]
|
|
2337
2277
|
end
|
|
2338
2278
|
|
|
2339
2279
|
specify "should use a subselect for the same conditions as count" do
|
|
2340
|
-
@
|
|
2341
|
-
@
|
|
2280
|
+
@ds.order(:stamp).limit(5).interval(:stamp).should == 1234
|
|
2281
|
+
@db.sqls.should == ['SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
|
|
2342
2282
|
end
|
|
2343
2283
|
end
|
|
2344
2284
|
|
|
2345
2285
|
describe "Dataset #first and #last" do
|
|
2346
2286
|
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)
|
|
2287
|
+
@db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
|
|
2288
|
+
@d = @db[:test]
|
|
2355
2289
|
end
|
|
2356
2290
|
|
|
2357
2291
|
specify "should return a single record if no argument is given" do
|
|
2358
|
-
@d.order(:a).first.should ==
|
|
2359
|
-
@d.order(:a).last.should ==
|
|
2292
|
+
@d.order(:a).first.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
|
|
2293
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2360
2294
|
end
|
|
2361
2295
|
|
|
2362
2296
|
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 ==
|
|
2297
|
+
@d.order(:a).first(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
|
|
2298
|
+
@d.order(:a).first('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
|
|
2299
|
+
@d.order(:a).last(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1'}
|
|
2300
|
+
@d.order(:a).last('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1'}
|
|
2367
2301
|
end
|
|
2368
2302
|
|
|
2369
2303
|
specify "should set the limit and return an array of records if the given number is > 1" do
|
|
2370
2304
|
i = rand(10) + 10
|
|
2371
|
-
r = @d.order(:a).first(i).should == [
|
|
2305
|
+
r = @d.order(:a).first(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
|
|
2372
2306
|
i = rand(10) + 10
|
|
2373
|
-
r = @d.order(:a).last(i).should == [
|
|
2307
|
+
r = @d.order(:a).last(i).should == [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
|
|
2374
2308
|
end
|
|
2375
2309
|
|
|
2376
2310
|
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 ==
|
|
2311
|
+
@d.first{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
|
|
2312
|
+
@d.order(:name).last{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1'}
|
|
2379
2313
|
end
|
|
2380
2314
|
|
|
2381
2315
|
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 ==
|
|
2316
|
+
@d.first(:y=>25){:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
|
|
2317
|
+
@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
2318
|
end
|
|
2385
2319
|
|
|
2386
2320
|
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
|
2387
2321
|
i = rand(10) + 10
|
|
2388
|
-
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [
|
|
2322
|
+
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
|
|
2389
2323
|
i = rand(10) + 10
|
|
2390
|
-
r = @d.order(:a).last(i){:z.sql_number > 26}.should == [
|
|
2324
|
+
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
2325
|
end
|
|
2392
2326
|
|
|
2393
2327
|
specify "#last should raise if no order is given" do
|
|
@@ -2398,10 +2332,10 @@ describe "Dataset #first and #last" do
|
|
|
2398
2332
|
end
|
|
2399
2333
|
|
|
2400
2334
|
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.
|
|
2335
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2336
|
+
@d.order(:b.desc).last.should == {:s=>'SELECT * FROM test ORDER BY b ASC LIMIT 1'}
|
|
2337
|
+
@d.order(:c, :d).last.should == {:s=>'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'}
|
|
2338
|
+
@d.order(:e.desc, :f).last.should == {:s=>'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'}
|
|
2405
2339
|
end
|
|
2406
2340
|
end
|
|
2407
2341
|
|
|
@@ -2412,55 +2346,37 @@ describe "Dataset compound operations" do
|
|
|
2412
2346
|
end
|
|
2413
2347
|
|
|
2414
2348
|
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"
|
|
2349
|
+
@a.union(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2350
|
+
@b.union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2351
|
+
@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
2352
|
end
|
|
2422
2353
|
|
|
2423
2354
|
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"
|
|
2355
|
+
@a.intersect(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2356
|
+
@b.intersect(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2357
|
+
@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
2358
|
end
|
|
2431
2359
|
|
|
2432
2360
|
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"
|
|
2361
|
+
@a.except(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2362
|
+
@b.except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2363
|
+
@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
2364
|
end
|
|
2440
2365
|
|
|
2441
2366
|
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"
|
|
2367
|
+
@a.union(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2368
|
+
@a.intersect(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2369
|
+
@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
2370
|
end
|
|
2449
2371
|
|
|
2450
2372
|
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)"
|
|
2373
|
+
@b.union(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
|
|
2374
|
+
@b.intersect(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
|
|
2375
|
+
@b.except(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
|
|
2457
2376
|
|
|
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)"
|
|
2377
|
+
@b.union(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
|
|
2378
|
+
@b.intersect(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2379
|
+
@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
2380
|
end
|
|
2465
2381
|
|
|
2466
2382
|
specify "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
|
|
@@ -2480,141 +2396,105 @@ describe "Dataset compound operations" do
|
|
|
2480
2396
|
end
|
|
2481
2397
|
|
|
2482
2398
|
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"
|
|
2399
|
+
@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"
|
|
2400
|
+
@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"
|
|
2401
|
+
@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
2402
|
end
|
|
2490
2403
|
|
|
2491
2404
|
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"
|
|
2405
|
+
@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"
|
|
2406
|
+
@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"
|
|
2407
|
+
@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
2408
|
end
|
|
2499
2409
|
|
|
2500
2410
|
specify "should order and limit properly when using UNION, INTERSECT, or EXCEPT" do
|
|
2501
2411
|
@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"
|
|
2412
|
+
@dataset.union(@dataset).limit(2).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
|
|
2413
|
+
@dataset.limit(2).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2414
|
+
@dataset.except(@dataset.limit(2)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
|
|
2415
|
+
|
|
2416
|
+
@dataset.union(@dataset).order(:num).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
|
|
2417
|
+
@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"
|
|
2418
|
+
@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
2419
|
|
|
2516
2420
|
@dataset.limit(2).order(:a).union(@dataset.limit(3).order(:b)).order(:c).limit(4).sql.should ==
|
|
2517
2421
|
"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
2422
|
end
|
|
2519
2423
|
|
|
2424
|
+
specify "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
|
|
2425
|
+
ds = Sequel::Dataset.new(nil)
|
|
2426
|
+
ds.meta_def(:supports_cte?){true}
|
|
2427
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2428
|
+
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'
|
|
2429
|
+
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'
|
|
2430
|
+
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'
|
|
2431
|
+
end
|
|
2520
2432
|
end
|
|
2521
2433
|
|
|
2522
2434
|
describe "Dataset#[]" do
|
|
2523
2435
|
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)
|
|
2436
|
+
@db = Sequel.mock(:fetch=>{1 => 2, 3 => 4})
|
|
2437
|
+
@d = @db[:items]
|
|
2537
2438
|
end
|
|
2538
2439
|
|
|
2539
2440
|
specify "should return a single record filtered according to the given conditions" do
|
|
2540
2441
|
@d[:name => 'didi'].should == {1 => 2, 3 => 4}
|
|
2541
|
-
@
|
|
2442
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (name = 'didi') LIMIT 1"]
|
|
2542
2443
|
|
|
2543
2444
|
@d[:id => 5..45].should == {1 => 2, 3 => 4}
|
|
2544
|
-
@
|
|
2445
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((id >= 5) AND (id <= 45)) LIMIT 1"]
|
|
2545
2446
|
end
|
|
2546
2447
|
end
|
|
2547
2448
|
|
|
2548
2449
|
describe "Dataset#single_record" do
|
|
2549
2450
|
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)
|
|
2451
|
+
@db = Sequel.mock
|
|
2561
2452
|
end
|
|
2562
2453
|
|
|
2563
2454
|
specify "should call each with a limit of 1 and return the record" do
|
|
2564
|
-
@
|
|
2455
|
+
@db.fetch = {:a=>1}
|
|
2456
|
+
@db[:test].single_record.should == {:a=>1}
|
|
2457
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2565
2458
|
end
|
|
2566
2459
|
|
|
2567
2460
|
specify "should return nil if no record is present" do
|
|
2568
|
-
@
|
|
2461
|
+
@db[:test].single_record.should be_nil
|
|
2462
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2569
2463
|
end
|
|
2570
2464
|
end
|
|
2571
2465
|
|
|
2572
2466
|
describe "Dataset#single_value" do
|
|
2573
2467
|
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)
|
|
2468
|
+
@db = Sequel.mock
|
|
2585
2469
|
end
|
|
2586
2470
|
|
|
2587
2471
|
specify "should call each and return the first value of the first record" do
|
|
2588
|
-
@
|
|
2472
|
+
@db.fetch = {:a=>1}
|
|
2473
|
+
@db[:test].single_value.should == 1
|
|
2474
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2589
2475
|
end
|
|
2590
2476
|
|
|
2591
2477
|
specify "should return nil if no records" do
|
|
2592
|
-
@
|
|
2478
|
+
@db[:test].single_value.should be_nil
|
|
2479
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2593
2480
|
end
|
|
2594
2481
|
|
|
2595
2482
|
it "should work on a graphed_dataset" do
|
|
2596
|
-
@
|
|
2597
|
-
@
|
|
2483
|
+
@db.fetch = {:a=>1}
|
|
2484
|
+
ds = @db[:test].columns(:a)
|
|
2485
|
+
ds.graph(ds, [:a], :table_alias=>:test2).single_value.should == 1
|
|
2486
|
+
@db.sqls.should == ['SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
2598
2487
|
end
|
|
2599
2488
|
end
|
|
2600
2489
|
|
|
2601
2490
|
describe "Dataset#get" do
|
|
2602
2491
|
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)
|
|
2492
|
+
@d = Sequel.mock(:fetch=>proc{|s| {:name=>s}})[:test]
|
|
2613
2493
|
end
|
|
2614
2494
|
|
|
2615
2495
|
specify "should select the specified column and fetch its value" do
|
|
2616
2496
|
@d.get(:name).should == "SELECT name FROM test LIMIT 1"
|
|
2617
|
-
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2497
|
+
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2618
2498
|
end
|
|
2619
2499
|
|
|
2620
2500
|
specify "should work with filters" do
|
|
@@ -2637,239 +2517,244 @@ end
|
|
|
2637
2517
|
|
|
2638
2518
|
describe "Dataset#set_row_proc" do
|
|
2639
2519
|
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)
|
|
2520
|
+
@db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
|
|
2521
|
+
@dataset = @db[:items]
|
|
2522
|
+
@dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
|
|
2647
2523
|
end
|
|
2648
2524
|
|
|
2649
2525
|
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
2526
|
rows = @dataset.all
|
|
2653
|
-
rows.
|
|
2654
|
-
|
|
2655
|
-
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
|
2527
|
+
rows.map{|h| h[:der]}.should == [3, 4]
|
|
2528
|
+
@db.sqls.should == ['SELECT * FROM items']
|
|
2656
2529
|
end
|
|
2657
2530
|
|
|
2658
2531
|
specify "should be copied over when dataset is cloned" do
|
|
2659
|
-
@dataset.
|
|
2660
|
-
|
|
2661
|
-
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
|
2532
|
+
@dataset.filter(:a => 1).all.should == [{:a=>1, :der=>3}, {:a=>2, :der=>4}]
|
|
2662
2533
|
end
|
|
2663
2534
|
end
|
|
2664
2535
|
|
|
2665
2536
|
describe "Dataset#<<" do
|
|
2666
2537
|
before do
|
|
2667
|
-
@
|
|
2668
|
-
@d.meta_def(:insert) do |*args|
|
|
2669
|
-
1234567890
|
|
2670
|
-
end
|
|
2538
|
+
@db = Sequel.mock
|
|
2671
2539
|
end
|
|
2672
|
-
|
|
2540
|
+
|
|
2673
2541
|
specify "should call #insert" do
|
|
2674
|
-
|
|
2542
|
+
@db[:items] << {:name => 1}
|
|
2543
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)']
|
|
2544
|
+
end
|
|
2545
|
+
|
|
2546
|
+
specify "should be chainable" do
|
|
2547
|
+
@db[:items] << {:name => 1} << @db[:old_items].select(:name)
|
|
2548
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)', 'INSERT INTO items SELECT name FROM old_items']
|
|
2675
2549
|
end
|
|
2676
2550
|
end
|
|
2677
2551
|
|
|
2678
2552
|
describe "Dataset#columns" do
|
|
2679
2553
|
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}
|
|
2554
|
+
@dataset = Sequel.mock[:items]
|
|
2684
2555
|
end
|
|
2685
2556
|
|
|
2686
2557
|
specify "should return the value of @columns if @columns is not nil" do
|
|
2687
|
-
@dataset.columns
|
|
2688
|
-
@dataset.
|
|
2558
|
+
@dataset.columns(:a, :b, :c).columns.should == [:a, :b, :c]
|
|
2559
|
+
@dataset.db.sqls.should == []
|
|
2689
2560
|
end
|
|
2690
2561
|
|
|
2691
2562
|
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
|
-
|
|
2563
|
+
@dataset.db.columns = [:a]
|
|
2564
|
+
@dataset.columns.should == [:a]
|
|
2565
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2566
|
+
end
|
|
2567
|
+
|
|
2568
|
+
specify "should be cleared if you change the selected columns" do
|
|
2569
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2570
|
+
@dataset.columns.should == [:a]
|
|
2571
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2572
|
+
@dataset.columns.should == [:a]
|
|
2573
|
+
@dataset.db.sqls.should == []
|
|
2574
|
+
ds = @dataset.select{foo{}}
|
|
2575
|
+
ds.columns.should == [:b]
|
|
2576
|
+
@dataset.db.sqls.should == ['SELECT foo() FROM items LIMIT 1']
|
|
2577
|
+
end
|
|
2578
|
+
|
|
2579
|
+
specify "should be cleared if you change the FROM table" do
|
|
2580
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2581
|
+
@dataset.columns.should == [:a]
|
|
2582
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2583
|
+
ds = @dataset.from(:foo)
|
|
2584
|
+
ds.columns.should == [:b]
|
|
2585
|
+
@dataset.db.sqls.should == ['SELECT * FROM foo LIMIT 1']
|
|
2586
|
+
end
|
|
2587
|
+
|
|
2588
|
+
specify "should be cleared if you join a table to the dataset" do
|
|
2589
|
+
@dataset.db.columns = [[:a], [:a, :b]]
|
|
2590
|
+
@dataset.columns.should == [:a]
|
|
2591
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2592
|
+
ds = @dataset.cross_join(:foo)
|
|
2593
|
+
ds.columns.should == [:a, :b]
|
|
2594
|
+
@dataset.db.sqls.should == ['SELECT * FROM items CROSS JOIN foo LIMIT 1']
|
|
2595
|
+
end
|
|
2596
|
+
|
|
2597
|
+
specify "should be cleared if you set custom SQL for the dataset" do
|
|
2598
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2599
|
+
@dataset.columns.should == [:a]
|
|
2600
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2601
|
+
ds = @dataset.with_sql('SELECT b FROM foo')
|
|
2602
|
+
ds.columns.should == [:b]
|
|
2603
|
+
@dataset.db.sqls.should == ['SELECT b FROM foo']
|
|
2696
2604
|
end
|
|
2697
2605
|
|
|
2698
2606
|
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
|
2607
|
+
@dataset.db.columns = [:a]
|
|
2699
2608
|
@dataset.filter!(:b=>100).order!(:b).distinct!
|
|
2700
|
-
@dataset.columns
|
|
2701
|
-
@dataset.
|
|
2609
|
+
@dataset.columns.should == [:a]
|
|
2610
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2702
2611
|
end
|
|
2703
2612
|
end
|
|
2704
2613
|
|
|
2705
2614
|
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
2615
|
specify "should always attempt to get a record and return @columns" do
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2616
|
+
ds = Sequel.mock(:columns=>[[:a, :b, :c], [:d, :e, :f]])[:items]
|
|
2617
|
+
ds.columns!.should == [:a, :b, :c]
|
|
2618
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2619
|
+
ds.columns!.should == [:d, :e, :f]
|
|
2620
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2717
2621
|
end
|
|
2718
2622
|
end
|
|
2719
2623
|
|
|
2720
2624
|
describe "Dataset#import" do
|
|
2721
2625
|
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'}]
|
|
2626
|
+
@db = Sequel.mock
|
|
2627
|
+
@ds = @db[:items]
|
|
2743
2628
|
end
|
|
2744
2629
|
|
|
2630
|
+
specify "should return nil without a query if no values" do
|
|
2631
|
+
@ds.import(['x', 'y'], []).should == nil
|
|
2632
|
+
@db.sqls.should == []
|
|
2633
|
+
end
|
|
2634
|
+
|
|
2745
2635
|
specify "should accept string keys as column names" do
|
|
2746
2636
|
@ds.import(['x', 'y'], [[1, 2], [3, 4]])
|
|
2747
|
-
@db.sqls.should == [
|
|
2748
|
-
'BEGIN',
|
|
2637
|
+
@db.sqls.should == ['BEGIN',
|
|
2749
2638
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2750
2639
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2751
|
-
'COMMIT'
|
|
2752
|
-
]
|
|
2640
|
+
'COMMIT']
|
|
2753
2641
|
end
|
|
2754
2642
|
|
|
2755
2643
|
specify "should accept a columns array and a values array" do
|
|
2756
2644
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
2757
|
-
@db.sqls.should == [
|
|
2758
|
-
'BEGIN',
|
|
2645
|
+
@db.sqls.should == ['BEGIN',
|
|
2759
2646
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2760
2647
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2761
|
-
'COMMIT'
|
|
2762
|
-
]
|
|
2648
|
+
'COMMIT']
|
|
2763
2649
|
end
|
|
2764
2650
|
|
|
2765
2651
|
specify "should accept a columns array and a dataset" do
|
|
2766
|
-
@ds2 =
|
|
2652
|
+
@ds2 = @ds.from(:cats).filter(:purr => true).select(:a, :b)
|
|
2767
2653
|
|
|
2768
2654
|
@ds.import([:x, :y], @ds2)
|
|
2769
|
-
@db.sqls.should == [
|
|
2770
|
-
'BEGIN',
|
|
2655
|
+
@db.sqls.should == ['BEGIN',
|
|
2771
2656
|
"INSERT INTO items (x, y) SELECT a, b FROM cats WHERE (purr IS TRUE)",
|
|
2772
|
-
'COMMIT'
|
|
2773
|
-
]
|
|
2657
|
+
'COMMIT']
|
|
2774
2658
|
end
|
|
2775
2659
|
|
|
2776
2660
|
specify "should accept a columns array and a values array with :commit_every option" do
|
|
2777
2661
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 3)
|
|
2778
|
-
@db.sqls.should == [
|
|
2779
|
-
'BEGIN',
|
|
2662
|
+
@db.sqls.should == ['BEGIN',
|
|
2780
2663
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2781
2664
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2782
2665
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2783
|
-
'COMMIT'
|
|
2784
|
-
]
|
|
2666
|
+
'COMMIT']
|
|
2785
2667
|
end
|
|
2786
|
-
specify "should accept a columns array and a values array with slice option" do
|
|
2668
|
+
specify "should accept a columns array and a values array with :slice option" do
|
|
2787
2669
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
|
2788
|
-
@db.sqls.should == [
|
|
2789
|
-
'BEGIN',
|
|
2670
|
+
@db.sqls.should == ['BEGIN',
|
|
2790
2671
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2791
2672
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2792
2673
|
'COMMIT',
|
|
2793
2674
|
'BEGIN',
|
|
2794
2675
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2795
|
-
'COMMIT'
|
|
2796
|
-
]
|
|
2676
|
+
'COMMIT']
|
|
2797
2677
|
end
|
|
2798
2678
|
end
|
|
2799
2679
|
|
|
2800
2680
|
describe "Dataset#multi_insert" do
|
|
2801
2681
|
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
|
-
|
|
2682
|
+
@db = Sequel.mock(:servers=>{:s1=>{}})
|
|
2683
|
+
@ds = @db[:items]
|
|
2822
2684
|
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
|
2823
2685
|
end
|
|
2824
2686
|
|
|
2687
|
+
specify "should return nil without a query if no values" do
|
|
2688
|
+
@ds.multi_insert([]).should == nil
|
|
2689
|
+
@db.sqls.should == []
|
|
2690
|
+
end
|
|
2691
|
+
|
|
2825
2692
|
specify "should issue multiple insert statements inside a transaction" do
|
|
2826
2693
|
@ds.multi_insert(@list)
|
|
2827
|
-
@db.sqls.should == [
|
|
2828
|
-
'
|
|
2694
|
+
@db.sqls.should == ['BEGIN',
|
|
2695
|
+
"INSERT INTO items (name) VALUES ('abc')",
|
|
2696
|
+
"INSERT INTO items (name) VALUES ('def')",
|
|
2697
|
+
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2698
|
+
'COMMIT']
|
|
2699
|
+
end
|
|
2700
|
+
|
|
2701
|
+
specify "should respect :server option" do
|
|
2702
|
+
@ds.multi_insert(@list, :server=>:s1)
|
|
2703
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2704
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2705
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2706
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2707
|
+
'COMMIT -- s1']
|
|
2708
|
+
end
|
|
2709
|
+
|
|
2710
|
+
specify "should respect existing :server option on dataset" do
|
|
2711
|
+
@ds.server(:s1).multi_insert(@list)
|
|
2712
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2713
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2714
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2715
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2716
|
+
'COMMIT -- s1']
|
|
2717
|
+
end
|
|
2718
|
+
|
|
2719
|
+
specify "should respect :return=>:primary_key option" do
|
|
2720
|
+
@db.autoid = 1
|
|
2721
|
+
@ds.multi_insert(@list, :return=>:primary_key).should == [1, 2, 3]
|
|
2722
|
+
@db.sqls.should == ['BEGIN',
|
|
2829
2723
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2830
2724
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2831
2725
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2832
|
-
'COMMIT'
|
|
2833
|
-
]
|
|
2726
|
+
'COMMIT']
|
|
2834
2727
|
end
|
|
2835
2728
|
|
|
2836
2729
|
specify "should handle different formats for tables" do
|
|
2837
2730
|
@ds = @ds.from(:sch__tab)
|
|
2838
2731
|
@ds.multi_insert(@list)
|
|
2839
|
-
@db.sqls.should == [
|
|
2840
|
-
'BEGIN',
|
|
2732
|
+
@db.sqls.should == ['BEGIN',
|
|
2841
2733
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2842
2734
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2843
2735
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2844
|
-
'COMMIT'
|
|
2845
|
-
]
|
|
2846
|
-
@db.sqls.clear
|
|
2736
|
+
'COMMIT']
|
|
2847
2737
|
|
|
2848
2738
|
@ds = @ds.from(:tab.qualify(:sch))
|
|
2849
2739
|
@ds.multi_insert(@list)
|
|
2850
|
-
@db.sqls.should == [
|
|
2851
|
-
'BEGIN',
|
|
2740
|
+
@db.sqls.should == ['BEGIN',
|
|
2852
2741
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2853
2742
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2854
2743
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2855
|
-
'COMMIT'
|
|
2856
|
-
|
|
2857
|
-
@db.sqls.clear
|
|
2744
|
+
'COMMIT']
|
|
2745
|
+
|
|
2858
2746
|
@ds = @ds.from(:sch__tab.identifier)
|
|
2859
2747
|
@ds.multi_insert(@list)
|
|
2860
|
-
@db.sqls.should == [
|
|
2861
|
-
'BEGIN',
|
|
2748
|
+
@db.sqls.should == ['BEGIN',
|
|
2862
2749
|
"INSERT INTO sch__tab (name) VALUES ('abc')",
|
|
2863
2750
|
"INSERT INTO sch__tab (name) VALUES ('def')",
|
|
2864
2751
|
"INSERT INTO sch__tab (name) VALUES ('ghi')",
|
|
2865
|
-
'COMMIT'
|
|
2866
|
-
]
|
|
2752
|
+
'COMMIT']
|
|
2867
2753
|
end
|
|
2868
2754
|
|
|
2869
2755
|
specify "should accept the :commit_every option for committing every x records" do
|
|
2870
2756
|
@ds.multi_insert(@list, :commit_every => 1)
|
|
2871
|
-
@db.sqls.should == [
|
|
2872
|
-
'BEGIN',
|
|
2757
|
+
@db.sqls.should == ['BEGIN',
|
|
2873
2758
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2874
2759
|
'COMMIT',
|
|
2875
2760
|
'BEGIN',
|
|
@@ -2877,36 +2762,31 @@ describe "Dataset#multi_insert" do
|
|
|
2877
2762
|
'COMMIT',
|
|
2878
2763
|
'BEGIN',
|
|
2879
2764
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2880
|
-
'COMMIT'
|
|
2881
|
-
]
|
|
2765
|
+
'COMMIT']
|
|
2882
2766
|
end
|
|
2883
2767
|
|
|
2884
2768
|
specify "should accept the :slice option for committing every x records" do
|
|
2885
2769
|
@ds.multi_insert(@list, :slice => 2)
|
|
2886
|
-
@db.sqls.should == [
|
|
2887
|
-
'BEGIN',
|
|
2770
|
+
@db.sqls.should == ['BEGIN',
|
|
2888
2771
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2889
2772
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2890
2773
|
'COMMIT',
|
|
2891
2774
|
'BEGIN',
|
|
2892
2775
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2893
|
-
'COMMIT'
|
|
2894
|
-
]
|
|
2776
|
+
'COMMIT']
|
|
2895
2777
|
end
|
|
2896
2778
|
|
|
2897
2779
|
specify "should accept string keys as column names" do
|
|
2898
2780
|
@ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
|
|
2899
|
-
@db.sqls.should == [
|
|
2900
|
-
'BEGIN',
|
|
2781
|
+
@db.sqls.should == ['BEGIN',
|
|
2901
2782
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2902
2783
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2903
|
-
'COMMIT'
|
|
2904
|
-
]
|
|
2784
|
+
'COMMIT']
|
|
2905
2785
|
end
|
|
2906
2786
|
|
|
2907
2787
|
specify "should not do anything if no hashes are provided" do
|
|
2908
2788
|
@ds.multi_insert([])
|
|
2909
|
-
@db.sqls.should
|
|
2789
|
+
@db.sqls.should == []
|
|
2910
2790
|
end
|
|
2911
2791
|
end
|
|
2912
2792
|
|
|
@@ -2951,41 +2831,21 @@ describe "Dataset" do
|
|
|
2951
2831
|
end
|
|
2952
2832
|
|
|
2953
2833
|
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"
|
|
2834
|
+
@d.order!(:y).filter!(:y => 1).sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
|
2957
2835
|
end
|
|
2958
2836
|
end
|
|
2959
2837
|
|
|
2960
2838
|
describe "Dataset#to_csv" do
|
|
2961
2839
|
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} ]
|
|
2840
|
+
@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
2841
|
end
|
|
2980
2842
|
|
|
2981
2843
|
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"
|
|
2844
|
+
@ds.to_csv.should == "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2984
2845
|
end
|
|
2985
2846
|
|
|
2986
2847
|
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"
|
|
2848
|
+
@ds.to_csv(false).should == "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2989
2849
|
end
|
|
2990
2850
|
end
|
|
2991
2851
|
|
|
@@ -3083,66 +2943,40 @@ describe "Dataset#insert_sql" do
|
|
|
3083
2943
|
end
|
|
3084
2944
|
end
|
|
3085
2945
|
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
true
|
|
2946
|
+
describe "Dataset#inspect" do
|
|
2947
|
+
before do
|
|
2948
|
+
class ::InspectDataset < Sequel::Dataset; end
|
|
3090
2949
|
end
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
class DummyMummyDatabase < Sequel::Database
|
|
3094
|
-
attr_reader :sqls
|
|
3095
|
-
|
|
3096
|
-
def execute(sql)
|
|
3097
|
-
@sqls ||= []
|
|
3098
|
-
@sqls << sql
|
|
2950
|
+
after do
|
|
2951
|
+
Object.send(:remove_const, :InspectDataset) if defined?(::InspectDataset)
|
|
3099
2952
|
end
|
|
3100
|
-
|
|
3101
|
-
def transaction; yield; end
|
|
3102
2953
|
|
|
3103
|
-
|
|
3104
|
-
|
|
2954
|
+
specify "should include the class name and the corresponding SQL statement" do
|
|
2955
|
+
Sequel::Dataset.new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
2956
|
+
InspectDataset.new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3105
2957
|
end
|
|
3106
|
-
end
|
|
3107
2958
|
|
|
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]
|
|
2959
|
+
specify "should skip anonymous classes" do
|
|
2960
|
+
Class.new(Class.new(Sequel::Dataset)).new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
2961
|
+
Class.new(InspectDataset).new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3115
2962
|
end
|
|
3116
2963
|
end
|
|
3117
2964
|
|
|
3118
2965
|
describe "Dataset#all" do
|
|
3119
2966
|
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)
|
|
2967
|
+
@dataset = Sequel.mock(:fetch=>[{:x => 1, :y => 2}, {:x => 3, :y => 4}])[:items]
|
|
3128
2968
|
end
|
|
3129
2969
|
|
|
3130
2970
|
specify "should return an array with all records" do
|
|
3131
|
-
@dataset.all.should == [
|
|
3132
|
-
|
|
3133
|
-
{:x => 3, :y => 4},
|
|
3134
|
-
"SELECT * FROM items"
|
|
3135
|
-
]
|
|
2971
|
+
@dataset.all.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
2972
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3136
2973
|
end
|
|
3137
2974
|
|
|
3138
2975
|
specify "should iterate over the array if a block is given" do
|
|
3139
2976
|
a = []
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
end
|
|
3144
|
-
|
|
3145
|
-
a.should == [1, 3, "SELECT * FROM items"]
|
|
2977
|
+
@dataset.all{|r| a << r.values_at(:x, :y)}.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
2978
|
+
a.should == [[1, 2], [3, 4]]
|
|
2979
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3146
2980
|
end
|
|
3147
2981
|
end
|
|
3148
2982
|
|
|
@@ -3152,71 +2986,56 @@ describe "Dataset#grep" do
|
|
|
3152
2986
|
end
|
|
3153
2987
|
|
|
3154
2988
|
specify "should format a SQL filter correctly" do
|
|
3155
|
-
@ds.grep(:title, 'ruby').sql.should ==
|
|
3156
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
2989
|
+
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3157
2990
|
end
|
|
3158
2991
|
|
|
3159
2992
|
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'))"
|
|
2993
|
+
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
|
3162
2994
|
end
|
|
3163
2995
|
|
|
3164
2996
|
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'))"
|
|
2997
|
+
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
|
3167
2998
|
end
|
|
3168
2999
|
|
|
3169
3000
|
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'))"
|
|
3001
|
+
@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
3002
|
end
|
|
3173
3003
|
|
|
3174
3004
|
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')))"
|
|
3005
|
+
@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
3006
|
end
|
|
3178
3007
|
|
|
3179
3008
|
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')))"
|
|
3009
|
+
@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
3010
|
end
|
|
3183
3011
|
|
|
3184
3012
|
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'))"
|
|
3013
|
+
@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
3014
|
end
|
|
3188
3015
|
|
|
3189
3016
|
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'))"
|
|
3017
|
+
@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
3018
|
end
|
|
3193
3019
|
|
|
3194
3020
|
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')))"
|
|
3021
|
+
@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
3022
|
end
|
|
3198
3023
|
|
|
3199
3024
|
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')))"
|
|
3025
|
+
@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
3026
|
end
|
|
3203
3027
|
|
|
3204
3028
|
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'))"
|
|
3029
|
+
@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
3030
|
end
|
|
3208
3031
|
|
|
3209
3032
|
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'))"
|
|
3033
|
+
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
|
3034
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
|
3215
3035
|
end
|
|
3216
3036
|
|
|
3217
3037
|
specify "should support searching against other columns" do
|
|
3218
|
-
@ds.grep(:title, :body).sql.should ==
|
|
3219
|
-
"SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3038
|
+
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3220
3039
|
end
|
|
3221
3040
|
end
|
|
3222
3041
|
|
|
@@ -3270,19 +3089,9 @@ end
|
|
|
3270
3089
|
|
|
3271
3090
|
describe "Dataset prepared statements and bound variables " do
|
|
3272
3091
|
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
|
|
3092
|
+
@db = Sequel.mock
|
|
3285
3093
|
@ds = @db[:items]
|
|
3094
|
+
@ds.meta_def(:insert_sql){|*v| "#{super(*v)}#{' RETURNING *' if opts.has_key?(:returning)}" }
|
|
3286
3095
|
end
|
|
3287
3096
|
|
|
3288
3097
|
specify "#call should take a type and bind hash and interpolate it" do
|
|
@@ -3291,11 +3100,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3291
3100
|
@ds.filter(:num=>:$n).call(:delete, :n=>1)
|
|
3292
3101
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
|
3293
3102
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
|
3103
|
+
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
|
3294
3104
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3295
3105
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3296
3106
|
'DELETE FROM items WHERE (num = 1)',
|
|
3297
3107
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3298
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3108
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3109
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3299
3110
|
end
|
|
3300
3111
|
|
|
3301
3112
|
specify "#prepare should take a type and name and store it in the database for later use with call" do
|
|
@@ -3305,23 +3116,26 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3305
3116
|
pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
|
|
3306
3117
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
|
3307
3118
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
|
3308
|
-
@
|
|
3309
|
-
[:
|
|
3119
|
+
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
|
3120
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sn, :un]
|
|
3121
|
+
[:sn, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3310
3122
|
@db.call(:sn, :n=>1)
|
|
3311
3123
|
@db.call(:fn, :n=>1)
|
|
3312
3124
|
@db.call(:dn, :n=>1)
|
|
3313
3125
|
@db.call(:un, :n=>1, :n2=>2)
|
|
3314
3126
|
@db.call(:in, :n=>1)
|
|
3127
|
+
@db.call(:ins, :n=>1)
|
|
3315
3128
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3316
3129
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3317
3130
|
'DELETE FROM items WHERE (num = 1)',
|
|
3318
3131
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3319
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3132
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3133
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3320
3134
|
end
|
|
3321
3135
|
|
|
3322
3136
|
specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
|
|
3323
3137
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
|
3324
|
-
'<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3138
|
+
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3325
3139
|
end
|
|
3326
3140
|
|
|
3327
3141
|
specify "should handle literal strings" do
|
|
@@ -3329,6 +3143,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3329
3143
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3330
3144
|
end
|
|
3331
3145
|
|
|
3146
|
+
specify "should handle columns on prepared statements correctly" do
|
|
3147
|
+
@db.columns = [:num]
|
|
3148
|
+
@ds.meta_def(:select_where_sql){|sql| super(sql); sql << " OR #{columns.first} = 1" if opts[:where]}
|
|
3149
|
+
@ds.filter(:num=>:$n).prepare(:select, :sn).sql.should == 'SELECT * FROM items WHERE (num = $n) OR num = 1'
|
|
3150
|
+
@db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
3151
|
+
end
|
|
3152
|
+
|
|
3332
3153
|
specify "should handle datasets using static sql and placeholders" do
|
|
3333
3154
|
@db["SELECT * FROM items WHERE (num = ?)", :$n].call(:select, :n=>1)
|
|
3334
3155
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
@@ -3357,23 +3178,16 @@ end
|
|
|
3357
3178
|
|
|
3358
3179
|
describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3359
3180
|
before do
|
|
3360
|
-
@db = Sequel
|
|
3361
|
-
@db.meta_def(:sqls){@sqls||=[]}
|
|
3362
|
-
def @db.execute(sql, opts={})
|
|
3363
|
-
sqls << [sql, *opts[:arguments]]
|
|
3364
|
-
end
|
|
3181
|
+
@db = Sequel.mock
|
|
3365
3182
|
@ds = @db[:items].filter(:num=>:$n)
|
|
3366
|
-
def @ds.fetch_rows(sql, &block)
|
|
3367
|
-
execute(sql)
|
|
3368
|
-
end
|
|
3369
3183
|
def @ds.execute(sql, opts={}, &block)
|
|
3370
|
-
|
|
3184
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3371
3185
|
end
|
|
3372
|
-
def @ds.execute_dui(
|
|
3373
|
-
|
|
3186
|
+
def @ds.execute_dui(sql, opts={}, &block)
|
|
3187
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3374
3188
|
end
|
|
3375
|
-
def @ds.execute_insert(
|
|
3376
|
-
|
|
3189
|
+
def @ds.execute_insert(sql, opts={}, &block)
|
|
3190
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3377
3191
|
end
|
|
3378
3192
|
@ps = []
|
|
3379
3193
|
@ps << @ds.prepare(:select, :s)
|
|
@@ -3386,64 +3200,43 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
|
3386
3200
|
end
|
|
3387
3201
|
|
|
3388
3202
|
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 = ?)">'
|
|
3203
|
+
@ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
|
3390
3204
|
end
|
|
3391
3205
|
|
|
3392
3206
|
specify "should submitted the SQL to the database with placeholders and bind variables" do
|
|
3393
3207
|
@ps.each{|p| p.prepared_sql; p.call(:n=>1)}
|
|
3394
|
-
@db.sqls.should == [
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
]
|
|
3208
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3209
|
+
"SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3210
|
+
"SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
|
|
3211
|
+
"DELETE FROM items WHERE (num = ?) -- args: [1]",
|
|
3212
|
+
"INSERT INTO items (num) VALUES (?) -- args: [1]",
|
|
3213
|
+
"UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
|
|
3401
3214
|
end
|
|
3402
3215
|
end
|
|
3403
3216
|
|
|
3404
3217
|
describe "Sequel::Dataset#server" do
|
|
3405
3218
|
specify "should set the server to use for the dataset" do
|
|
3406
|
-
@db = Sequel
|
|
3219
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}, :d=>{}, :u=>{}})
|
|
3407
3220
|
@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
3221
|
@ds.all
|
|
3416
3222
|
@ds.server(:i).insert(:a=>1)
|
|
3417
3223
|
@ds.server(:d).delete
|
|
3418
3224
|
@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]]
|
|
3225
|
+
@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
3226
|
end
|
|
3424
3227
|
end
|
|
3425
3228
|
|
|
3426
3229
|
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
3230
|
specify "should yield a dataset for each server" do
|
|
3231
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}})
|
|
3232
|
+
@ds = @db[:items]
|
|
3440
3233
|
@ds.each_server do |ds|
|
|
3441
3234
|
ds.should be_a_kind_of(Sequel::Dataset)
|
|
3442
3235
|
ds.should_not == @ds
|
|
3443
3236
|
ds.sql.should == @ds.sql
|
|
3444
3237
|
ds.all
|
|
3445
3238
|
end
|
|
3446
|
-
@sqls.
|
|
3239
|
+
@db.sqls.sort.should == ['SELECT * FROM items', 'SELECT * FROM items -- i', 'SELECT * FROM items -- s']
|
|
3447
3240
|
end
|
|
3448
3241
|
end
|
|
3449
3242
|
|
|
@@ -3493,23 +3286,23 @@ end
|
|
|
3493
3286
|
|
|
3494
3287
|
describe "Sequel::Dataset#qualify" do
|
|
3495
3288
|
specify "should qualify to the given table" do
|
|
3496
|
-
|
|
3289
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3497
3290
|
end
|
|
3498
3291
|
|
|
3499
3292
|
specify "should qualify to the first source if no table if given" do
|
|
3500
|
-
|
|
3293
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
|
|
3501
3294
|
end
|
|
3502
3295
|
end
|
|
3503
3296
|
|
|
3504
3297
|
describe "Sequel::Dataset#qualify_to" do
|
|
3505
3298
|
specify "should qualify to the given table" do
|
|
3506
|
-
|
|
3299
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3507
3300
|
end
|
|
3508
3301
|
end
|
|
3509
3302
|
|
|
3510
3303
|
describe "Sequel::Dataset#qualify_to_first_source" do
|
|
3511
3304
|
before do
|
|
3512
|
-
@ds =
|
|
3305
|
+
@ds = Sequel::Database.new[:t]
|
|
3513
3306
|
end
|
|
3514
3307
|
|
|
3515
3308
|
specify "should qualify_to the first source" do
|
|
@@ -3519,13 +3312,11 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3519
3312
|
end
|
|
3520
3313
|
|
|
3521
3314
|
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'
|
|
3315
|
+
@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
3316
|
end
|
|
3525
3317
|
|
|
3526
3318
|
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'
|
|
3319
|
+
@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
3320
|
end
|
|
3530
3321
|
|
|
3531
3322
|
specify "should handle hashes in select option" do
|
|
@@ -3594,14 +3385,83 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3594
3385
|
end
|
|
3595
3386
|
|
|
3596
3387
|
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
|
-
|
|
3388
|
+
@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"
|
|
3389
|
+
end
|
|
3390
|
+
end
|
|
3391
|
+
|
|
3392
|
+
describe "Sequel::Dataset#unbind" do
|
|
3393
|
+
before do
|
|
3394
|
+
@ds = Sequel::Database.new[:t]
|
|
3395
|
+
@u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
|
|
3396
|
+
end
|
|
3397
|
+
|
|
3398
|
+
specify "should unbind values assigned to equality and inequality statements" do
|
|
3399
|
+
@ds.filter(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo = $foo)"
|
|
3400
|
+
@ds.exclude(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo != $foo)"
|
|
3401
|
+
@ds.filter{foo > 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo > $foo)"
|
|
3402
|
+
@ds.filter{foo >= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo >= $foo)"
|
|
3403
|
+
@ds.filter{foo < 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo < $foo)"
|
|
3404
|
+
@ds.filter{foo <= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo <= $foo)"
|
|
3405
|
+
end
|
|
3406
|
+
|
|
3407
|
+
specify "should return variables that could be used bound to recreate the previous query" do
|
|
3408
|
+
@ds.filter(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3409
|
+
@ds.exclude(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3410
|
+
end
|
|
3411
|
+
|
|
3412
|
+
specify "should handle numerics, strings, dates, times, and datetimes" do
|
|
3413
|
+
@u[@ds.filter(:foo=>1)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1}]
|
|
3414
|
+
@u[@ds.filter(:foo=>1.0)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1.0}]
|
|
3415
|
+
@u[@ds.filter(:foo=>BigDecimal.new('1.0'))].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>BigDecimal.new('1.0')}]
|
|
3416
|
+
@u[@ds.filter(:foo=>'a')].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>'a'}]
|
|
3417
|
+
@u[@ds.filter(:foo=>Date.today)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>Date.today}]
|
|
3418
|
+
t = Time.now
|
|
3419
|
+
@u[@ds.filter(:foo=>t)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>t}]
|
|
3420
|
+
dt = DateTime.now
|
|
3421
|
+
@u[@ds.filter(:foo=>dt)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>dt}]
|
|
3422
|
+
end
|
|
3423
|
+
|
|
3424
|
+
specify "should not unbind literal strings" do
|
|
3425
|
+
@u[@ds.filter(:foo=>'a'.lit)].should == ["SELECT * FROM t WHERE (foo = a)", {}]
|
|
3426
|
+
end
|
|
3427
|
+
|
|
3428
|
+
specify "should not unbind Identifiers, QualifiedIdentifiers, or Symbols used as booleans" do
|
|
3429
|
+
@u[@ds.filter(:foo).filter{bar}.filter{foo__bar}].should == ["SELECT * FROM t WHERE (foo AND bar AND foo.bar)", {}]
|
|
3430
|
+
end
|
|
3431
|
+
|
|
3432
|
+
specify "should not unbind for values it doesn't understand" do
|
|
3433
|
+
@u[@ds.filter(:foo=>Class.new{def sql_literal(ds) 'bar' end}.new)].should == ["SELECT * FROM t WHERE (foo = bar)", {}]
|
|
3434
|
+
end
|
|
3435
|
+
|
|
3436
|
+
specify "should handle QualifiedIdentifiers" do
|
|
3437
|
+
@u[@ds.filter{foo__bar > 1}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3438
|
+
end
|
|
3439
|
+
|
|
3440
|
+
specify "should handle deep nesting" do
|
|
3441
|
+
@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}]
|
|
3442
|
+
end
|
|
3443
|
+
|
|
3444
|
+
specify "should handle JOIN ON" do
|
|
3445
|
+
@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}]
|
|
3446
|
+
end
|
|
3447
|
+
|
|
3448
|
+
specify "should raise an UnbindDuplicate exception if same variable is used with multiple different values" do
|
|
3449
|
+
proc{@ds.filter(:foo=>1).or(:foo=>2).unbind}.should raise_error(Sequel::UnbindDuplicate)
|
|
3450
|
+
end
|
|
3451
|
+
|
|
3452
|
+
specify "should handle case where the same variable has the same value in multiple places " do
|
|
3453
|
+
@u[@ds.filter(:foo=>1).or(:foo=>1)].should == ["SELECT * FROM t WHERE ((foo = $foo) OR (foo = $foo))", {:foo=>1}]
|
|
3454
|
+
end
|
|
3455
|
+
|
|
3456
|
+
specify "should raise Error for unhandled objects inside Identifiers and QualifiedIndentifiers" do
|
|
3457
|
+
proc{@ds.filter(Sequel::SQL::Identifier.new([]) > 1).unbind}.should raise_error(Sequel::Error)
|
|
3458
|
+
proc{@ds.filter{foo.qualify({}) > 1}.unbind}.should raise_error(Sequel::Error)
|
|
3599
3459
|
end
|
|
3600
3460
|
end
|
|
3601
3461
|
|
|
3602
3462
|
describe "Sequel::Dataset #with and #with_recursive" do
|
|
3603
3463
|
before do
|
|
3604
|
-
@db =
|
|
3464
|
+
@db = Sequel::Database.new
|
|
3605
3465
|
@ds = @db[:t]
|
|
3606
3466
|
end
|
|
3607
3467
|
|
|
@@ -3633,11 +3493,27 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
|
3633
3493
|
proc{@ds.with(:t, @db[:x], :args=>[:b])}.should raise_error(Sequel::Error)
|
|
3634
3494
|
proc{@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c])}.should raise_error(Sequel::Error)
|
|
3635
3495
|
end
|
|
3496
|
+
|
|
3497
|
+
specify "#with should work on insert, update, and delete statements if they support it" do
|
|
3498
|
+
[:insert, :update, :delete].each do |m|
|
|
3499
|
+
@ds.meta_def(:"#{m}_clause_methods"){[:"#{m}_with_sql"] + super()}
|
|
3500
|
+
end
|
|
3501
|
+
@ds.with(:t, @db[:x]).insert_sql(1).should == 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
|
|
3502
|
+
@ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
|
|
3503
|
+
@ds.with(:t, @db[:x]).delete_sql.should == 'WITH t AS (SELECT * FROM x) DELETE FROM t'
|
|
3504
|
+
end
|
|
3505
|
+
|
|
3506
|
+
specify "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
|
|
3507
|
+
@ds.meta_def(:supports_cte?){true}
|
|
3508
|
+
@ds.meta_def(:supports_cte_in_subselect?){false}
|
|
3509
|
+
@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'
|
|
3510
|
+
@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'
|
|
3511
|
+
end
|
|
3636
3512
|
end
|
|
3637
3513
|
|
|
3638
3514
|
describe Sequel::SQL::Constants do
|
|
3639
3515
|
before do
|
|
3640
|
-
@db =
|
|
3516
|
+
@db = Sequel::Database.new
|
|
3641
3517
|
end
|
|
3642
3518
|
|
|
3643
3519
|
it "should have CURRENT_DATE" do
|
|
@@ -3682,7 +3558,7 @@ end
|
|
|
3682
3558
|
|
|
3683
3559
|
describe "Sequel timezone support" do
|
|
3684
3560
|
before do
|
|
3685
|
-
@db =
|
|
3561
|
+
@db = Sequel::Database.new
|
|
3686
3562
|
@dataset = @db.dataset
|
|
3687
3563
|
@dataset.meta_def(:supports_timestamp_timezones?){true}
|
|
3688
3564
|
@dataset.meta_def(:supports_timestamp_usecs?){false}
|
|
@@ -3717,6 +3593,30 @@ describe "Sequel timezone support" do
|
|
|
3717
3593
|
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3718
3594
|
end
|
|
3719
3595
|
|
|
3596
|
+
specify "should have Database#timezone override Sequel.database_timezone" do
|
|
3597
|
+
Sequel.database_timezone = :local
|
|
3598
|
+
@db.timezone = :utc
|
|
3599
|
+
|
|
3600
|
+
t = Time.now
|
|
3601
|
+
s = t.getutc.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3602
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3603
|
+
|
|
3604
|
+
t = DateTime.now
|
|
3605
|
+
s = t.new_offset(0).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3606
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3607
|
+
|
|
3608
|
+
Sequel.database_timezone = :utc
|
|
3609
|
+
@db.timezone = :local
|
|
3610
|
+
|
|
3611
|
+
t = Time.now.utc
|
|
3612
|
+
s = t.getlocal.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3613
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3614
|
+
|
|
3615
|
+
t = DateTime.now.new_offset(0)
|
|
3616
|
+
s = t.new_offset(DateTime.now.offset).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3617
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3618
|
+
end
|
|
3619
|
+
|
|
3720
3620
|
specify "should handle converting database timestamps into application timestamps" do
|
|
3721
3621
|
Sequel.database_timezone = :utc
|
|
3722
3622
|
Sequel.application_timezone = :local
|
|
@@ -3827,13 +3727,7 @@ end
|
|
|
3827
3727
|
|
|
3828
3728
|
describe "Sequel::Dataset#select_map" do
|
|
3829
3729
|
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
|
|
3730
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3837
3731
|
end
|
|
3838
3732
|
|
|
3839
3733
|
specify "should do select and map in one step" do
|
|
@@ -3860,17 +3754,23 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3860
3754
|
@ds.select_map{a(t__c)}.should == [1, 2]
|
|
3861
3755
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t']
|
|
3862
3756
|
end
|
|
3757
|
+
|
|
3758
|
+
specify "should handle an array of columns" do
|
|
3759
|
+
@ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3760
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3761
|
+
@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]]
|
|
3762
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
|
|
3763
|
+
end
|
|
3764
|
+
|
|
3765
|
+
specify "should handle an array with a single element" do
|
|
3766
|
+
@ds.select_map([:c]).should == [[1], [2]]
|
|
3767
|
+
@ds.db.sqls.should == ['SELECT c FROM t']
|
|
3768
|
+
end
|
|
3863
3769
|
end
|
|
3864
3770
|
|
|
3865
3771
|
describe "Sequel::Dataset#select_order_map" do
|
|
3866
3772
|
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
|
|
3773
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3874
3774
|
end
|
|
3875
3775
|
|
|
3876
3776
|
specify "should do select and map in one step" do
|
|
@@ -3898,55 +3798,89 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3898
3798
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
3899
3799
|
end
|
|
3900
3800
|
|
|
3801
|
+
specify "should handle OrderedExpressions" do
|
|
3802
|
+
@ds.select_order_map(:a.desc).should == [1, 2]
|
|
3803
|
+
@ds.db.sqls.should == ['SELECT a FROM t ORDER BY a DESC']
|
|
3804
|
+
end
|
|
3805
|
+
|
|
3901
3806
|
specify "should accept a block" do
|
|
3902
3807
|
@ds.select_order_map{a(t__c)}.should == [1, 2]
|
|
3903
3808
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t ORDER BY a(t.c)']
|
|
3904
3809
|
end
|
|
3810
|
+
|
|
3811
|
+
specify "should handle an array of columns" do
|
|
3812
|
+
@ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3813
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
|
|
3814
|
+
@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]]
|
|
3815
|
+
@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']
|
|
3816
|
+
end
|
|
3817
|
+
|
|
3818
|
+
specify "should handle an array with a single element" do
|
|
3819
|
+
@ds.select_order_map([:c]).should == [[1], [2]]
|
|
3820
|
+
@ds.db.sqls.should == ['SELECT c FROM t ORDER BY c']
|
|
3821
|
+
end
|
|
3905
3822
|
end
|
|
3906
3823
|
|
|
3907
3824
|
describe "Sequel::Dataset#select_hash" do
|
|
3908
3825
|
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
|
|
3826
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3827
|
+
@ds = @db[:t]
|
|
3918
3828
|
end
|
|
3919
3829
|
|
|
3920
|
-
specify "should do select and
|
|
3921
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3830
|
+
specify "should do select and to_hash in one step" do
|
|
3922
3831
|
@ds.select_hash(:a, :b).should == {1=>2, 3=>4}
|
|
3923
3832
|
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3924
3833
|
end
|
|
3925
3834
|
|
|
3926
3835
|
specify "should handle implicit qualifiers in arguments" do
|
|
3927
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3928
3836
|
@ds.select_hash(:t__a, :t__b).should == {1=>2, 3=>4}
|
|
3929
3837
|
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3930
3838
|
end
|
|
3931
3839
|
|
|
3932
3840
|
specify "should handle implicit aliases in arguments" do
|
|
3933
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3934
3841
|
@ds.select_hash(:c___a, :d___b).should == {1=>2, 3=>4}
|
|
3935
3842
|
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
3936
3843
|
end
|
|
3937
3844
|
|
|
3938
3845
|
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
3939
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3940
3846
|
@ds.select_hash(:t__c___a, :t__d___b).should == {1=>2, 3=>4}
|
|
3941
3847
|
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
3942
3848
|
end
|
|
3849
|
+
|
|
3850
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
3851
|
+
@ds.select_hash(:a.identifier, :b.identifier).should == {1=>2, 3=>4}
|
|
3852
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3853
|
+
end
|
|
3854
|
+
|
|
3855
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
3856
|
+
@ds.select_hash(:a.qualify(:t), :b.identifier.qualify(:t)).should == {1=>2, 3=>4}
|
|
3857
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3858
|
+
end
|
|
3859
|
+
|
|
3860
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
3861
|
+
@ds.select_hash(:c.as(:a), :t.as(:b)).should == {1=>2, 3=>4}
|
|
3862
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
3863
|
+
end
|
|
3864
|
+
|
|
3865
|
+
specify "should work with arrays of columns" do
|
|
3866
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
3867
|
+
@ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [4, 6]=>5}
|
|
3868
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
3869
|
+
@ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 4=>[5, 6]}
|
|
3870
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
3871
|
+
@ds.select_hash([:a, :b], [:b, :c]).should == {[1, 2]=>[2, 3], [4, 5]=>[5, 6]}
|
|
3872
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
3873
|
+
end
|
|
3874
|
+
|
|
3875
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
3876
|
+
proc{@ds.select_hash(:c.as(:a), 'foo')}.should raise_error(Sequel::Error)
|
|
3877
|
+
end
|
|
3943
3878
|
end
|
|
3944
3879
|
|
|
3945
3880
|
describe "Modifying joined datasets" do
|
|
3946
3881
|
before do
|
|
3947
|
-
@ds =
|
|
3882
|
+
@ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
|
|
3948
3883
|
@ds.meta_def(:supports_modifying_joins?){true}
|
|
3949
|
-
@ds.db.reset
|
|
3950
3884
|
end
|
|
3951
3885
|
|
|
3952
3886
|
specify "should allow deleting from joined datasets" do
|
|
@@ -3962,7 +3896,7 @@ end
|
|
|
3962
3896
|
|
|
3963
3897
|
describe "Dataset#lock_style and for_update" do
|
|
3964
3898
|
before do
|
|
3965
|
-
@ds =
|
|
3899
|
+
@ds = Sequel::Dataset.new(nil).from(:t)
|
|
3966
3900
|
end
|
|
3967
3901
|
|
|
3968
3902
|
specify "#for_update should use FOR UPDATE" do
|
|
@@ -3977,3 +3911,89 @@ describe "Dataset#lock_style and for_update" do
|
|
|
3977
3911
|
@ds.lock_style("FOR SHARE").sql.should == "SELECT * FROM t FOR SHARE"
|
|
3978
3912
|
end
|
|
3979
3913
|
end
|
|
3914
|
+
|
|
3915
|
+
describe "Custom ASTTransformer" do
|
|
3916
|
+
specify "should transform given objects" do
|
|
3917
|
+
c = Class.new(Sequel::ASTTransformer) do
|
|
3918
|
+
def v(s)
|
|
3919
|
+
(s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
|
|
3920
|
+
end
|
|
3921
|
+
end.new
|
|
3922
|
+
ds = Sequel::Dataset.new(nil).from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
|
3923
|
+
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)'
|
|
3924
|
+
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)'
|
|
3925
|
+
end
|
|
3926
|
+
end
|
|
3927
|
+
|
|
3928
|
+
describe "Dataset#returning" do
|
|
3929
|
+
before do
|
|
3930
|
+
@ds = Sequel.mock(:fetch=>proc{|s| {:foo=>s}})[:t].returning(:foo)
|
|
3931
|
+
@pr = proc do
|
|
3932
|
+
[:insert, :update, :delete].each do |m|
|
|
3933
|
+
@ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_returning_sql"]}
|
|
3934
|
+
end
|
|
3935
|
+
end
|
|
3936
|
+
end
|
|
3937
|
+
|
|
3938
|
+
specify "should use RETURNING clause in the SQL if the dataset supports it" do
|
|
3939
|
+
@pr.call
|
|
3940
|
+
@ds.delete_sql.should == "DELETE FROM t RETURNING foo"
|
|
3941
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1) RETURNING foo"
|
|
3942
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1 RETURNING foo"
|
|
3943
|
+
end
|
|
3944
|
+
|
|
3945
|
+
specify "should not use RETURNING clause in the SQL if the dataset does not support it" do
|
|
3946
|
+
@ds.delete_sql.should == "DELETE FROM t"
|
|
3947
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1)"
|
|
3948
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1"
|
|
3949
|
+
end
|
|
3950
|
+
|
|
3951
|
+
specify "should have insert, update, and delete yield to blocks if RETURNING is used" do
|
|
3952
|
+
@pr.call
|
|
3953
|
+
h = {}
|
|
3954
|
+
@ds.delete{|r| h = r}
|
|
3955
|
+
h.should == {:foo=>"DELETE FROM t RETURNING foo"}
|
|
3956
|
+
@ds.insert(1){|r| h = r}
|
|
3957
|
+
h.should == {:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}
|
|
3958
|
+
@ds.update(:foo=>1){|r| h = r}
|
|
3959
|
+
h.should == {:foo=>"UPDATE t SET foo = 1 RETURNING foo"}
|
|
3960
|
+
end
|
|
3961
|
+
|
|
3962
|
+
specify "should have insert, update, and delete return arrays of hashes if RETURNING is used and a block is not given" do
|
|
3963
|
+
@pr.call
|
|
3964
|
+
h = {}
|
|
3965
|
+
@ds.delete.should == [{:foo=>"DELETE FROM t RETURNING foo"}]
|
|
3966
|
+
@ds.insert(1).should == [{:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}]
|
|
3967
|
+
@ds.update(:foo=>1).should == [{:foo=>"UPDATE t SET foo = 1 RETURNING foo"}]
|
|
3968
|
+
end
|
|
3969
|
+
end
|
|
3970
|
+
|
|
3971
|
+
describe "Dataset emulating bitwise operator support" do
|
|
3972
|
+
before do
|
|
3973
|
+
@ds = Sequel::Database.new.dataset
|
|
3974
|
+
@ds.quote_identifiers = true
|
|
3975
|
+
def @ds.complex_expression_sql_append(sql, op, args)
|
|
3976
|
+
sql << complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
|
3977
|
+
end
|
|
3978
|
+
end
|
|
3979
|
+
|
|
3980
|
+
it "should work with any numbers of arguments for operators" do
|
|
3981
|
+
@ds.select(Sequel::SQL::ComplexExpression.new(:&, :x)).sql.should == 'SELECT "x"'
|
|
3982
|
+
@ds.select(:x & 1).sql.should == 'SELECT bitand("x", 1)'
|
|
3983
|
+
@ds.select(:x & 1 & 2).sql.should == 'SELECT bitand(bitand("x", 1), 2)'
|
|
3984
|
+
end
|
|
3985
|
+
end
|
|
3986
|
+
|
|
3987
|
+
describe "Dataset feature defaults" do
|
|
3988
|
+
it "should not require aliases for recursive CTEs by default" do
|
|
3989
|
+
Sequel::Database.new.dataset.recursive_cte_requires_column_aliases?.should be_false
|
|
3990
|
+
end
|
|
3991
|
+
|
|
3992
|
+
it "should not require placeholder type specifiers by default" do
|
|
3993
|
+
Sequel::Database.new.dataset.requires_placeholder_type_specifiers?.should be_false
|
|
3994
|
+
end
|
|
3995
|
+
|
|
3996
|
+
it "offset use should be returning a separate row number column by default" do
|
|
3997
|
+
Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
|
|
3998
|
+
end
|
|
3999
|
+
end
|