sequel 3.21.0 → 3.32.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 +539 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/advanced_associations.rdoc +17 -0
- data/doc/association_basics.rdoc +293 -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/release_notes/3.32.0.txt +202 -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 +52 -0
- data/lib/sequel/adapters/jdbc/derby.rb +260 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +66 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -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 +88 -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 +339 -0
- data/lib/sequel/adapters/mysql.rb +85 -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 +355 -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 +328 -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 +278 -107
- data/lib/sequel/adapters/shared/mysql.rb +203 -65
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +237 -46
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +200 -50
- 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 +68 -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 +163 -59
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +240 -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 +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +59 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +676 -267
- 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/query.rb +1 -1
- 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 +1081 -344
- data/lib/sequel/model/base.rb +420 -133
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +20 -10
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +43 -10
- 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 +68 -7
- data/lib/sequel/plugins/nested_attributes.rb +65 -10
- 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 +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +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 +135 -30
- data/spec/adapters/mysql_spec.rb +244 -212
- data/spec/adapters/oracle_spec.rb +67 -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 +789 -512
- data/spec/core/dataset_spec.rb +1176 -1061
- 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/active_model_spec.rb +13 -0
- 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/query_spec.rb +6 -0
- 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 +72 -0
- data/spec/extensions/serialization_spec.rb +81 -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 +661 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +500 -67
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +367 -119
- data/spec/integration/prepared_statement_test.rb +222 -125
- data/spec/integration/schema_test.rb +217 -39
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +182 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +955 -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 +349 -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 +117 -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
|
|
@@ -510,62 +495,89 @@ describe "Dataset#where" do
|
|
|
510
495
|
"SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
|
511
496
|
end
|
|
512
497
|
|
|
498
|
+
specify "should handle all types of IN/NOT IN queries with empty arrays" do
|
|
499
|
+
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (id != id)"
|
|
500
|
+
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
501
|
+
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (id = id)"
|
|
502
|
+
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
specify "should handle all types of IN/NOT IN queries with empty arrays" do
|
|
506
|
+
begin
|
|
507
|
+
Sequel.empty_array_handle_nulls = false
|
|
508
|
+
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
509
|
+
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
510
|
+
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
511
|
+
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
512
|
+
ensure
|
|
513
|
+
Sequel.empty_array_handle_nulls = true
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
|
|
513
517
|
specify "should handle all types of IN/NOT IN queries" do
|
|
514
518
|
@dataset.filter(:id => @d1.select(:id)).sql.should == "SELECT * FROM test WHERE (id IN (SELECT id FROM test WHERE (region = 'Asia')))"
|
|
515
|
-
@dataset.filter(:id => []).sql.should == "SELECT * FROM test WHERE (id != id)"
|
|
516
519
|
@dataset.filter(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id IN (1, 2))"
|
|
517
520
|
@dataset.filter([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
|
|
518
|
-
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
519
521
|
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
|
|
520
522
|
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
|
|
521
523
|
|
|
522
524
|
@dataset.exclude(:id => @d1.select(:id)).sql.should == "SELECT * FROM test WHERE (id NOT IN (SELECT id FROM test WHERE (region = 'Asia')))"
|
|
523
|
-
@dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
524
525
|
@dataset.exclude(:id => [1, 2]).sql.should == "SELECT * FROM test WHERE (id NOT IN (1, 2))"
|
|
525
526
|
@dataset.exclude([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
|
|
526
|
-
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
527
527
|
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
|
|
528
528
|
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
|
|
529
529
|
end
|
|
530
530
|
|
|
531
531
|
specify "should handle IN/NOT IN queries with multiple columns and an array where the database doesn't support it" do
|
|
532
532
|
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
533
|
-
@dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
534
533
|
@dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
535
|
-
@dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
536
534
|
@dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
537
535
|
end
|
|
538
536
|
|
|
539
537
|
specify "should handle IN/NOT IN queries with multiple columns and a dataset where the database doesn't support it" do
|
|
540
538
|
@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
|
|
539
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
540
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
549
541
|
@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)
|
|
542
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
552
543
|
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
553
|
-
|
|
544
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
554
545
|
end
|
|
555
546
|
|
|
556
547
|
specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it" do
|
|
557
548
|
@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
|
|
549
|
+
db = Sequel.mock
|
|
550
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
564
551
|
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
552
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
553
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 = id1) AND (id2 = id2))"
|
|
554
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it with correct NULL handling" do
|
|
558
|
+
begin
|
|
559
|
+
Sequel.empty_array_handle_nulls = false
|
|
560
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
561
|
+
db = Sequel.mock
|
|
562
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
563
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
564
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
565
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
566
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
567
|
+
ensure
|
|
568
|
+
Sequel.empty_array_handle_nulls = true
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
specify "should handle IN/NOT IN queries for datasets with row_procs" do
|
|
573
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
574
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
575
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
576
|
+
d1.row_proc = proc{|h| Object.new}
|
|
577
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
578
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
579
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
580
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
569
581
|
end
|
|
570
582
|
|
|
571
583
|
specify "should accept a subquery for an EXISTS clause" do
|
|
@@ -601,10 +613,18 @@ describe "Dataset#where" do
|
|
|
601
613
|
end
|
|
602
614
|
|
|
603
615
|
specify "should accept true and false as arguments" do
|
|
604
|
-
@dataset.filter(true).sql.should ==
|
|
605
|
-
|
|
606
|
-
@dataset.filter(false).sql.should ==
|
|
607
|
-
|
|
616
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE 't'"
|
|
617
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE 't'"
|
|
618
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
619
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
specify "should use boolean expression if dataset does not support where true/false" do
|
|
623
|
+
def @dataset.supports_where_true?() false end
|
|
624
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
625
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
626
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
627
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
608
628
|
end
|
|
609
629
|
|
|
610
630
|
specify "should allow the use of multiple arguments" do
|
|
@@ -658,33 +678,25 @@ describe "Dataset#or" do
|
|
|
658
678
|
end
|
|
659
679
|
|
|
660
680
|
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))'
|
|
681
|
+
@d1.or(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
|
663
682
|
end
|
|
664
683
|
|
|
665
684
|
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))'
|
|
685
|
+
@d1.or('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
|
686
|
+
@d1.or(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
670
687
|
end
|
|
671
688
|
|
|
672
689
|
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))'
|
|
690
|
+
@d1.or{:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
675
691
|
end
|
|
676
692
|
|
|
677
693
|
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))'
|
|
694
|
+
@d1.filter(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
695
|
+
@d1.or(:y => 2).filter(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
683
696
|
end
|
|
684
697
|
|
|
685
698
|
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)))'
|
|
699
|
+
@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
700
|
end
|
|
689
701
|
end
|
|
690
702
|
|
|
@@ -697,34 +709,25 @@ describe "Dataset#and" do
|
|
|
697
709
|
specify "should raise if no filter exists" do
|
|
698
710
|
proc {@dataset.and(:a => 1)}.should raise_error(Sequel::Error)
|
|
699
711
|
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"
|
|
712
|
+
@dataset.where(:a => 1).group(:t).and(:b => 2).sql == "SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
|
|
702
713
|
end
|
|
703
714
|
|
|
704
715
|
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))'
|
|
716
|
+
@d1.and(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
|
707
717
|
end
|
|
708
718
|
|
|
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))'
|
|
719
|
+
specify "should accept different types of filters" do
|
|
720
|
+
@d1.and('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
|
721
|
+
@d1.and(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
715
722
|
end
|
|
716
723
|
|
|
717
724
|
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))'
|
|
725
|
+
@d1.and {:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
720
726
|
end
|
|
721
727
|
|
|
722
728
|
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))'
|
|
729
|
+
@d1.or(:y => 2).and(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
730
|
+
@d1.and(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
728
731
|
end
|
|
729
732
|
end
|
|
730
733
|
|
|
@@ -734,8 +737,11 @@ describe "Dataset#exclude" do
|
|
|
734
737
|
end
|
|
735
738
|
|
|
736
739
|
specify "should correctly negate the expression when one condition is given" do
|
|
737
|
-
@dataset.exclude(:region=>'Asia').select_sql.should ==
|
|
738
|
-
|
|
740
|
+
@dataset.exclude(:region=>'Asia').select_sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
specify "should affect the having clause if having clause is already used" do
|
|
744
|
+
@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
745
|
end
|
|
740
746
|
|
|
741
747
|
specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
|
|
@@ -745,30 +751,46 @@ describe "Dataset#exclude" do
|
|
|
745
751
|
end
|
|
746
752
|
|
|
747
753
|
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')"
|
|
754
|
+
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
750
755
|
end
|
|
751
756
|
|
|
752
757
|
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')"
|
|
758
|
+
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
755
759
|
end
|
|
756
760
|
|
|
757
761
|
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'))"
|
|
762
|
+
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
|
760
763
|
end
|
|
761
764
|
|
|
762
765
|
specify "should support proc expressions" do
|
|
763
|
-
@dataset.exclude{:id.sql_number < 6}.sql.should ==
|
|
764
|
-
'SELECT * FROM test WHERE (id >= 6)'
|
|
766
|
+
@dataset.exclude{:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE (id >= 6)'
|
|
765
767
|
end
|
|
766
768
|
|
|
767
769
|
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
|
-
|
|
770
|
+
@dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id < 7) OR (id > 11) OR (id >= 6))'
|
|
771
|
+
@dataset.exclude([:id, 1], [:x, 3]){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id != 1) OR (x != 3) OR (id >= 6))'
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
describe "Dataset#exclude_where" do
|
|
776
|
+
before do
|
|
777
|
+
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
specify "should correctly negate the expression and add it to the where clause" do
|
|
781
|
+
@dataset.exclude_where(:region=>'Asia').sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
782
|
+
@dataset.exclude_where(:region=>'Asia').exclude_where(:region=>'NA').sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (region != 'NA'))"
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
specify "should affect the where clause even if having clause is already used" do
|
|
786
|
+
@dataset.group_and_count(:name).having{count > 2}.exclude_where(:region=>'Asia').sql.should ==
|
|
787
|
+
"SELECT name, count(*) AS count FROM test WHERE (region != 'Asia') GROUP BY name HAVING (count > 2)"
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
describe "Dataset#exclude_having" do
|
|
792
|
+
specify "should correctly negate the expression and add it to the having clause" do
|
|
793
|
+
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
794
|
end
|
|
773
795
|
end
|
|
774
796
|
|
|
@@ -794,9 +816,6 @@ describe "Dataset#having" do
|
|
|
794
816
|
before do
|
|
795
817
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
796
818
|
@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
819
|
end
|
|
801
820
|
|
|
802
821
|
specify "should just clone if given an empty argument" do
|
|
@@ -806,18 +825,15 @@ describe "Dataset#having" do
|
|
|
806
825
|
end
|
|
807
826
|
|
|
808
827
|
specify "should affect select statements" do
|
|
809
|
-
@
|
|
810
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
828
|
+
@grouped.having('sum(population) > 10').select_sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
811
829
|
end
|
|
812
830
|
|
|
813
831
|
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)"
|
|
832
|
+
@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
833
|
end
|
|
817
834
|
|
|
818
835
|
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))"
|
|
836
|
+
@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
837
|
end
|
|
822
838
|
end
|
|
823
839
|
|
|
@@ -848,7 +864,7 @@ describe "a grouped dataset" do
|
|
|
848
864
|
end
|
|
849
865
|
|
|
850
866
|
specify "should format the right statement for counting (as a subquery)" do
|
|
851
|
-
db =
|
|
867
|
+
db = Sequel.mock
|
|
852
868
|
db[:test].select(:name).group(:name).count
|
|
853
869
|
db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT name FROM test GROUP BY name) AS t1 LIMIT 1"]
|
|
854
870
|
end
|
|
@@ -856,7 +872,7 @@ end
|
|
|
856
872
|
|
|
857
873
|
describe "Dataset#group_by" do
|
|
858
874
|
before do
|
|
859
|
-
@dataset = Sequel
|
|
875
|
+
@dataset = Sequel.mock[:test].group_by(:type_id)
|
|
860
876
|
end
|
|
861
877
|
|
|
862
878
|
specify "should raise when trying to generate an update statement" do
|
|
@@ -868,45 +884,60 @@ describe "Dataset#group_by" do
|
|
|
868
884
|
end
|
|
869
885
|
|
|
870
886
|
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)"
|
|
887
|
+
@dataset.select_sql.should == "SELECT * FROM test GROUP BY type_id"
|
|
888
|
+
@dataset.group_by(:a, :b).select_sql.should == "SELECT * FROM test GROUP BY a, b"
|
|
889
|
+
@dataset.group_by(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
877
890
|
end
|
|
878
891
|
|
|
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"
|
|
892
|
+
specify "should ungroup when passed nil or no arguments" do
|
|
893
|
+
@dataset.group_by.select_sql.should == "SELECT * FROM test"
|
|
894
|
+
@dataset.group_by(nil).select_sql.should == "SELECT * FROM test"
|
|
884
895
|
end
|
|
885
896
|
|
|
886
897
|
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"
|
|
898
|
+
@dataset.group_by(:a).group_by(:b).select_sql.should == "SELECT * FROM test GROUP BY b"
|
|
899
|
+
@dataset.group_by(:a, :b).group_by.select_sql.should == "SELECT * FROM test"
|
|
891
900
|
end
|
|
892
901
|
|
|
893
902
|
specify "should be aliased as #group" do
|
|
894
|
-
@dataset.group(:type_id=>nil).select_sql.should ==
|
|
895
|
-
|
|
903
|
+
@dataset.group(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
specify "should take a virtual row block" do
|
|
907
|
+
@dataset.group{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
908
|
+
@dataset.group_by{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
909
|
+
@dataset.group{[type_id > 1, type_id < 2]}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1), (type_id < 2)"
|
|
910
|
+
@dataset.group(:foo){type_id > 1}.sql.should == "SELECT * FROM test GROUP BY foo, (type_id > 1)"
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
specify "should support a #group_rollup method if the database supports it" do
|
|
914
|
+
@dataset.meta_def(:supports_group_rollup?){true}
|
|
915
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id)"
|
|
916
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id, b)"
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
specify "should support a #group_cube method if the database supports it" do
|
|
920
|
+
@dataset.meta_def(:supports_group_cube?){true}
|
|
921
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id)"
|
|
922
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id, b)"
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
specify "should have #group_cube and #group_rollup methods raise an Error if not supported it" do
|
|
926
|
+
proc{@dataset.group(:type_id).group_rollup}.should raise_error(Sequel::Error)
|
|
927
|
+
proc{@dataset.group(:type_id).group_cube}.should raise_error(Sequel::Error)
|
|
896
928
|
end
|
|
897
929
|
end
|
|
898
930
|
|
|
899
931
|
describe "Dataset#as" do
|
|
900
932
|
specify "should set up an alias" do
|
|
901
933
|
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'
|
|
934
|
+
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
|
904
935
|
end
|
|
905
936
|
end
|
|
906
937
|
|
|
907
938
|
describe "Dataset#literal" do
|
|
908
939
|
before do
|
|
909
|
-
@dataset = Sequel::
|
|
940
|
+
@dataset = Sequel::Database.new.from(:test)
|
|
910
941
|
end
|
|
911
942
|
|
|
912
943
|
specify "should escape strings properly" do
|
|
@@ -944,6 +975,21 @@ describe "Dataset#literal" do
|
|
|
944
975
|
@dataset.literal(:"items__na#m$e").should == "items.na#m$e"
|
|
945
976
|
end
|
|
946
977
|
|
|
978
|
+
specify "should call sql_literal_append with dataset and sql on type if not natively supported and the object responds to it" do
|
|
979
|
+
@a = Class.new do
|
|
980
|
+
def sql_literal_append(ds, sql)
|
|
981
|
+
sql << "called #{ds.blah}"
|
|
982
|
+
end
|
|
983
|
+
def sql_literal(ds)
|
|
984
|
+
"not called #{ds.blah}"
|
|
985
|
+
end
|
|
986
|
+
end
|
|
987
|
+
def @dataset.blah
|
|
988
|
+
"ds"
|
|
989
|
+
end
|
|
990
|
+
@dataset.literal(@a.new).should == "called ds"
|
|
991
|
+
end
|
|
992
|
+
|
|
947
993
|
specify "should call sql_literal with dataset on type if not natively supported and the object responds to it" do
|
|
948
994
|
@a = Class.new do
|
|
949
995
|
def sql_literal(ds)
|
|
@@ -965,6 +1011,12 @@ describe "Dataset#literal" do
|
|
|
965
1011
|
d.literal(d).should == "(#{d.sql})"
|
|
966
1012
|
end
|
|
967
1013
|
|
|
1014
|
+
specify "should literalize Sequel::SQLTime properly" do
|
|
1015
|
+
t = Sequel::SQLTime.now
|
|
1016
|
+
s = t.strftime("'%H:%M:%S")
|
|
1017
|
+
@dataset.literal(t).should == "#{s}.#{sprintf('%06i', t.usec)}'"
|
|
1018
|
+
end
|
|
1019
|
+
|
|
968
1020
|
specify "should literalize Time properly" do
|
|
969
1021
|
t = Time.now
|
|
970
1022
|
s = t.strftime("'%Y-%m-%d %H:%M:%S")
|
|
@@ -1041,10 +1093,9 @@ describe "Dataset#literal" do
|
|
|
1041
1093
|
end
|
|
1042
1094
|
|
|
1043
1095
|
specify "should not modify literal strings" do
|
|
1096
|
+
@dataset.quote_identifiers = true
|
|
1044
1097
|
@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'
|
|
1098
|
+
@dataset.update_sql(Sequel::SQL::Identifier.new('a'.lit) => 'a + 2'.lit).should == 'UPDATE "test" SET a = a + 2'
|
|
1048
1099
|
end
|
|
1049
1100
|
|
|
1050
1101
|
specify "should literalize BigDecimal instances correctly" do
|
|
@@ -1069,35 +1120,25 @@ describe "Dataset#from" do
|
|
|
1069
1120
|
end
|
|
1070
1121
|
|
|
1071
1122
|
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"
|
|
1123
|
+
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should == "SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
|
|
1074
1124
|
end
|
|
1075
1125
|
|
|
1076
1126
|
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"
|
|
1127
|
+
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
|
|
1079
1128
|
|
|
1080
1129
|
d1 = @dataset.from(:a).group(:b)
|
|
1081
1130
|
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"
|
|
1131
|
+
@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
1132
|
end
|
|
1086
1133
|
|
|
1087
1134
|
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"
|
|
1135
|
+
@dataset.from(:a => :b).sql.should == "SELECT * FROM a AS b"
|
|
1136
|
+
@dataset.from(:a => 'b').sql.should == "SELECT * FROM a AS b"
|
|
1137
|
+
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
|
|
1096
1138
|
end
|
|
1097
1139
|
|
|
1098
1140
|
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"
|
|
1141
|
+
@dataset.from(@dataset.from(:a)).select_sql.should == "SELECT * FROM (SELECT * FROM a) AS t1"
|
|
1101
1142
|
end
|
|
1102
1143
|
|
|
1103
1144
|
specify "should remove all FROM tables if called with no arguments" do
|
|
@@ -1105,32 +1146,31 @@ describe "Dataset#from" do
|
|
|
1105
1146
|
end
|
|
1106
1147
|
|
|
1107
1148
|
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)"
|
|
1149
|
+
@dataset.from(:abc.sql_function(:def)).select_sql.should == "SELECT * FROM abc(def)"
|
|
1150
|
+
@dataset.from(:a.sql_function(:i)).select_sql.should == "SELECT * FROM a(i)"
|
|
1113
1151
|
end
|
|
1114
1152
|
|
|
1115
1153
|
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
|
-
|
|
1154
|
+
@dataset.from(:abc__def).select_sql.should == "SELECT * FROM abc.def"
|
|
1155
|
+
@dataset.from(:a_b__c).select_sql.should == "SELECT * FROM a_b.c"
|
|
1156
|
+
@dataset.from(:'#__#').select_sql.should == 'SELECT * FROM #.#'
|
|
1157
|
+
@dataset.from(:abc__def___d).select_sql.should == "SELECT * FROM abc.def AS d"
|
|
1158
|
+
@dataset.from(:a_b__d_e___f_g).select_sql.should == "SELECT * FROM a_b.d_e AS f_g"
|
|
1159
|
+
@dataset.from(:'#__#___#').select_sql.should == 'SELECT * FROM #.# AS #'
|
|
1160
|
+
@dataset.from(:abc___def).select_sql.should == "SELECT * FROM abc AS def"
|
|
1161
|
+
@dataset.from(:a_b___c_d).select_sql.should == "SELECT * FROM a_b AS c_d"
|
|
1162
|
+
@dataset.from(:'#___#').select_sql.should == 'SELECT * FROM # AS #'
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
specify "should not handle :foo__schema__table___alias specially" do
|
|
1166
|
+
@dataset.from(:foo__schema__table___alias).select_sql.should == "SELECT * FROM foo.schema__table AS alias"
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
1170
|
+
@dataset.meta_def(:supports_cte?){true}
|
|
1171
|
+
@dataset.meta_def(:supports_cte_in_subselect?){false}
|
|
1172
|
+
@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'
|
|
1173
|
+
@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
1174
|
end
|
|
1135
1175
|
end
|
|
1136
1176
|
|
|
@@ -1147,18 +1187,17 @@ describe "Dataset#select" do
|
|
|
1147
1187
|
specify "should accept symbols and literal strings" do
|
|
1148
1188
|
@d.select('aaa'.lit).sql.should == 'SELECT aaa FROM test'
|
|
1149
1189
|
@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'
|
|
1190
|
+
@d.select(:test__cc, 'test.d AS e'.lit).sql.should == 'SELECT test.cc, test.d AS e FROM test'
|
|
1191
|
+
@d.select('test.d AS e'.lit, :test__cc).sql.should == 'SELECT test.d AS e, test.cc FROM test'
|
|
1192
|
+
@d.select(:test__name___n).sql.should == 'SELECT test.name AS n FROM test'
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1195
|
+
specify "should accept ColumnAlls" do
|
|
1196
|
+
@d.select(:test.*).sql.should == 'SELECT test.* FROM test'
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1199
|
+
specify "should accept QualifiedIdentifiers" do
|
|
1200
|
+
@d.select(:test__name.as(:n)).sql.should == 'SELECT test.name AS n FROM test'
|
|
1162
1201
|
end
|
|
1163
1202
|
|
|
1164
1203
|
specify "should use the wildcard if no arguments are given" do
|
|
@@ -1166,20 +1205,17 @@ describe "Dataset#select" do
|
|
|
1166
1205
|
end
|
|
1167
1206
|
|
|
1168
1207
|
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/
|
|
1208
|
+
@d.select(:name => 'n', :__ggh => 'age').sql.should =~ /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
|
1171
1209
|
end
|
|
1172
1210
|
|
|
1173
|
-
specify "should
|
|
1211
|
+
specify "should override the previous select option" do
|
|
1174
1212
|
@d.select!(:a, :b, :c).select.sql.should == 'SELECT * FROM test'
|
|
1175
1213
|
@d.select!(:price).select(:name).sql.should == 'SELECT name FROM test'
|
|
1176
1214
|
end
|
|
1177
1215
|
|
|
1178
1216
|
specify "should accept arbitrary objects and literalize them correctly" do
|
|
1179
1217
|
@d.select(1, :a, 't').sql.should == "SELECT 1, a, 't' FROM test"
|
|
1180
|
-
|
|
1181
1218
|
@d.select(nil, :sum.sql_function(:t), :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
|
|
1182
|
-
|
|
1183
1219
|
@d.select(nil, 1, :x => :y).sql.should == "SELECT NULL, 1, x AS y FROM test"
|
|
1184
1220
|
end
|
|
1185
1221
|
|
|
@@ -1198,6 +1234,27 @@ describe "Dataset#select" do
|
|
|
1198
1234
|
end
|
|
1199
1235
|
end
|
|
1200
1236
|
|
|
1237
|
+
describe "Dataset#select_group" do
|
|
1238
|
+
before do
|
|
1239
|
+
@d = Sequel::Dataset.new(nil).from(:test)
|
|
1240
|
+
end
|
|
1241
|
+
|
|
1242
|
+
specify "should set both SELECT and GROUP" do
|
|
1243
|
+
@d.select_group(:name).sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1244
|
+
@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'
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
specify "should remove from both SELECT and GROUP if no arguments" do
|
|
1248
|
+
@d.select_group(:name).select_group.sql.should == 'SELECT * FROM test'
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
specify "should accept virtual row blocks" do
|
|
1252
|
+
@d.select_group{name}.sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1253
|
+
@d.select_group{[name, f(v).as(a)]}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1254
|
+
@d.select_group(:name){f(v).as(a)}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1255
|
+
end
|
|
1256
|
+
end
|
|
1257
|
+
|
|
1201
1258
|
describe "Dataset#select_all" do
|
|
1202
1259
|
before do
|
|
1203
1260
|
@d = Sequel::Dataset.new(nil).from(:test)
|
|
@@ -1207,9 +1264,43 @@ describe "Dataset#select_all" do
|
|
|
1207
1264
|
@d.select_all.sql.should == 'SELECT * FROM test'
|
|
1208
1265
|
end
|
|
1209
1266
|
|
|
1210
|
-
specify "should
|
|
1267
|
+
specify "should override the previous select option" do
|
|
1211
1268
|
@d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
|
|
1212
1269
|
end
|
|
1270
|
+
|
|
1271
|
+
specify "should select all columns in a table if given an argument" do
|
|
1272
|
+
@d.select_all(:test).sql.should == 'SELECT test.* FROM test'
|
|
1273
|
+
end
|
|
1274
|
+
|
|
1275
|
+
specify "should select all columns all tables if given a multiple arguments" do
|
|
1276
|
+
@d.select_all(:test, :foo).sql.should == 'SELECT test.*, foo.* FROM test'
|
|
1277
|
+
end
|
|
1278
|
+
|
|
1279
|
+
specify "should work correctly with qualified symbols" do
|
|
1280
|
+
@d.select_all(:sch__test).sql.should == 'SELECT sch.test.* FROM test'
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1283
|
+
specify "should work correctly with aliased symbols" do
|
|
1284
|
+
@d.select_all(:test___al).sql.should == 'SELECT al.* FROM test'
|
|
1285
|
+
@d.select_all(:sch__test___al).sql.should == 'SELECT al.* FROM test'
|
|
1286
|
+
end
|
|
1287
|
+
|
|
1288
|
+
specify "should work correctly with SQL::Identifiers" do
|
|
1289
|
+
@d.select_all(:test.identifier).sql.should == 'SELECT test.* FROM test'
|
|
1290
|
+
end
|
|
1291
|
+
|
|
1292
|
+
specify "should work correctly with SQL::QualifiedIdentifier" do
|
|
1293
|
+
@d.select_all(:test.qualify(:sch)).sql.should == 'SELECT sch.test.* FROM test'
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
specify "should work correctly with SQL::AliasedExpressions" do
|
|
1297
|
+
@d.select_all(:test.as(:al)).sql.should == 'SELECT al.* FROM test'
|
|
1298
|
+
end
|
|
1299
|
+
|
|
1300
|
+
specify "should work correctly with SQL::JoinClauses" do
|
|
1301
|
+
d = @d.cross_join(:foo).cross_join(:test___al)
|
|
1302
|
+
@d.select_all(*d.opts[:join]).sql.should == 'SELECT foo.*, al.* FROM test'
|
|
1303
|
+
end
|
|
1213
1304
|
end
|
|
1214
1305
|
|
|
1215
1306
|
describe "Dataset#select_more" do
|
|
@@ -1254,6 +1345,14 @@ describe "Dataset#select_append" do
|
|
|
1254
1345
|
@d.select(:a).select_append{|o| o.b}.sql.should == 'SELECT a, b FROM test'
|
|
1255
1346
|
@d.select(:a.*).select_append(:b.*){b(1)}.sql.should == 'SELECT a.*, b.*, b(1) FROM test'
|
|
1256
1347
|
end
|
|
1348
|
+
|
|
1349
|
+
specify "should select from all from and join tables if SELECT *, column not supported" do
|
|
1350
|
+
@d.meta_def(:supports_select_all_and_column?){false}
|
|
1351
|
+
@d.select_append(:b).sql.should == 'SELECT test.*, b FROM test'
|
|
1352
|
+
@d.from(:test, :c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test, c'
|
|
1353
|
+
@d.cross_join(:c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test CROSS JOIN c'
|
|
1354
|
+
@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'
|
|
1355
|
+
end
|
|
1257
1356
|
end
|
|
1258
1357
|
|
|
1259
1358
|
describe "Dataset#order" do
|
|
@@ -1262,38 +1361,31 @@ describe "Dataset#order" do
|
|
|
1262
1361
|
end
|
|
1263
1362
|
|
|
1264
1363
|
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'
|
|
1364
|
+
@dataset.order(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1267
1365
|
end
|
|
1268
1366
|
|
|
1269
1367
|
specify "should accept multiple arguments" do
|
|
1270
|
-
@dataset.order(:name, :price.desc).sql.should ==
|
|
1271
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1368
|
+
@dataset.order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1272
1369
|
end
|
|
1273
1370
|
|
|
1274
1371
|
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'
|
|
1372
|
+
@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
1373
|
end
|
|
1278
1374
|
|
|
1279
|
-
specify "should
|
|
1280
|
-
@dataset.order(:name).order(:stamp).sql.should ==
|
|
1281
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1375
|
+
specify "should override a previous ordering" do
|
|
1376
|
+
@dataset.order(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1282
1377
|
end
|
|
1283
1378
|
|
|
1284
1379
|
specify "should accept a literal string" do
|
|
1285
|
-
@dataset.order('dada ASC'.lit).sql.should ==
|
|
1286
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1380
|
+
@dataset.order('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1287
1381
|
end
|
|
1288
1382
|
|
|
1289
1383
|
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)'
|
|
1384
|
+
@dataset.order(:name=>nil).sql.should == 'SELECT * FROM test ORDER BY (name IS NULL)'
|
|
1292
1385
|
end
|
|
1293
1386
|
|
|
1294
1387
|
specify "should accept a nil to remove ordering" do
|
|
1295
|
-
@dataset.order(:bah).order(nil).sql.should ==
|
|
1296
|
-
'SELECT * FROM test'
|
|
1388
|
+
@dataset.order(:bah).order(nil).sql.should == 'SELECT * FROM test'
|
|
1297
1389
|
end
|
|
1298
1390
|
|
|
1299
1391
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1355,6 +1447,13 @@ describe "Dataset#with_sql" do
|
|
|
1355
1447
|
specify "should keep row_proc" do
|
|
1356
1448
|
@dataset.with_sql('SELECT 1 FROM test').row_proc.should == @dataset.row_proc
|
|
1357
1449
|
end
|
|
1450
|
+
|
|
1451
|
+
specify "should work with method symbols and arguments" do
|
|
1452
|
+
@dataset.with_sql(:delete_sql).sql.should == 'DELETE FROM test'
|
|
1453
|
+
@dataset.with_sql(:insert_sql, :b=>1).sql.should == 'INSERT INTO test (b) VALUES (1)'
|
|
1454
|
+
@dataset.with_sql(:update_sql, :b=>1).sql.should == 'UPDATE test SET b = 1'
|
|
1455
|
+
end
|
|
1456
|
+
|
|
1358
1457
|
end
|
|
1359
1458
|
|
|
1360
1459
|
describe "Dataset#order_by" do
|
|
@@ -1363,28 +1462,23 @@ describe "Dataset#order_by" do
|
|
|
1363
1462
|
end
|
|
1364
1463
|
|
|
1365
1464
|
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'
|
|
1465
|
+
@dataset.order_by(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1368
1466
|
end
|
|
1369
1467
|
|
|
1370
1468
|
specify "should accept multiple arguments" do
|
|
1371
|
-
@dataset.order_by(:name, :price.desc).sql.should ==
|
|
1372
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1469
|
+
@dataset.order_by(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1373
1470
|
end
|
|
1374
1471
|
|
|
1375
|
-
specify "should
|
|
1376
|
-
@dataset.order_by(:name).order(:stamp).sql.should ==
|
|
1377
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1472
|
+
specify "should override a previous ordering" do
|
|
1473
|
+
@dataset.order_by(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1378
1474
|
end
|
|
1379
1475
|
|
|
1380
1476
|
specify "should accept a string" do
|
|
1381
|
-
@dataset.order_by('dada ASC'.lit).sql.should ==
|
|
1382
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1477
|
+
@dataset.order_by('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1383
1478
|
end
|
|
1384
1479
|
|
|
1385
1480
|
specify "should accept a nil to remove ordering" do
|
|
1386
|
-
@dataset.order_by(:bah).order_by(nil).sql.should ==
|
|
1387
|
-
'SELECT * FROM test'
|
|
1481
|
+
@dataset.order_by(:bah).order_by(nil).sql.should == 'SELECT * FROM test'
|
|
1388
1482
|
end
|
|
1389
1483
|
end
|
|
1390
1484
|
|
|
@@ -1417,13 +1511,11 @@ describe "Dataset#order_prepend" do
|
|
|
1417
1511
|
end
|
|
1418
1512
|
|
|
1419
1513
|
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'
|
|
1514
|
+
@dataset.order_prepend(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1422
1515
|
end
|
|
1423
1516
|
|
|
1424
1517
|
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'
|
|
1518
|
+
@dataset.order(:name).order_prepend(:stamp.desc).sql.should == 'SELECT * FROM test ORDER BY stamp DESC, name'
|
|
1427
1519
|
end
|
|
1428
1520
|
|
|
1429
1521
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1438,45 +1530,36 @@ describe "Dataset#reverse_order" do
|
|
|
1438
1530
|
end
|
|
1439
1531
|
|
|
1440
1532
|
specify "should use DESC as default order" do
|
|
1441
|
-
@dataset.reverse_order(:name).sql.should ==
|
|
1442
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1533
|
+
@dataset.reverse_order(:name).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1443
1534
|
end
|
|
1444
1535
|
|
|
1445
1536
|
specify "should invert the order given" do
|
|
1446
|
-
@dataset.reverse_order(:name.desc).sql.should ==
|
|
1447
|
-
'SELECT * FROM test ORDER BY name ASC'
|
|
1537
|
+
@dataset.reverse_order(:name.desc).sql.should == 'SELECT * FROM test ORDER BY name ASC'
|
|
1448
1538
|
end
|
|
1449
1539
|
|
|
1450
1540
|
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'
|
|
1541
|
+
@dataset.reverse_order(:name.asc).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1453
1542
|
end
|
|
1454
1543
|
|
|
1455
1544
|
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'
|
|
1545
|
+
@dataset.reverse_order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name DESC, price ASC'
|
|
1458
1546
|
end
|
|
1459
1547
|
|
|
1460
1548
|
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'
|
|
1549
|
+
@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
1550
|
end
|
|
1464
1551
|
|
|
1465
1552
|
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'
|
|
1553
|
+
@dataset.order(:name).reverse_order.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1554
|
+
@dataset.order(:clumsy.desc, :fool).reverse_order.sql.should == 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
|
|
1470
1555
|
end
|
|
1471
1556
|
|
|
1472
1557
|
specify "should return an unordered dataset for a dataset with no order" do
|
|
1473
|
-
@dataset.unordered.reverse_order.sql.should ==
|
|
1474
|
-
'SELECT * FROM test'
|
|
1558
|
+
@dataset.unordered.reverse_order.sql.should == 'SELECT * FROM test'
|
|
1475
1559
|
end
|
|
1476
1560
|
|
|
1477
1561
|
specify "should have #reverse alias" do
|
|
1478
|
-
@dataset.order(:name).reverse.sql.should ==
|
|
1479
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1562
|
+
@dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1480
1563
|
end
|
|
1481
1564
|
end
|
|
1482
1565
|
|
|
@@ -1486,42 +1569,33 @@ describe "Dataset#limit" do
|
|
|
1486
1569
|
end
|
|
1487
1570
|
|
|
1488
1571
|
specify "should include a LIMIT clause in the select statement" do
|
|
1489
|
-
@dataset.limit(10).sql.should ==
|
|
1490
|
-
'SELECT * FROM test LIMIT 10'
|
|
1572
|
+
@dataset.limit(10).sql.should == 'SELECT * FROM test LIMIT 10'
|
|
1491
1573
|
end
|
|
1492
1574
|
|
|
1493
1575
|
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'
|
|
1576
|
+
@dataset.limit(3..7).sql.should == 'SELECT * FROM test LIMIT 5 OFFSET 3'
|
|
1577
|
+
@dataset.limit(3...7).sql.should == 'SELECT * FROM test LIMIT 4 OFFSET 3'
|
|
1499
1578
|
end
|
|
1500
1579
|
|
|
1501
1580
|
specify "should include an offset if a second argument is given" do
|
|
1502
|
-
@dataset.limit(6, 10).sql.should ==
|
|
1503
|
-
|
|
1504
|
-
end
|
|
1581
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 10'
|
|
1582
|
+
end
|
|
1505
1583
|
|
|
1506
1584
|
specify "should convert regular strings to integers" do
|
|
1507
|
-
@dataset.limit('6', 'a() - 1').sql.should ==
|
|
1508
|
-
'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1585
|
+
@dataset.limit('6', 'a() - 1').sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1509
1586
|
end
|
|
1510
1587
|
|
|
1511
1588
|
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'
|
|
1589
|
+
@dataset.limit('6'.lit, 'a() - 1'.lit).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1514
1590
|
end
|
|
1515
1591
|
|
|
1516
1592
|
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)'
|
|
1593
|
+
@dataset.limit(6, :a.sql_function - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1519
1594
|
end
|
|
1520
1595
|
|
|
1521
1596
|
specify "should work with fixed sql datasets" do
|
|
1522
1597
|
@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'
|
|
1598
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
|
1525
1599
|
end
|
|
1526
1600
|
|
|
1527
1601
|
specify "should raise an error if an invalid limit or offset is used" do
|
|
@@ -1535,15 +1609,20 @@ describe "Dataset#limit" do
|
|
|
1535
1609
|
end
|
|
1536
1610
|
|
|
1537
1611
|
describe "Dataset#naked" do
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1612
|
+
specify "should returned clone dataset without row_proc" do
|
|
1613
|
+
d = Sequel::Dataset.new(nil)
|
|
1614
|
+
d.row_proc = Proc.new{|r| r}
|
|
1615
|
+
d.naked.row_proc.should be_nil
|
|
1616
|
+
d.row_proc.should_not be_nil
|
|
1542
1617
|
end
|
|
1543
|
-
|
|
1618
|
+
end
|
|
1619
|
+
|
|
1620
|
+
describe "Dataset#naked!" do
|
|
1544
1621
|
specify "should remove any existing row_proc" do
|
|
1545
|
-
|
|
1546
|
-
|
|
1622
|
+
d = Sequel::Dataset.new(nil)
|
|
1623
|
+
d.row_proc = Proc.new{|r| r}
|
|
1624
|
+
d.naked!.row_proc.should be_nil
|
|
1625
|
+
d.row_proc.should be_nil
|
|
1547
1626
|
end
|
|
1548
1627
|
end
|
|
1549
1628
|
|
|
@@ -1571,38 +1650,42 @@ describe "Dataset#qualified_column_name" do
|
|
|
1571
1650
|
end
|
|
1572
1651
|
end
|
|
1573
1652
|
|
|
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
1653
|
describe "Dataset#map" do
|
|
1586
1654
|
before do
|
|
1587
|
-
@d =
|
|
1655
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1588
1656
|
end
|
|
1589
1657
|
|
|
1590
1658
|
specify "should provide the usual functionality if no argument is given" do
|
|
1591
|
-
@d.map
|
|
1659
|
+
@d.map{|n| n[:a] + n[:b]}.should == [3, 7, 11]
|
|
1592
1660
|
end
|
|
1593
1661
|
|
|
1594
1662
|
specify "should map using #[column name] if column name is given" do
|
|
1595
1663
|
@d.map(:a).should == [1, 3, 5]
|
|
1596
1664
|
end
|
|
1597
1665
|
|
|
1666
|
+
specify "should support multiple column names if an array of column names is given" do
|
|
1667
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1668
|
+
end
|
|
1669
|
+
|
|
1670
|
+
specify "should not call the row_proc if an argument is given" do
|
|
1671
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1672
|
+
@d.map(:a).should == [1, 3, 5]
|
|
1673
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1674
|
+
end
|
|
1675
|
+
|
|
1676
|
+
specify "should call the row_proc if no argument is given" do
|
|
1677
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1678
|
+
@d.map{|n| n[:a] + n[:b]}.should == [6, 14, 22]
|
|
1679
|
+
end
|
|
1680
|
+
|
|
1598
1681
|
specify "should return the complete dataset values if nothing is given" do
|
|
1599
|
-
@d.map.to_a.should ==
|
|
1682
|
+
@d.map.to_a.should == [{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}]
|
|
1600
1683
|
end
|
|
1601
1684
|
end
|
|
1602
1685
|
|
|
1603
1686
|
describe "Dataset#to_hash" do
|
|
1604
1687
|
before do
|
|
1605
|
-
@d =
|
|
1688
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1606
1689
|
end
|
|
1607
1690
|
|
|
1608
1691
|
specify "should provide a hash with the first column as key and the second as value" do
|
|
@@ -1614,11 +1697,35 @@ describe "Dataset#to_hash" do
|
|
|
1614
1697
|
@d.to_hash(:a).should == {1 => {:a => 1, :b => 2}, 3 => {:a => 3, :b => 4}, 5 => {:a => 5, :b => 6}}
|
|
1615
1698
|
@d.to_hash(:b).should == {2 => {:a => 1, :b => 2}, 4 => {:a => 3, :b => 4}, 6 => {:a => 5, :b => 6}}
|
|
1616
1699
|
end
|
|
1700
|
+
|
|
1701
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1702
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1703
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1704
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1705
|
+
@d.to_hash([:a, :b]).should == {[1, 2] => {:a => 1, :b => 2}, [3, 4] => {:a => 3, :b => 4}, [5, 6] => {:a => 5, :b => 6}}
|
|
1706
|
+
end
|
|
1707
|
+
|
|
1708
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1709
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1710
|
+
@d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
|
|
1711
|
+
@d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
|
|
1712
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1713
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1714
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1715
|
+
end
|
|
1716
|
+
|
|
1717
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1718
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1719
|
+
@d.to_hash(:a).should == {2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12}}
|
|
1720
|
+
@d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
|
|
1721
|
+
@d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
|
|
1722
|
+
end
|
|
1723
|
+
|
|
1617
1724
|
end
|
|
1618
1725
|
|
|
1619
1726
|
describe "Dataset#distinct" do
|
|
1620
1727
|
before do
|
|
1621
|
-
@db =
|
|
1728
|
+
@db = Sequel.mock
|
|
1622
1729
|
@dataset = @db[:test].select(:name)
|
|
1623
1730
|
end
|
|
1624
1731
|
|
|
@@ -1645,132 +1752,100 @@ end
|
|
|
1645
1752
|
|
|
1646
1753
|
describe "Dataset#count" do
|
|
1647
1754
|
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)
|
|
1755
|
+
@db = Sequel.mock(:fetch=>{:count=>1})
|
|
1756
|
+
@dataset = @db.from(:test).columns(:count)
|
|
1660
1757
|
end
|
|
1661
1758
|
|
|
1662
1759
|
specify "should format SQL properly" do
|
|
1663
1760
|
@dataset.count.should == 1
|
|
1664
|
-
@
|
|
1761
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
|
|
1665
1762
|
end
|
|
1666
1763
|
|
|
1667
1764
|
specify "should include the where clause if it's there" do
|
|
1668
1765
|
@dataset.filter(:abc.sql_number < 30).count.should == 1
|
|
1669
|
-
@
|
|
1766
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
|
|
1670
1767
|
end
|
|
1671
1768
|
|
|
1672
1769
|
specify "should count properly for datasets with fixed sql" do
|
|
1673
1770
|
@dataset.opts[:sql] = "select abc from xyz"
|
|
1674
1771
|
@dataset.count.should == 1
|
|
1675
|
-
@
|
|
1772
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
|
|
1676
1773
|
end
|
|
1677
1774
|
|
|
1678
1775
|
specify "should count properly when using UNION, INTERSECT, or EXCEPT" do
|
|
1679
1776
|
@dataset.union(@dataset).count.should == 1
|
|
1680
|
-
@
|
|
1777
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1681
1778
|
@dataset.intersect(@dataset).count.should == 1
|
|
1682
|
-
@
|
|
1779
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1683
1780
|
@dataset.except(@dataset).count.should == 1
|
|
1684
|
-
@
|
|
1781
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1685
1782
|
end
|
|
1686
1783
|
|
|
1687
1784
|
specify "should return limit if count is greater than it" do
|
|
1688
1785
|
@dataset.limit(5).count.should == 1
|
|
1689
|
-
@
|
|
1786
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"]
|
|
1690
1787
|
end
|
|
1691
1788
|
|
|
1692
1789
|
it "should work on a graphed_dataset" do
|
|
1693
1790
|
@dataset.should_receive(:columns).twice.and_return([:a])
|
|
1694
1791
|
@dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
|
|
1695
|
-
@
|
|
1792
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
1696
1793
|
end
|
|
1697
1794
|
|
|
1698
1795
|
specify "should not cache the columns value" do
|
|
1699
|
-
ds = @dataset.from(:blah)
|
|
1796
|
+
ds = @dataset.from(:blah).columns(:a)
|
|
1700
1797
|
ds.columns.should == [:a]
|
|
1701
1798
|
ds.count.should == 1
|
|
1702
|
-
@
|
|
1799
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM blah LIMIT 1']
|
|
1703
1800
|
ds.columns.should == [:a]
|
|
1704
1801
|
end
|
|
1705
1802
|
end
|
|
1706
1803
|
|
|
1707
|
-
|
|
1708
1804
|
describe "Dataset#group_and_count" do
|
|
1709
1805
|
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)
|
|
1806
|
+
@ds = Sequel::Dataset.new(nil).from(:test)
|
|
1721
1807
|
end
|
|
1722
1808
|
|
|
1723
1809
|
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"
|
|
1810
|
+
@ds.group_and_count(:name).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1726
1811
|
end
|
|
1727
1812
|
|
|
1728
1813
|
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"
|
|
1814
|
+
@ds.group_and_count(:a, :b).sql.should == "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
|
|
1731
1815
|
end
|
|
1732
1816
|
|
|
1733
1817
|
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"
|
|
1818
|
+
@ds.group_and_count(:name___n).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1819
|
+
@ds.group_and_count(:name__n).sql.should == "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
|
1738
1820
|
end
|
|
1739
1821
|
|
|
1740
1822
|
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"
|
|
1823
|
+
@ds.group_and_count(:name___n.identifier).sql.should == "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1743
1824
|
end
|
|
1744
1825
|
|
|
1745
1826
|
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"
|
|
1827
|
+
@ds.group_and_count("name".lit).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1748
1828
|
end
|
|
1749
1829
|
|
|
1750
1830
|
specify "should handle aliased expressions" do
|
|
1751
|
-
@ds.group_and_count(:name.as(:n)).sql.should ==
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1831
|
+
@ds.group_and_count(:name.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1832
|
+
@ds.group_and_count(:name.identifier.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1833
|
+
end
|
|
1834
|
+
|
|
1835
|
+
specify "should take a virtual row block" do
|
|
1836
|
+
@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)"
|
|
1837
|
+
@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)"
|
|
1838
|
+
@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
1839
|
end
|
|
1756
1840
|
end
|
|
1757
1841
|
|
|
1758
1842
|
describe "Dataset#empty?" do
|
|
1759
1843
|
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"
|
|
1844
|
+
db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
|
|
1845
|
+
db.from(:test).should_not be_empty
|
|
1846
|
+
db.sqls.should == ['SELECT 1 AS one FROM test LIMIT 1']
|
|
1847
|
+
db.from(:test).filter(false).should be_empty
|
|
1848
|
+
db.sqls.should == ["SELECT 1 AS one FROM test WHERE 'f' LIMIT 1"]
|
|
1774
1849
|
end
|
|
1775
1850
|
end
|
|
1776
1851
|
|
|
@@ -1817,9 +1892,9 @@ describe "Dataset#first_source_table" do
|
|
|
1817
1892
|
end
|
|
1818
1893
|
|
|
1819
1894
|
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 ==
|
|
1895
|
+
@ds.literal(@ds.from(:t___a).first_source_table).should == "t"
|
|
1896
|
+
@ds.literal(@ds.from(:s__t___a).first_source_table).should == "s.t"
|
|
1897
|
+
@ds.literal(@ds.from(:t.as(:a)).first_source_table).should == "t"
|
|
1823
1898
|
end
|
|
1824
1899
|
|
|
1825
1900
|
specify "should raise exception if table doesn't have a source" do
|
|
@@ -1849,25 +1924,31 @@ describe "Dataset#from_self" do
|
|
|
1849
1924
|
'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
|
|
1850
1925
|
end
|
|
1851
1926
|
|
|
1852
|
-
specify "should not options such as server" do
|
|
1927
|
+
specify "should not remove non-SQL options such as :server" do
|
|
1853
1928
|
@ds.server(:blah).from_self(:alias=>:some_name).opts[:server].should == :blah
|
|
1854
1929
|
end
|
|
1855
1930
|
|
|
1931
|
+
specify "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
|
|
1932
|
+
ds = Sequel::Dataset.new(nil)
|
|
1933
|
+
ds.meta_def(:supports_cte?){true}
|
|
1934
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
1935
|
+
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'
|
|
1936
|
+
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'
|
|
1937
|
+
end
|
|
1856
1938
|
end
|
|
1857
1939
|
|
|
1858
1940
|
describe "Dataset#join_table" do
|
|
1859
1941
|
before do
|
|
1860
|
-
@d =
|
|
1942
|
+
@d = Sequel::Dataset.new(nil).from(:items)
|
|
1861
1943
|
@d.quote_identifiers = true
|
|
1862
1944
|
end
|
|
1863
1945
|
|
|
1864
1946
|
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")'
|
|
1947
|
+
@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
1948
|
end
|
|
1868
1949
|
|
|
1869
1950
|
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 ==
|
|
1951
|
+
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
|
1871
1952
|
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND ("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100))'
|
|
1872
1953
|
end
|
|
1873
1954
|
|
|
@@ -1877,45 +1958,30 @@ describe "Dataset#join_table" do
|
|
|
1877
1958
|
end
|
|
1878
1959
|
|
|
1879
1960
|
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"'
|
|
1961
|
+
@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
1962
|
end
|
|
1883
1963
|
|
|
1884
1964
|
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")'
|
|
1965
|
+
@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
1966
|
end
|
|
1888
1967
|
|
|
1889
1968
|
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")'
|
|
1969
|
+
@d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1892
1970
|
end
|
|
1893
1971
|
|
|
1894
1972
|
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"'
|
|
1973
|
+
@d.left_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1974
|
+
@d.right_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1975
|
+
@d.full_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1976
|
+
@d.inner_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1977
|
+
@d.left_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1978
|
+
@d.right_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1979
|
+
@d.full_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1980
|
+
@d.natural_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
1981
|
+
@d.natural_left_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
|
|
1982
|
+
@d.natural_right_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
|
|
1983
|
+
@d.natural_full_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
|
|
1984
|
+
@d.cross_join(:categories).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
1919
1985
|
end
|
|
1920
1986
|
|
|
1921
1987
|
specify "should raise an error if additional arguments are provided to join methods that don't take conditions" do
|
|
@@ -1935,95 +2001,68 @@ describe "Dataset#join_table" do
|
|
|
1935
2001
|
end
|
|
1936
2002
|
|
|
1937
2003
|
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")'
|
|
2004
|
+
@d.join_table(nil, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1940
2005
|
end
|
|
1941
2006
|
|
|
1942
2007
|
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")'
|
|
2008
|
+
@d.join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1945
2009
|
end
|
|
1946
2010
|
|
|
1947
2011
|
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")'
|
|
2012
|
+
@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
2013
|
end
|
|
1951
2014
|
|
|
1952
2015
|
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")'
|
|
2016
|
+
@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
2017
|
end
|
|
1956
2018
|
|
|
1957
2019
|
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")'
|
|
2020
|
+
@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
2021
|
end
|
|
1961
2022
|
|
|
1962
2023
|
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")'
|
|
2024
|
+
@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
2025
|
end
|
|
1968
2026
|
|
|
1969
2027
|
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")'
|
|
2028
|
+
@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
2029
|
end
|
|
1973
2030
|
|
|
1974
2031
|
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")'
|
|
2032
|
+
@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")'
|
|
2033
|
+
@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
2034
|
end
|
|
1980
2035
|
|
|
1981
2036
|
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")'
|
|
2037
|
+
@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
2038
|
end
|
|
1985
2039
|
|
|
1986
2040
|
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")'
|
|
2041
|
+
@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
2042
|
end
|
|
1990
2043
|
|
|
1991
2044
|
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))'
|
|
2045
|
+
@d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
|
2046
|
+
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
|
2047
|
+
@d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
|
2048
|
+
@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
2049
|
end
|
|
2001
2050
|
|
|
2002
2051
|
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)
|
|
2052
|
+
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.should raise_error(Sequel::Error)
|
|
2005
2053
|
end
|
|
2006
2054
|
|
|
2007
2055
|
specify "should support joining datasets" do
|
|
2008
2056
|
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
|
-
|
|
2057
|
+
@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
2058
|
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")'
|
|
2059
|
+
@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")'
|
|
2060
|
+
@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
2061
|
end
|
|
2021
2062
|
|
|
2022
2063
|
specify "should support joining datasets and aliasing the join" do
|
|
2023
2064
|
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")'
|
|
2065
|
+
@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
2066
|
end
|
|
2028
2067
|
|
|
2029
2068
|
specify "should support joining multiple datasets" do
|
|
@@ -2040,40 +2079,30 @@ describe "Dataset#join_table" do
|
|
|
2040
2079
|
specify "should support joining objects that respond to :table_name" do
|
|
2041
2080
|
ds = Object.new
|
|
2042
2081
|
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")'
|
|
2082
|
+
@d.join(ds, :item_id => :id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
|
|
2046
2083
|
end
|
|
2047
2084
|
|
|
2048
|
-
specify "should support using
|
|
2049
|
-
@d.join(:categories,
|
|
2050
|
-
'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
|
2085
|
+
specify "should support using an SQL String as the join condition" do
|
|
2086
|
+
@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
2087
|
end
|
|
2052
2088
|
|
|
2053
2089
|
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"'
|
|
2090
|
+
@d.join(:categories, :active).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
|
2056
2091
|
end
|
|
2057
2092
|
|
|
2058
2093
|
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)'
|
|
2094
|
+
@d.join(:categories, :number.sql_number > 10).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2061
2095
|
end
|
|
2062
2096
|
|
|
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"'
|
|
2097
|
+
specify "should support natural and cross joins" do
|
|
2098
|
+
@d.join_table(:natural, :categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2099
|
+
@d.join_table(:cross, :categories, nil).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2100
|
+
@d.join_table(:natural, :categories, nil, :c).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
|
2070
2101
|
end
|
|
2071
2102
|
|
|
2072
2103
|
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")'
|
|
2104
|
+
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
|
|
2105
|
+
@d.join(:categories, [:id1, :id2]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
|
2077
2106
|
end
|
|
2078
2107
|
|
|
2079
2108
|
specify "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
|
|
@@ -2081,6 +2110,12 @@ describe "Dataset#join_table" do
|
|
|
2081
2110
|
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."id" = "items"."id")'
|
|
2082
2111
|
end
|
|
2083
2112
|
|
|
2113
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
2114
|
+
@d.meta_def(:supports_cte?){true}
|
|
2115
|
+
@d.meta_def(:supports_cte_in_subselect?){false}
|
|
2116
|
+
@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")'
|
|
2117
|
+
end
|
|
2118
|
+
|
|
2084
2119
|
specify "should raise an error if using an array of symbols with a block" do
|
|
2085
2120
|
proc{@d.join(:categories, [:id]){|j,lj,js|}}.should raise_error(Sequel::Error)
|
|
2086
2121
|
end
|
|
@@ -2135,27 +2170,21 @@ describe "Dataset#join_table" do
|
|
|
2135
2170
|
end
|
|
2136
2171
|
|
|
2137
2172
|
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")'
|
|
2173
|
+
@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")'
|
|
2174
|
+
@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
2175
|
end
|
|
2143
2176
|
|
|
2144
2177
|
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"))'
|
|
2178
|
+
@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"))'
|
|
2179
|
+
@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
2180
|
end
|
|
2150
2181
|
|
|
2151
2182
|
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")'
|
|
2183
|
+
@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
2184
|
@d.from(:items.as(:i)).join(:categories.as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
|
|
2155
2185
|
'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2156
2186
|
end
|
|
2157
2187
|
|
|
2158
|
-
|
|
2159
2188
|
specify "should not allow insert, update, delete, or truncate" do
|
|
2160
2189
|
proc{@d.join(:categories, :a=>:d).insert_sql}.should raise_error(Sequel::InvalidOperation)
|
|
2161
2190
|
proc{@d.join(:categories, :a=>:d).update_sql(:a=>1)}.should raise_error(Sequel::InvalidOperation)
|
|
@@ -2170,81 +2199,52 @@ describe "Dataset#join_table" do
|
|
|
2170
2199
|
end
|
|
2171
2200
|
|
|
2172
2201
|
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
2202
|
specify "should perform an update on the specified filter" do
|
|
2188
|
-
|
|
2189
|
-
|
|
2203
|
+
db = Sequel.mock
|
|
2204
|
+
ds = db[:items]
|
|
2205
|
+
ds[:a => 1] = {:x => 3}
|
|
2206
|
+
db.sqls.should == ['UPDATE items SET x = 3 WHERE (a = 1)']
|
|
2190
2207
|
end
|
|
2191
2208
|
end
|
|
2192
2209
|
|
|
2193
2210
|
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
2211
|
specify "should act as alias to #update" do
|
|
2209
|
-
|
|
2210
|
-
|
|
2212
|
+
db = Sequel.mock
|
|
2213
|
+
ds = db[:items]
|
|
2214
|
+
ds.set({:x => 3})
|
|
2215
|
+
db.sqls.should == ['UPDATE items SET x = 3']
|
|
2211
2216
|
end
|
|
2212
2217
|
end
|
|
2213
2218
|
|
|
2214
|
-
|
|
2215
2219
|
describe "Dataset#insert_multiple" do
|
|
2216
2220
|
before do
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
def insert(arg)
|
|
2220
|
-
@inserts ||= []
|
|
2221
|
-
@inserts << arg
|
|
2222
|
-
end
|
|
2223
|
-
end
|
|
2224
|
-
|
|
2225
|
-
@d = c.new(nil)
|
|
2221
|
+
@db = Sequel.mock(:autoid=>2)
|
|
2222
|
+
@ds = @db[:items]
|
|
2226
2223
|
end
|
|
2227
2224
|
|
|
2228
2225
|
specify "should insert all items in the supplied array" do
|
|
2229
|
-
@
|
|
2230
|
-
@
|
|
2226
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}])
|
|
2227
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('aa')",
|
|
2228
|
+
"INSERT INTO items VALUES (5)",
|
|
2229
|
+
"INSERT INTO items VALUES (3)",
|
|
2230
|
+
"INSERT INTO items (a) VALUES (2)"]
|
|
2231
2231
|
end
|
|
2232
2232
|
|
|
2233
2233
|
specify "should pass array items through the supplied block if given" do
|
|
2234
|
-
|
|
2235
|
-
@
|
|
2236
|
-
|
|
2234
|
+
@ds.insert_multiple(["inevitable", "hello", "the ticking clock"]){|i| i.gsub('l', 'r')}
|
|
2235
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('inevitabre')",
|
|
2236
|
+
"INSERT INTO items VALUES ('herro')",
|
|
2237
|
+
"INSERT INTO items VALUES ('the ticking crock')"]
|
|
2238
|
+
end
|
|
2239
|
+
|
|
2240
|
+
specify "should return array of inserted ids" do
|
|
2241
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}]).should == [2, 3, 4, 5]
|
|
2237
2242
|
end
|
|
2238
2243
|
end
|
|
2239
2244
|
|
|
2240
2245
|
describe "Dataset aggregate methods" do
|
|
2241
2246
|
before do
|
|
2242
|
-
|
|
2243
|
-
def fetch_rows(sql)
|
|
2244
|
-
yield({1 => sql})
|
|
2245
|
-
end
|
|
2246
|
-
end
|
|
2247
|
-
@d = c.new(nil).from(:test)
|
|
2247
|
+
@d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
|
|
2248
2248
|
end
|
|
2249
2249
|
|
|
2250
2250
|
specify "should include min" do
|
|
@@ -2278,116 +2278,88 @@ end
|
|
|
2278
2278
|
|
|
2279
2279
|
describe "Dataset#range" do
|
|
2280
2280
|
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)
|
|
2281
|
+
@db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
|
|
2282
|
+
@ds = @db[:test]
|
|
2292
2283
|
end
|
|
2293
2284
|
|
|
2294
2285
|
specify "should generate a correct SQL statement" do
|
|
2295
|
-
@
|
|
2296
|
-
@
|
|
2286
|
+
@ds.range(:stamp)
|
|
2287
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
|
|
2297
2288
|
|
|
2298
|
-
@
|
|
2299
|
-
@
|
|
2289
|
+
@ds.filter(:price.sql_number > 100).range(:stamp)
|
|
2290
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
|
|
2300
2291
|
end
|
|
2301
2292
|
|
|
2302
2293
|
specify "should return a range object" do
|
|
2303
|
-
@
|
|
2294
|
+
@ds.range(:tryme).should == (1..10)
|
|
2304
2295
|
end
|
|
2305
2296
|
|
|
2306
2297
|
specify "should use a subselect for the same conditions as count" do
|
|
2307
|
-
@
|
|
2308
|
-
@
|
|
2298
|
+
@ds.order(:stamp).limit(5).range(:stamp).should == (1..10)
|
|
2299
|
+
@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
2300
|
end
|
|
2310
2301
|
end
|
|
2311
2302
|
|
|
2312
2303
|
describe "Dataset#interval" do
|
|
2313
2304
|
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)
|
|
2305
|
+
@db = Sequel.mock(:fetch=>{:v => 1234})
|
|
2306
|
+
@ds = @db[:test]
|
|
2325
2307
|
end
|
|
2326
2308
|
|
|
2327
|
-
specify "should generate
|
|
2328
|
-
@
|
|
2329
|
-
@
|
|
2309
|
+
specify "should generate the correct SQL statement" do
|
|
2310
|
+
@ds.interval(:stamp)
|
|
2311
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"]
|
|
2330
2312
|
|
|
2331
|
-
@
|
|
2332
|
-
@
|
|
2333
|
-
end
|
|
2334
|
-
|
|
2335
|
-
specify "should return an integer" do
|
|
2336
|
-
@d.interval(:tryme).should == 1234
|
|
2313
|
+
@ds.filter(:price.sql_number > 100).interval(:stamp)
|
|
2314
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"]
|
|
2337
2315
|
end
|
|
2338
2316
|
|
|
2339
2317
|
specify "should use a subselect for the same conditions as count" do
|
|
2340
|
-
@
|
|
2341
|
-
@
|
|
2318
|
+
@ds.order(:stamp).limit(5).interval(:stamp).should == 1234
|
|
2319
|
+
@db.sqls.should == ['SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
|
|
2342
2320
|
end
|
|
2343
2321
|
end
|
|
2344
2322
|
|
|
2345
2323
|
describe "Dataset #first and #last" do
|
|
2346
2324
|
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)
|
|
2325
|
+
@db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
|
|
2326
|
+
@d = @db[:test]
|
|
2355
2327
|
end
|
|
2356
2328
|
|
|
2357
2329
|
specify "should return a single record if no argument is given" do
|
|
2358
|
-
@d.order(:a).first.should ==
|
|
2359
|
-
@d.order(:a).last.should ==
|
|
2330
|
+
@d.order(:a).first.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
|
|
2331
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2360
2332
|
end
|
|
2361
2333
|
|
|
2362
2334
|
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 ==
|
|
2335
|
+
@d.order(:a).first(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
|
|
2336
|
+
@d.order(:a).first('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
|
|
2337
|
+
@d.order(:a).last(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1'}
|
|
2338
|
+
@d.order(:a).last('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1'}
|
|
2367
2339
|
end
|
|
2368
2340
|
|
|
2369
2341
|
specify "should set the limit and return an array of records if the given number is > 1" do
|
|
2370
2342
|
i = rand(10) + 10
|
|
2371
|
-
r = @d.order(:a).first(i).should == [
|
|
2343
|
+
r = @d.order(:a).first(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
|
|
2372
2344
|
i = rand(10) + 10
|
|
2373
|
-
r = @d.order(:a).last(i).should == [
|
|
2345
|
+
r = @d.order(:a).last(i).should == [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
|
|
2374
2346
|
end
|
|
2375
2347
|
|
|
2376
2348
|
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 ==
|
|
2349
|
+
@d.first{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
|
|
2350
|
+
@d.order(:name).last{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1'}
|
|
2379
2351
|
end
|
|
2380
2352
|
|
|
2381
2353
|
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 ==
|
|
2354
|
+
@d.first(:y=>25){:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
|
|
2355
|
+
@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
2356
|
end
|
|
2385
2357
|
|
|
2386
2358
|
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
|
2387
2359
|
i = rand(10) + 10
|
|
2388
|
-
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [
|
|
2360
|
+
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
|
|
2389
2361
|
i = rand(10) + 10
|
|
2390
|
-
r = @d.order(:a).last(i){:z.sql_number > 26}.should == [
|
|
2362
|
+
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
2363
|
end
|
|
2392
2364
|
|
|
2393
2365
|
specify "#last should raise if no order is given" do
|
|
@@ -2398,10 +2370,10 @@ describe "Dataset #first and #last" do
|
|
|
2398
2370
|
end
|
|
2399
2371
|
|
|
2400
2372
|
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.
|
|
2373
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2374
|
+
@d.order(:b.desc).last.should == {:s=>'SELECT * FROM test ORDER BY b ASC LIMIT 1'}
|
|
2375
|
+
@d.order(:c, :d).last.should == {:s=>'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'}
|
|
2376
|
+
@d.order(:e.desc, :f).last.should == {:s=>'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'}
|
|
2405
2377
|
end
|
|
2406
2378
|
end
|
|
2407
2379
|
|
|
@@ -2412,55 +2384,37 @@ describe "Dataset compound operations" do
|
|
|
2412
2384
|
end
|
|
2413
2385
|
|
|
2414
2386
|
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"
|
|
2387
|
+
@a.union(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2388
|
+
@b.union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2389
|
+
@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
2390
|
end
|
|
2422
2391
|
|
|
2423
2392
|
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"
|
|
2393
|
+
@a.intersect(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2394
|
+
@b.intersect(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2395
|
+
@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
2396
|
end
|
|
2431
2397
|
|
|
2432
2398
|
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"
|
|
2399
|
+
@a.except(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2400
|
+
@b.except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2401
|
+
@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
2402
|
end
|
|
2440
2403
|
|
|
2441
2404
|
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"
|
|
2405
|
+
@a.union(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2406
|
+
@a.intersect(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2407
|
+
@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
2408
|
end
|
|
2449
2409
|
|
|
2450
2410
|
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)"
|
|
2411
|
+
@b.union(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
|
|
2412
|
+
@b.intersect(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
|
|
2413
|
+
@b.except(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
|
|
2457
2414
|
|
|
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)"
|
|
2415
|
+
@b.union(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
|
|
2416
|
+
@b.intersect(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2417
|
+
@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
2418
|
end
|
|
2465
2419
|
|
|
2466
2420
|
specify "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
|
|
@@ -2480,141 +2434,105 @@ describe "Dataset compound operations" do
|
|
|
2480
2434
|
end
|
|
2481
2435
|
|
|
2482
2436
|
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"
|
|
2437
|
+
@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"
|
|
2438
|
+
@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"
|
|
2439
|
+
@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
2440
|
end
|
|
2490
2441
|
|
|
2491
2442
|
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"
|
|
2443
|
+
@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"
|
|
2444
|
+
@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"
|
|
2445
|
+
@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
2446
|
end
|
|
2499
2447
|
|
|
2500
2448
|
specify "should order and limit properly when using UNION, INTERSECT, or EXCEPT" do
|
|
2501
2449
|
@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"
|
|
2450
|
+
@dataset.union(@dataset).limit(2).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
|
|
2451
|
+
@dataset.limit(2).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2452
|
+
@dataset.except(@dataset.limit(2)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
|
|
2453
|
+
|
|
2454
|
+
@dataset.union(@dataset).order(:num).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
|
|
2455
|
+
@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"
|
|
2456
|
+
@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
2457
|
|
|
2516
2458
|
@dataset.limit(2).order(:a).union(@dataset.limit(3).order(:b)).order(:c).limit(4).sql.should ==
|
|
2517
2459
|
"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
2460
|
end
|
|
2519
2461
|
|
|
2462
|
+
specify "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
|
|
2463
|
+
ds = Sequel::Dataset.new(nil)
|
|
2464
|
+
ds.meta_def(:supports_cte?){true}
|
|
2465
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2466
|
+
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'
|
|
2467
|
+
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'
|
|
2468
|
+
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'
|
|
2469
|
+
end
|
|
2520
2470
|
end
|
|
2521
2471
|
|
|
2522
2472
|
describe "Dataset#[]" do
|
|
2523
2473
|
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)
|
|
2474
|
+
@db = Sequel.mock(:fetch=>{1 => 2, 3 => 4})
|
|
2475
|
+
@d = @db[:items]
|
|
2537
2476
|
end
|
|
2538
2477
|
|
|
2539
2478
|
specify "should return a single record filtered according to the given conditions" do
|
|
2540
2479
|
@d[:name => 'didi'].should == {1 => 2, 3 => 4}
|
|
2541
|
-
@
|
|
2480
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (name = 'didi') LIMIT 1"]
|
|
2542
2481
|
|
|
2543
2482
|
@d[:id => 5..45].should == {1 => 2, 3 => 4}
|
|
2544
|
-
@
|
|
2483
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((id >= 5) AND (id <= 45)) LIMIT 1"]
|
|
2545
2484
|
end
|
|
2546
2485
|
end
|
|
2547
2486
|
|
|
2548
2487
|
describe "Dataset#single_record" do
|
|
2549
2488
|
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)
|
|
2489
|
+
@db = Sequel.mock
|
|
2561
2490
|
end
|
|
2562
2491
|
|
|
2563
2492
|
specify "should call each with a limit of 1 and return the record" do
|
|
2564
|
-
@
|
|
2493
|
+
@db.fetch = {:a=>1}
|
|
2494
|
+
@db[:test].single_record.should == {:a=>1}
|
|
2495
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2565
2496
|
end
|
|
2566
2497
|
|
|
2567
2498
|
specify "should return nil if no record is present" do
|
|
2568
|
-
@
|
|
2499
|
+
@db[:test].single_record.should be_nil
|
|
2500
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2569
2501
|
end
|
|
2570
2502
|
end
|
|
2571
2503
|
|
|
2572
2504
|
describe "Dataset#single_value" do
|
|
2573
2505
|
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)
|
|
2506
|
+
@db = Sequel.mock
|
|
2585
2507
|
end
|
|
2586
2508
|
|
|
2587
2509
|
specify "should call each and return the first value of the first record" do
|
|
2588
|
-
@
|
|
2510
|
+
@db.fetch = {:a=>1}
|
|
2511
|
+
@db[:test].single_value.should == 1
|
|
2512
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2589
2513
|
end
|
|
2590
2514
|
|
|
2591
2515
|
specify "should return nil if no records" do
|
|
2592
|
-
@
|
|
2516
|
+
@db[:test].single_value.should be_nil
|
|
2517
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2593
2518
|
end
|
|
2594
2519
|
|
|
2595
2520
|
it "should work on a graphed_dataset" do
|
|
2596
|
-
@
|
|
2597
|
-
@
|
|
2521
|
+
@db.fetch = {:a=>1}
|
|
2522
|
+
ds = @db[:test].columns(:a)
|
|
2523
|
+
ds.graph(ds, [:a], :table_alias=>:test2).single_value.should == 1
|
|
2524
|
+
@db.sqls.should == ['SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
2598
2525
|
end
|
|
2599
2526
|
end
|
|
2600
2527
|
|
|
2601
2528
|
describe "Dataset#get" do
|
|
2602
2529
|
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)
|
|
2530
|
+
@d = Sequel.mock(:fetch=>proc{|s| {:name=>s}})[:test]
|
|
2613
2531
|
end
|
|
2614
2532
|
|
|
2615
2533
|
specify "should select the specified column and fetch its value" do
|
|
2616
2534
|
@d.get(:name).should == "SELECT name FROM test LIMIT 1"
|
|
2617
|
-
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2535
|
+
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2618
2536
|
end
|
|
2619
2537
|
|
|
2620
2538
|
specify "should work with filters" do
|
|
@@ -2637,239 +2555,244 @@ end
|
|
|
2637
2555
|
|
|
2638
2556
|
describe "Dataset#set_row_proc" do
|
|
2639
2557
|
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)
|
|
2558
|
+
@db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
|
|
2559
|
+
@dataset = @db[:items]
|
|
2560
|
+
@dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
|
|
2647
2561
|
end
|
|
2648
2562
|
|
|
2649
2563
|
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
2564
|
rows = @dataset.all
|
|
2653
|
-
rows.
|
|
2654
|
-
|
|
2655
|
-
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
|
2565
|
+
rows.map{|h| h[:der]}.should == [3, 4]
|
|
2566
|
+
@db.sqls.should == ['SELECT * FROM items']
|
|
2656
2567
|
end
|
|
2657
2568
|
|
|
2658
2569
|
specify "should be copied over when dataset is cloned" do
|
|
2659
|
-
@dataset.
|
|
2660
|
-
|
|
2661
|
-
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
|
2570
|
+
@dataset.filter(:a => 1).all.should == [{:a=>1, :der=>3}, {:a=>2, :der=>4}]
|
|
2662
2571
|
end
|
|
2663
2572
|
end
|
|
2664
2573
|
|
|
2665
2574
|
describe "Dataset#<<" do
|
|
2666
2575
|
before do
|
|
2667
|
-
@
|
|
2668
|
-
@d.meta_def(:insert) do |*args|
|
|
2669
|
-
1234567890
|
|
2670
|
-
end
|
|
2576
|
+
@db = Sequel.mock
|
|
2671
2577
|
end
|
|
2672
|
-
|
|
2578
|
+
|
|
2673
2579
|
specify "should call #insert" do
|
|
2674
|
-
|
|
2580
|
+
@db[:items] << {:name => 1}
|
|
2581
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)']
|
|
2582
|
+
end
|
|
2583
|
+
|
|
2584
|
+
specify "should be chainable" do
|
|
2585
|
+
@db[:items] << {:name => 1} << @db[:old_items].select(:name)
|
|
2586
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)', 'INSERT INTO items SELECT name FROM old_items']
|
|
2675
2587
|
end
|
|
2676
2588
|
end
|
|
2677
2589
|
|
|
2678
2590
|
describe "Dataset#columns" do
|
|
2679
2591
|
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}
|
|
2592
|
+
@dataset = Sequel.mock[:items]
|
|
2684
2593
|
end
|
|
2685
2594
|
|
|
2686
2595
|
specify "should return the value of @columns if @columns is not nil" do
|
|
2687
|
-
@dataset.columns
|
|
2688
|
-
@dataset.
|
|
2596
|
+
@dataset.columns(:a, :b, :c).columns.should == [:a, :b, :c]
|
|
2597
|
+
@dataset.db.sqls.should == []
|
|
2689
2598
|
end
|
|
2690
2599
|
|
|
2691
2600
|
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
|
-
|
|
2601
|
+
@dataset.db.columns = [:a]
|
|
2602
|
+
@dataset.columns.should == [:a]
|
|
2603
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2604
|
+
end
|
|
2605
|
+
|
|
2606
|
+
specify "should be cleared if you change the selected columns" do
|
|
2607
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2608
|
+
@dataset.columns.should == [:a]
|
|
2609
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2610
|
+
@dataset.columns.should == [:a]
|
|
2611
|
+
@dataset.db.sqls.should == []
|
|
2612
|
+
ds = @dataset.select{foo{}}
|
|
2613
|
+
ds.columns.should == [:b]
|
|
2614
|
+
@dataset.db.sqls.should == ['SELECT foo() FROM items LIMIT 1']
|
|
2615
|
+
end
|
|
2616
|
+
|
|
2617
|
+
specify "should be cleared if you change the FROM table" do
|
|
2618
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2619
|
+
@dataset.columns.should == [:a]
|
|
2620
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2621
|
+
ds = @dataset.from(:foo)
|
|
2622
|
+
ds.columns.should == [:b]
|
|
2623
|
+
@dataset.db.sqls.should == ['SELECT * FROM foo LIMIT 1']
|
|
2624
|
+
end
|
|
2625
|
+
|
|
2626
|
+
specify "should be cleared if you join a table to the dataset" do
|
|
2627
|
+
@dataset.db.columns = [[:a], [:a, :b]]
|
|
2628
|
+
@dataset.columns.should == [:a]
|
|
2629
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2630
|
+
ds = @dataset.cross_join(:foo)
|
|
2631
|
+
ds.columns.should == [:a, :b]
|
|
2632
|
+
@dataset.db.sqls.should == ['SELECT * FROM items CROSS JOIN foo LIMIT 1']
|
|
2633
|
+
end
|
|
2634
|
+
|
|
2635
|
+
specify "should be cleared if you set custom SQL for the dataset" do
|
|
2636
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2637
|
+
@dataset.columns.should == [:a]
|
|
2638
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2639
|
+
ds = @dataset.with_sql('SELECT b FROM foo')
|
|
2640
|
+
ds.columns.should == [:b]
|
|
2641
|
+
@dataset.db.sqls.should == ['SELECT b FROM foo']
|
|
2696
2642
|
end
|
|
2697
2643
|
|
|
2698
2644
|
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
|
2645
|
+
@dataset.db.columns = [:a]
|
|
2699
2646
|
@dataset.filter!(:b=>100).order!(:b).distinct!
|
|
2700
|
-
@dataset.columns
|
|
2701
|
-
@dataset.
|
|
2647
|
+
@dataset.columns.should == [:a]
|
|
2648
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2702
2649
|
end
|
|
2703
2650
|
end
|
|
2704
2651
|
|
|
2705
2652
|
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
2653
|
specify "should always attempt to get a record and return @columns" do
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2654
|
+
ds = Sequel.mock(:columns=>[[:a, :b, :c], [:d, :e, :f]])[:items]
|
|
2655
|
+
ds.columns!.should == [:a, :b, :c]
|
|
2656
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2657
|
+
ds.columns!.should == [:d, :e, :f]
|
|
2658
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2717
2659
|
end
|
|
2718
2660
|
end
|
|
2719
2661
|
|
|
2720
2662
|
describe "Dataset#import" do
|
|
2721
2663
|
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'}]
|
|
2664
|
+
@db = Sequel.mock
|
|
2665
|
+
@ds = @db[:items]
|
|
2743
2666
|
end
|
|
2744
2667
|
|
|
2668
|
+
specify "should return nil without a query if no values" do
|
|
2669
|
+
@ds.import(['x', 'y'], []).should == nil
|
|
2670
|
+
@db.sqls.should == []
|
|
2671
|
+
end
|
|
2672
|
+
|
|
2745
2673
|
specify "should accept string keys as column names" do
|
|
2746
2674
|
@ds.import(['x', 'y'], [[1, 2], [3, 4]])
|
|
2747
|
-
@db.sqls.should == [
|
|
2748
|
-
'BEGIN',
|
|
2675
|
+
@db.sqls.should == ['BEGIN',
|
|
2749
2676
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2750
2677
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2751
|
-
'COMMIT'
|
|
2752
|
-
]
|
|
2678
|
+
'COMMIT']
|
|
2753
2679
|
end
|
|
2754
2680
|
|
|
2755
2681
|
specify "should accept a columns array and a values array" do
|
|
2756
2682
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
2757
|
-
@db.sqls.should == [
|
|
2758
|
-
'BEGIN',
|
|
2683
|
+
@db.sqls.should == ['BEGIN',
|
|
2759
2684
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2760
2685
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2761
|
-
'COMMIT'
|
|
2762
|
-
]
|
|
2686
|
+
'COMMIT']
|
|
2763
2687
|
end
|
|
2764
2688
|
|
|
2765
2689
|
specify "should accept a columns array and a dataset" do
|
|
2766
|
-
@ds2 =
|
|
2690
|
+
@ds2 = @ds.from(:cats).filter(:purr => true).select(:a, :b)
|
|
2767
2691
|
|
|
2768
2692
|
@ds.import([:x, :y], @ds2)
|
|
2769
|
-
@db.sqls.should == [
|
|
2770
|
-
'BEGIN',
|
|
2693
|
+
@db.sqls.should == ['BEGIN',
|
|
2771
2694
|
"INSERT INTO items (x, y) SELECT a, b FROM cats WHERE (purr IS TRUE)",
|
|
2772
|
-
'COMMIT'
|
|
2773
|
-
]
|
|
2695
|
+
'COMMIT']
|
|
2774
2696
|
end
|
|
2775
2697
|
|
|
2776
2698
|
specify "should accept a columns array and a values array with :commit_every option" do
|
|
2777
2699
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 3)
|
|
2778
|
-
@db.sqls.should == [
|
|
2779
|
-
'BEGIN',
|
|
2700
|
+
@db.sqls.should == ['BEGIN',
|
|
2780
2701
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2781
2702
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2782
2703
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2783
|
-
'COMMIT'
|
|
2784
|
-
]
|
|
2704
|
+
'COMMIT']
|
|
2785
2705
|
end
|
|
2786
|
-
specify "should accept a columns array and a values array with slice option" do
|
|
2706
|
+
specify "should accept a columns array and a values array with :slice option" do
|
|
2787
2707
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
|
2788
|
-
@db.sqls.should == [
|
|
2789
|
-
'BEGIN',
|
|
2708
|
+
@db.sqls.should == ['BEGIN',
|
|
2790
2709
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2791
2710
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2792
2711
|
'COMMIT',
|
|
2793
2712
|
'BEGIN',
|
|
2794
2713
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2795
|
-
'COMMIT'
|
|
2796
|
-
]
|
|
2714
|
+
'COMMIT']
|
|
2797
2715
|
end
|
|
2798
2716
|
end
|
|
2799
2717
|
|
|
2800
2718
|
describe "Dataset#multi_insert" do
|
|
2801
2719
|
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
|
-
|
|
2720
|
+
@db = Sequel.mock(:servers=>{:s1=>{}})
|
|
2721
|
+
@ds = @db[:items]
|
|
2822
2722
|
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
|
2823
2723
|
end
|
|
2824
2724
|
|
|
2725
|
+
specify "should return nil without a query if no values" do
|
|
2726
|
+
@ds.multi_insert([]).should == nil
|
|
2727
|
+
@db.sqls.should == []
|
|
2728
|
+
end
|
|
2729
|
+
|
|
2825
2730
|
specify "should issue multiple insert statements inside a transaction" do
|
|
2826
2731
|
@ds.multi_insert(@list)
|
|
2827
|
-
@db.sqls.should == [
|
|
2828
|
-
'BEGIN',
|
|
2732
|
+
@db.sqls.should == ['BEGIN',
|
|
2829
2733
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2830
2734
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2831
2735
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2832
|
-
'COMMIT'
|
|
2833
|
-
|
|
2736
|
+
'COMMIT']
|
|
2737
|
+
end
|
|
2738
|
+
|
|
2739
|
+
specify "should respect :server option" do
|
|
2740
|
+
@ds.multi_insert(@list, :server=>:s1)
|
|
2741
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2742
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2743
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2744
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2745
|
+
'COMMIT -- s1']
|
|
2746
|
+
end
|
|
2747
|
+
|
|
2748
|
+
specify "should respect existing :server option on dataset" do
|
|
2749
|
+
@ds.server(:s1).multi_insert(@list)
|
|
2750
|
+
@db.sqls.should == ['BEGIN -- s1',
|
|
2751
|
+
"INSERT INTO items (name) VALUES ('abc') -- s1",
|
|
2752
|
+
"INSERT INTO items (name) VALUES ('def') -- s1",
|
|
2753
|
+
"INSERT INTO items (name) VALUES ('ghi') -- s1",
|
|
2754
|
+
'COMMIT -- s1']
|
|
2755
|
+
end
|
|
2756
|
+
|
|
2757
|
+
specify "should respect :return=>:primary_key option" do
|
|
2758
|
+
@db.autoid = 1
|
|
2759
|
+
@ds.multi_insert(@list, :return=>:primary_key).should == [1, 2, 3]
|
|
2760
|
+
@db.sqls.should == ['BEGIN',
|
|
2761
|
+
"INSERT INTO items (name) VALUES ('abc')",
|
|
2762
|
+
"INSERT INTO items (name) VALUES ('def')",
|
|
2763
|
+
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2764
|
+
'COMMIT']
|
|
2834
2765
|
end
|
|
2835
2766
|
|
|
2836
2767
|
specify "should handle different formats for tables" do
|
|
2837
2768
|
@ds = @ds.from(:sch__tab)
|
|
2838
2769
|
@ds.multi_insert(@list)
|
|
2839
|
-
@db.sqls.should == [
|
|
2840
|
-
'BEGIN',
|
|
2770
|
+
@db.sqls.should == ['BEGIN',
|
|
2841
2771
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2842
2772
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2843
2773
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2844
|
-
'COMMIT'
|
|
2845
|
-
]
|
|
2846
|
-
@db.sqls.clear
|
|
2774
|
+
'COMMIT']
|
|
2847
2775
|
|
|
2848
2776
|
@ds = @ds.from(:tab.qualify(:sch))
|
|
2849
2777
|
@ds.multi_insert(@list)
|
|
2850
|
-
@db.sqls.should == [
|
|
2851
|
-
'BEGIN',
|
|
2778
|
+
@db.sqls.should == ['BEGIN',
|
|
2852
2779
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2853
2780
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2854
2781
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2855
|
-
'COMMIT'
|
|
2856
|
-
|
|
2857
|
-
@db.sqls.clear
|
|
2782
|
+
'COMMIT']
|
|
2783
|
+
|
|
2858
2784
|
@ds = @ds.from(:sch__tab.identifier)
|
|
2859
2785
|
@ds.multi_insert(@list)
|
|
2860
|
-
@db.sqls.should == [
|
|
2861
|
-
'BEGIN',
|
|
2786
|
+
@db.sqls.should == ['BEGIN',
|
|
2862
2787
|
"INSERT INTO sch__tab (name) VALUES ('abc')",
|
|
2863
2788
|
"INSERT INTO sch__tab (name) VALUES ('def')",
|
|
2864
2789
|
"INSERT INTO sch__tab (name) VALUES ('ghi')",
|
|
2865
|
-
'COMMIT'
|
|
2866
|
-
]
|
|
2790
|
+
'COMMIT']
|
|
2867
2791
|
end
|
|
2868
2792
|
|
|
2869
2793
|
specify "should accept the :commit_every option for committing every x records" do
|
|
2870
2794
|
@ds.multi_insert(@list, :commit_every => 1)
|
|
2871
|
-
@db.sqls.should == [
|
|
2872
|
-
'BEGIN',
|
|
2795
|
+
@db.sqls.should == ['BEGIN',
|
|
2873
2796
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2874
2797
|
'COMMIT',
|
|
2875
2798
|
'BEGIN',
|
|
@@ -2877,36 +2800,31 @@ describe "Dataset#multi_insert" do
|
|
|
2877
2800
|
'COMMIT',
|
|
2878
2801
|
'BEGIN',
|
|
2879
2802
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2880
|
-
'COMMIT'
|
|
2881
|
-
]
|
|
2803
|
+
'COMMIT']
|
|
2882
2804
|
end
|
|
2883
2805
|
|
|
2884
2806
|
specify "should accept the :slice option for committing every x records" do
|
|
2885
2807
|
@ds.multi_insert(@list, :slice => 2)
|
|
2886
|
-
@db.sqls.should == [
|
|
2887
|
-
'BEGIN',
|
|
2808
|
+
@db.sqls.should == ['BEGIN',
|
|
2888
2809
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2889
2810
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2890
2811
|
'COMMIT',
|
|
2891
2812
|
'BEGIN',
|
|
2892
2813
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2893
|
-
'COMMIT'
|
|
2894
|
-
]
|
|
2814
|
+
'COMMIT']
|
|
2895
2815
|
end
|
|
2896
2816
|
|
|
2897
2817
|
specify "should accept string keys as column names" do
|
|
2898
2818
|
@ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
|
|
2899
|
-
@db.sqls
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
'COMMIT'
|
|
2904
|
-
]
|
|
2819
|
+
sqls = @db.sqls
|
|
2820
|
+
["INSERT INTO items (x, y) VALUES (1, 2)", "INSERT INTO items (y, x) VALUES (2, 1)"].should include(sqls.slice!(1))
|
|
2821
|
+
["INSERT INTO items (x, y) VALUES (3, 4)", "INSERT INTO items (y, x) VALUES (4, 3)"].should include(sqls.slice!(1))
|
|
2822
|
+
sqls.should == ['BEGIN', 'COMMIT']
|
|
2905
2823
|
end
|
|
2906
2824
|
|
|
2907
2825
|
specify "should not do anything if no hashes are provided" do
|
|
2908
2826
|
@ds.multi_insert([])
|
|
2909
|
-
@db.sqls.should
|
|
2827
|
+
@db.sqls.should == []
|
|
2910
2828
|
end
|
|
2911
2829
|
end
|
|
2912
2830
|
|
|
@@ -2951,41 +2869,21 @@ describe "Dataset" do
|
|
|
2951
2869
|
end
|
|
2952
2870
|
|
|
2953
2871
|
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"
|
|
2872
|
+
@d.order!(:y).filter!(:y => 1).sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
|
2957
2873
|
end
|
|
2958
2874
|
end
|
|
2959
2875
|
|
|
2960
2876
|
describe "Dataset#to_csv" do
|
|
2961
2877
|
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} ]
|
|
2878
|
+
@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
2879
|
end
|
|
2980
2880
|
|
|
2981
2881
|
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"
|
|
2882
|
+
@ds.to_csv.should == "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2984
2883
|
end
|
|
2985
2884
|
|
|
2986
2885
|
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"
|
|
2886
|
+
@ds.to_csv(false).should == "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2989
2887
|
end
|
|
2990
2888
|
end
|
|
2991
2889
|
|
|
@@ -3083,66 +2981,40 @@ describe "Dataset#insert_sql" do
|
|
|
3083
2981
|
end
|
|
3084
2982
|
end
|
|
3085
2983
|
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
true
|
|
2984
|
+
describe "Dataset#inspect" do
|
|
2985
|
+
before do
|
|
2986
|
+
class ::InspectDataset < Sequel::Dataset; end
|
|
3090
2987
|
end
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
class DummyMummyDatabase < Sequel::Database
|
|
3094
|
-
attr_reader :sqls
|
|
3095
|
-
|
|
3096
|
-
def execute(sql)
|
|
3097
|
-
@sqls ||= []
|
|
3098
|
-
@sqls << sql
|
|
2988
|
+
after do
|
|
2989
|
+
Object.send(:remove_const, :InspectDataset) if defined?(::InspectDataset)
|
|
3099
2990
|
end
|
|
3100
|
-
|
|
3101
|
-
def transaction; yield; end
|
|
3102
2991
|
|
|
3103
|
-
|
|
3104
|
-
|
|
2992
|
+
specify "should include the class name and the corresponding SQL statement" do
|
|
2993
|
+
Sequel::Dataset.new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
2994
|
+
InspectDataset.new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3105
2995
|
end
|
|
3106
|
-
end
|
|
3107
2996
|
|
|
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]
|
|
2997
|
+
specify "should skip anonymous classes" do
|
|
2998
|
+
Class.new(Class.new(Sequel::Dataset)).new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
2999
|
+
Class.new(InspectDataset).new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3115
3000
|
end
|
|
3116
3001
|
end
|
|
3117
3002
|
|
|
3118
3003
|
describe "Dataset#all" do
|
|
3119
3004
|
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)
|
|
3005
|
+
@dataset = Sequel.mock(:fetch=>[{:x => 1, :y => 2}, {:x => 3, :y => 4}])[:items]
|
|
3128
3006
|
end
|
|
3129
3007
|
|
|
3130
3008
|
specify "should return an array with all records" do
|
|
3131
|
-
@dataset.all.should == [
|
|
3132
|
-
|
|
3133
|
-
{:x => 3, :y => 4},
|
|
3134
|
-
"SELECT * FROM items"
|
|
3135
|
-
]
|
|
3009
|
+
@dataset.all.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3010
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3136
3011
|
end
|
|
3137
3012
|
|
|
3138
3013
|
specify "should iterate over the array if a block is given" do
|
|
3139
3014
|
a = []
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
end
|
|
3144
|
-
|
|
3145
|
-
a.should == [1, 3, "SELECT * FROM items"]
|
|
3015
|
+
@dataset.all{|r| a << r.values_at(:x, :y)}.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
3016
|
+
a.should == [[1, 2], [3, 4]]
|
|
3017
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3146
3018
|
end
|
|
3147
3019
|
end
|
|
3148
3020
|
|
|
@@ -3152,71 +3024,56 @@ describe "Dataset#grep" do
|
|
|
3152
3024
|
end
|
|
3153
3025
|
|
|
3154
3026
|
specify "should format a SQL filter correctly" do
|
|
3155
|
-
@ds.grep(:title, 'ruby').sql.should ==
|
|
3156
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3027
|
+
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3157
3028
|
end
|
|
3158
3029
|
|
|
3159
3030
|
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'))"
|
|
3031
|
+
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
|
3162
3032
|
end
|
|
3163
3033
|
|
|
3164
3034
|
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'))"
|
|
3035
|
+
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
|
3167
3036
|
end
|
|
3168
3037
|
|
|
3169
3038
|
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'))"
|
|
3039
|
+
@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
3040
|
end
|
|
3173
3041
|
|
|
3174
3042
|
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')))"
|
|
3043
|
+
@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
3044
|
end
|
|
3178
3045
|
|
|
3179
3046
|
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')))"
|
|
3047
|
+
@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
3048
|
end
|
|
3183
3049
|
|
|
3184
3050
|
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'))"
|
|
3051
|
+
@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
3052
|
end
|
|
3188
3053
|
|
|
3189
3054
|
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'))"
|
|
3055
|
+
@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
3056
|
end
|
|
3193
3057
|
|
|
3194
3058
|
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')))"
|
|
3059
|
+
@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
3060
|
end
|
|
3198
3061
|
|
|
3199
3062
|
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')))"
|
|
3063
|
+
@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
3064
|
end
|
|
3203
3065
|
|
|
3204
3066
|
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'))"
|
|
3067
|
+
@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
3068
|
end
|
|
3208
3069
|
|
|
3209
3070
|
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'))"
|
|
3071
|
+
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
|
3072
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
|
3215
3073
|
end
|
|
3216
3074
|
|
|
3217
3075
|
specify "should support searching against other columns" do
|
|
3218
|
-
@ds.grep(:title, :body).sql.should ==
|
|
3219
|
-
"SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3076
|
+
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3220
3077
|
end
|
|
3221
3078
|
end
|
|
3222
3079
|
|
|
@@ -3270,58 +3127,63 @@ end
|
|
|
3270
3127
|
|
|
3271
3128
|
describe "Dataset prepared statements and bound variables " do
|
|
3272
3129
|
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
|
|
3130
|
+
@db = Sequel.mock
|
|
3285
3131
|
@ds = @db[:items]
|
|
3132
|
+
@ds.meta_def(:insert_sql){|*v| "#{super(*v)}#{' RETURNING *' if opts.has_key?(:returning)}" }
|
|
3286
3133
|
end
|
|
3287
3134
|
|
|
3288
3135
|
specify "#call should take a type and bind hash and interpolate it" do
|
|
3289
3136
|
@ds.filter(:num=>:$n).call(:select, :n=>1)
|
|
3137
|
+
@ds.filter(:num=>:$n).call([:map, :a], :n=>1)
|
|
3138
|
+
@ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
|
|
3290
3139
|
@ds.filter(:num=>:$n).call(:first, :n=>1)
|
|
3291
3140
|
@ds.filter(:num=>:$n).call(:delete, :n=>1)
|
|
3292
3141
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
|
3293
3142
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
|
3143
|
+
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
|
3294
3144
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3145
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3146
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3295
3147
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3296
3148
|
'DELETE FROM items WHERE (num = 1)',
|
|
3297
3149
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3298
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3150
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3151
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3299
3152
|
end
|
|
3300
3153
|
|
|
3301
3154
|
specify "#prepare should take a type and name and store it in the database for later use with call" do
|
|
3302
3155
|
pss = []
|
|
3303
3156
|
pss << @ds.filter(:num=>:$n).prepare(:select, :sn)
|
|
3157
|
+
pss << @ds.filter(:num=>:$n).prepare([:map, :a], :sm)
|
|
3158
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
|
|
3304
3159
|
pss << @ds.filter(:num=>:$n).prepare(:first, :fn)
|
|
3305
3160
|
pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
|
|
3306
3161
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
|
3307
3162
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
|
3308
|
-
@
|
|
3309
|
-
[:
|
|
3163
|
+
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
|
3164
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sh, :sm, :sn, :un]
|
|
3165
|
+
[:sn, :sm, :sh, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3310
3166
|
@db.call(:sn, :n=>1)
|
|
3167
|
+
@db.call(:sm, :n=>1)
|
|
3168
|
+
@db.call(:sh, :n=>1)
|
|
3311
3169
|
@db.call(:fn, :n=>1)
|
|
3312
3170
|
@db.call(:dn, :n=>1)
|
|
3313
3171
|
@db.call(:un, :n=>1, :n2=>2)
|
|
3314
3172
|
@db.call(:in, :n=>1)
|
|
3173
|
+
@db.call(:ins, :n=>1)
|
|
3315
3174
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3175
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3176
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3316
3177
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3317
3178
|
'DELETE FROM items WHERE (num = 1)',
|
|
3318
3179
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3319
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3180
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3181
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3320
3182
|
end
|
|
3321
3183
|
|
|
3322
3184
|
specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
|
|
3323
3185
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
|
3324
|
-
'<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3186
|
+
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3325
3187
|
end
|
|
3326
3188
|
|
|
3327
3189
|
specify "should handle literal strings" do
|
|
@@ -3329,6 +3191,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3329
3191
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
3330
3192
|
end
|
|
3331
3193
|
|
|
3194
|
+
specify "should handle columns on prepared statements correctly" do
|
|
3195
|
+
@db.columns = [:num]
|
|
3196
|
+
@ds.meta_def(:select_where_sql){|sql| super(sql); sql << " OR #{columns.first} = 1" if opts[:where]}
|
|
3197
|
+
@ds.filter(:num=>:$n).prepare(:select, :sn).sql.should == 'SELECT * FROM items WHERE (num = $n) OR num = 1'
|
|
3198
|
+
@db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
3199
|
+
end
|
|
3200
|
+
|
|
3332
3201
|
specify "should handle datasets using static sql and placeholders" do
|
|
3333
3202
|
@db["SELECT * FROM items WHERE (num = ?)", :$n].call(:select, :n=>1)
|
|
3334
3203
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
|
@@ -3357,23 +3226,16 @@ end
|
|
|
3357
3226
|
|
|
3358
3227
|
describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3359
3228
|
before do
|
|
3360
|
-
@db = Sequel
|
|
3361
|
-
@db.meta_def(:sqls){@sqls||=[]}
|
|
3362
|
-
def @db.execute(sql, opts={})
|
|
3363
|
-
sqls << [sql, *opts[:arguments]]
|
|
3364
|
-
end
|
|
3229
|
+
@db = Sequel.mock
|
|
3365
3230
|
@ds = @db[:items].filter(:num=>:$n)
|
|
3366
|
-
def @ds.fetch_rows(sql, &block)
|
|
3367
|
-
execute(sql)
|
|
3368
|
-
end
|
|
3369
3231
|
def @ds.execute(sql, opts={}, &block)
|
|
3370
|
-
|
|
3232
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3371
3233
|
end
|
|
3372
|
-
def @ds.execute_dui(
|
|
3373
|
-
|
|
3234
|
+
def @ds.execute_dui(sql, opts={}, &block)
|
|
3235
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3374
3236
|
end
|
|
3375
|
-
def @ds.execute_insert(
|
|
3376
|
-
|
|
3237
|
+
def @ds.execute_insert(sql, opts={}, &block)
|
|
3238
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3377
3239
|
end
|
|
3378
3240
|
@ps = []
|
|
3379
3241
|
@ps << @ds.prepare(:select, :s)
|
|
@@ -3386,64 +3248,43 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
|
3386
3248
|
end
|
|
3387
3249
|
|
|
3388
3250
|
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 = ?)">'
|
|
3251
|
+
@ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
|
3390
3252
|
end
|
|
3391
3253
|
|
|
3392
3254
|
specify "should submitted the SQL to the database with placeholders and bind variables" do
|
|
3393
3255
|
@ps.each{|p| p.prepared_sql; p.call(:n=>1)}
|
|
3394
|
-
@db.sqls.should == [
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
]
|
|
3256
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3257
|
+
"SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3258
|
+
"SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
|
|
3259
|
+
"DELETE FROM items WHERE (num = ?) -- args: [1]",
|
|
3260
|
+
"INSERT INTO items (num) VALUES (?) -- args: [1]",
|
|
3261
|
+
"UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
|
|
3401
3262
|
end
|
|
3402
3263
|
end
|
|
3403
3264
|
|
|
3404
3265
|
describe "Sequel::Dataset#server" do
|
|
3405
3266
|
specify "should set the server to use for the dataset" do
|
|
3406
|
-
@db = Sequel
|
|
3267
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}, :d=>{}, :u=>{}})
|
|
3407
3268
|
@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
3269
|
@ds.all
|
|
3416
3270
|
@ds.server(:i).insert(:a=>1)
|
|
3417
3271
|
@ds.server(:d).delete
|
|
3418
3272
|
@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]]
|
|
3273
|
+
@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
3274
|
end
|
|
3424
3275
|
end
|
|
3425
3276
|
|
|
3426
3277
|
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
3278
|
specify "should yield a dataset for each server" do
|
|
3279
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}})
|
|
3280
|
+
@ds = @db[:items]
|
|
3440
3281
|
@ds.each_server do |ds|
|
|
3441
3282
|
ds.should be_a_kind_of(Sequel::Dataset)
|
|
3442
3283
|
ds.should_not == @ds
|
|
3443
3284
|
ds.sql.should == @ds.sql
|
|
3444
3285
|
ds.all
|
|
3445
3286
|
end
|
|
3446
|
-
@sqls.
|
|
3287
|
+
@db.sqls.sort.should == ['SELECT * FROM items', 'SELECT * FROM items -- i', 'SELECT * FROM items -- s']
|
|
3447
3288
|
end
|
|
3448
3289
|
end
|
|
3449
3290
|
|
|
@@ -3493,23 +3334,23 @@ end
|
|
|
3493
3334
|
|
|
3494
3335
|
describe "Sequel::Dataset#qualify" do
|
|
3495
3336
|
specify "should qualify to the given table" do
|
|
3496
|
-
|
|
3337
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3497
3338
|
end
|
|
3498
3339
|
|
|
3499
3340
|
specify "should qualify to the first source if no table if given" do
|
|
3500
|
-
|
|
3341
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
|
|
3501
3342
|
end
|
|
3502
3343
|
end
|
|
3503
3344
|
|
|
3504
3345
|
describe "Sequel::Dataset#qualify_to" do
|
|
3505
3346
|
specify "should qualify to the given table" do
|
|
3506
|
-
|
|
3347
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3507
3348
|
end
|
|
3508
3349
|
end
|
|
3509
3350
|
|
|
3510
3351
|
describe "Sequel::Dataset#qualify_to_first_source" do
|
|
3511
3352
|
before do
|
|
3512
|
-
@ds =
|
|
3353
|
+
@ds = Sequel::Database.new[:t]
|
|
3513
3354
|
end
|
|
3514
3355
|
|
|
3515
3356
|
specify "should qualify_to the first source" do
|
|
@@ -3519,13 +3360,11 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3519
3360
|
end
|
|
3520
3361
|
|
|
3521
3362
|
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'
|
|
3363
|
+
@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
3364
|
end
|
|
3525
3365
|
|
|
3526
3366
|
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'
|
|
3367
|
+
@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
3368
|
end
|
|
3530
3369
|
|
|
3531
3370
|
specify "should handle hashes in select option" do
|
|
@@ -3594,14 +3433,83 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3594
3433
|
end
|
|
3595
3434
|
|
|
3596
3435
|
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
|
-
|
|
3436
|
+
@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"
|
|
3437
|
+
end
|
|
3438
|
+
end
|
|
3439
|
+
|
|
3440
|
+
describe "Sequel::Dataset#unbind" do
|
|
3441
|
+
before do
|
|
3442
|
+
@ds = Sequel::Database.new[:t]
|
|
3443
|
+
@u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
|
|
3444
|
+
end
|
|
3445
|
+
|
|
3446
|
+
specify "should unbind values assigned to equality and inequality statements" do
|
|
3447
|
+
@ds.filter(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo = $foo)"
|
|
3448
|
+
@ds.exclude(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo != $foo)"
|
|
3449
|
+
@ds.filter{foo > 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo > $foo)"
|
|
3450
|
+
@ds.filter{foo >= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo >= $foo)"
|
|
3451
|
+
@ds.filter{foo < 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo < $foo)"
|
|
3452
|
+
@ds.filter{foo <= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo <= $foo)"
|
|
3453
|
+
end
|
|
3454
|
+
|
|
3455
|
+
specify "should return variables that could be used bound to recreate the previous query" do
|
|
3456
|
+
@ds.filter(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3457
|
+
@ds.exclude(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3458
|
+
end
|
|
3459
|
+
|
|
3460
|
+
specify "should handle numerics, strings, dates, times, and datetimes" do
|
|
3461
|
+
@u[@ds.filter(:foo=>1)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1}]
|
|
3462
|
+
@u[@ds.filter(:foo=>1.0)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1.0}]
|
|
3463
|
+
@u[@ds.filter(:foo=>BigDecimal.new('1.0'))].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>BigDecimal.new('1.0')}]
|
|
3464
|
+
@u[@ds.filter(:foo=>'a')].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>'a'}]
|
|
3465
|
+
@u[@ds.filter(:foo=>Date.today)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>Date.today}]
|
|
3466
|
+
t = Time.now
|
|
3467
|
+
@u[@ds.filter(:foo=>t)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>t}]
|
|
3468
|
+
dt = DateTime.now
|
|
3469
|
+
@u[@ds.filter(:foo=>dt)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>dt}]
|
|
3470
|
+
end
|
|
3471
|
+
|
|
3472
|
+
specify "should not unbind literal strings" do
|
|
3473
|
+
@u[@ds.filter(:foo=>'a'.lit)].should == ["SELECT * FROM t WHERE (foo = a)", {}]
|
|
3474
|
+
end
|
|
3475
|
+
|
|
3476
|
+
specify "should not unbind Identifiers, QualifiedIdentifiers, or Symbols used as booleans" do
|
|
3477
|
+
@u[@ds.filter(:foo).filter{bar}.filter{foo__bar}].should == ["SELECT * FROM t WHERE (foo AND bar AND foo.bar)", {}]
|
|
3478
|
+
end
|
|
3479
|
+
|
|
3480
|
+
specify "should not unbind for values it doesn't understand" do
|
|
3481
|
+
@u[@ds.filter(:foo=>Class.new{def sql_literal(ds) 'bar' end}.new)].should == ["SELECT * FROM t WHERE (foo = bar)", {}]
|
|
3482
|
+
end
|
|
3483
|
+
|
|
3484
|
+
specify "should handle QualifiedIdentifiers" do
|
|
3485
|
+
@u[@ds.filter{foo__bar > 1}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3486
|
+
end
|
|
3487
|
+
|
|
3488
|
+
specify "should handle deep nesting" do
|
|
3489
|
+
@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}]
|
|
3490
|
+
end
|
|
3491
|
+
|
|
3492
|
+
specify "should handle JOIN ON" do
|
|
3493
|
+
@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}]
|
|
3494
|
+
end
|
|
3495
|
+
|
|
3496
|
+
specify "should raise an UnbindDuplicate exception if same variable is used with multiple different values" do
|
|
3497
|
+
proc{@ds.filter(:foo=>1).or(:foo=>2).unbind}.should raise_error(Sequel::UnbindDuplicate)
|
|
3498
|
+
end
|
|
3499
|
+
|
|
3500
|
+
specify "should handle case where the same variable has the same value in multiple places " do
|
|
3501
|
+
@u[@ds.filter(:foo=>1).or(:foo=>1)].should == ["SELECT * FROM t WHERE ((foo = $foo) OR (foo = $foo))", {:foo=>1}]
|
|
3502
|
+
end
|
|
3503
|
+
|
|
3504
|
+
specify "should raise Error for unhandled objects inside Identifiers and QualifiedIndentifiers" do
|
|
3505
|
+
proc{@ds.filter(Sequel::SQL::Identifier.new([]) > 1).unbind}.should raise_error(Sequel::Error)
|
|
3506
|
+
proc{@ds.filter{foo.qualify({}) > 1}.unbind}.should raise_error(Sequel::Error)
|
|
3599
3507
|
end
|
|
3600
3508
|
end
|
|
3601
3509
|
|
|
3602
3510
|
describe "Sequel::Dataset #with and #with_recursive" do
|
|
3603
3511
|
before do
|
|
3604
|
-
@db =
|
|
3512
|
+
@db = Sequel::Database.new
|
|
3605
3513
|
@ds = @db[:t]
|
|
3606
3514
|
end
|
|
3607
3515
|
|
|
@@ -3633,11 +3541,27 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
|
3633
3541
|
proc{@ds.with(:t, @db[:x], :args=>[:b])}.should raise_error(Sequel::Error)
|
|
3634
3542
|
proc{@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c])}.should raise_error(Sequel::Error)
|
|
3635
3543
|
end
|
|
3544
|
+
|
|
3545
|
+
specify "#with should work on insert, update, and delete statements if they support it" do
|
|
3546
|
+
[:insert, :update, :delete].each do |m|
|
|
3547
|
+
@ds.meta_def(:"#{m}_clause_methods"){[:"#{m}_with_sql"] + super()}
|
|
3548
|
+
end
|
|
3549
|
+
@ds.with(:t, @db[:x]).insert_sql(1).should == 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
|
|
3550
|
+
@ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
|
|
3551
|
+
@ds.with(:t, @db[:x]).delete_sql.should == 'WITH t AS (SELECT * FROM x) DELETE FROM t'
|
|
3552
|
+
end
|
|
3553
|
+
|
|
3554
|
+
specify "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
|
|
3555
|
+
@ds.meta_def(:supports_cte?){true}
|
|
3556
|
+
@ds.meta_def(:supports_cte_in_subselect?){false}
|
|
3557
|
+
@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'
|
|
3558
|
+
@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'
|
|
3559
|
+
end
|
|
3636
3560
|
end
|
|
3637
3561
|
|
|
3638
3562
|
describe Sequel::SQL::Constants do
|
|
3639
3563
|
before do
|
|
3640
|
-
@db =
|
|
3564
|
+
@db = Sequel::Database.new
|
|
3641
3565
|
end
|
|
3642
3566
|
|
|
3643
3567
|
it "should have CURRENT_DATE" do
|
|
@@ -3682,7 +3606,7 @@ end
|
|
|
3682
3606
|
|
|
3683
3607
|
describe "Sequel timezone support" do
|
|
3684
3608
|
before do
|
|
3685
|
-
@db =
|
|
3609
|
+
@db = Sequel::Database.new
|
|
3686
3610
|
@dataset = @db.dataset
|
|
3687
3611
|
@dataset.meta_def(:supports_timestamp_timezones?){true}
|
|
3688
3612
|
@dataset.meta_def(:supports_timestamp_usecs?){false}
|
|
@@ -3717,6 +3641,30 @@ describe "Sequel timezone support" do
|
|
|
3717
3641
|
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3718
3642
|
end
|
|
3719
3643
|
|
|
3644
|
+
specify "should have Database#timezone override Sequel.database_timezone" do
|
|
3645
|
+
Sequel.database_timezone = :local
|
|
3646
|
+
@db.timezone = :utc
|
|
3647
|
+
|
|
3648
|
+
t = Time.now
|
|
3649
|
+
s = t.getutc.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3650
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3651
|
+
|
|
3652
|
+
t = DateTime.now
|
|
3653
|
+
s = t.new_offset(0).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3654
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3655
|
+
|
|
3656
|
+
Sequel.database_timezone = :utc
|
|
3657
|
+
@db.timezone = :local
|
|
3658
|
+
|
|
3659
|
+
t = Time.now.utc
|
|
3660
|
+
s = t.getlocal.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3661
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3662
|
+
|
|
3663
|
+
t = DateTime.now.new_offset(0)
|
|
3664
|
+
s = t.new_offset(DateTime.now.offset).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3665
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3666
|
+
end
|
|
3667
|
+
|
|
3720
3668
|
specify "should handle converting database timestamps into application timestamps" do
|
|
3721
3669
|
Sequel.database_timezone = :utc
|
|
3722
3670
|
Sequel.application_timezone = :local
|
|
@@ -3827,13 +3775,7 @@ end
|
|
|
3827
3775
|
|
|
3828
3776
|
describe "Sequel::Dataset#select_map" do
|
|
3829
3777
|
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
|
|
3778
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3837
3779
|
end
|
|
3838
3780
|
|
|
3839
3781
|
specify "should do select and map in one step" do
|
|
@@ -3846,6 +3788,12 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3846
3788
|
@ds.db.sqls.should == ['SELECT a.b FROM t']
|
|
3847
3789
|
end
|
|
3848
3790
|
|
|
3791
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
3792
|
+
proc{@ds.select_map([:a.sql_function, :b])}.should raise_error(Sequel::Error)
|
|
3793
|
+
proc{@ds.select_map(:a.sql_function){b}}.should raise_error(Sequel::Error)
|
|
3794
|
+
proc{@ds.select_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
3795
|
+
end
|
|
3796
|
+
|
|
3849
3797
|
specify "should handle implicit aliases in arguments" do
|
|
3850
3798
|
@ds.select_map(:a___b).should == [1, 2]
|
|
3851
3799
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
@@ -3856,21 +3804,47 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3856
3804
|
@ds.db.sqls.should == ['SELECT a AS b FROM t']
|
|
3857
3805
|
end
|
|
3858
3806
|
|
|
3807
|
+
specify "should handle identifiers with strings" do
|
|
3808
|
+
@ds.select_map([Sequel::SQL::Identifier.new('c'), :c]).should == [[1, 1], [2, 2]]
|
|
3809
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3810
|
+
end
|
|
3811
|
+
|
|
3859
3812
|
specify "should accept a block" do
|
|
3860
3813
|
@ds.select_map{a(t__c)}.should == [1, 2]
|
|
3861
3814
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t']
|
|
3862
3815
|
end
|
|
3816
|
+
|
|
3817
|
+
specify "should accept a block with an array of columns" do
|
|
3818
|
+
@ds.select_map{[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
3819
|
+
@ds.db.sqls.should == ['SELECT a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3820
|
+
end
|
|
3821
|
+
|
|
3822
|
+
specify "should accept a block with a column" do
|
|
3823
|
+
@ds.select_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
3824
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t']
|
|
3825
|
+
end
|
|
3826
|
+
|
|
3827
|
+
specify "should accept a block and array of arguments" do
|
|
3828
|
+
@ds.select_map([:c, :c]){[a(t__c).as(c), a(t__c).as(c)]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
3829
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, a(t.c) AS c FROM t']
|
|
3830
|
+
end
|
|
3831
|
+
|
|
3832
|
+
specify "should handle an array of columns" do
|
|
3833
|
+
@ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3834
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3835
|
+
@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]]
|
|
3836
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
|
|
3837
|
+
end
|
|
3838
|
+
|
|
3839
|
+
specify "should handle an array with a single element" do
|
|
3840
|
+
@ds.select_map([:c]).should == [[1], [2]]
|
|
3841
|
+
@ds.db.sqls.should == ['SELECT c FROM t']
|
|
3842
|
+
end
|
|
3863
3843
|
end
|
|
3864
3844
|
|
|
3865
3845
|
describe "Sequel::Dataset#select_order_map" do
|
|
3866
3846
|
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
|
|
3847
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3874
3848
|
end
|
|
3875
3849
|
|
|
3876
3850
|
specify "should do select and map in one step" do
|
|
@@ -3883,6 +3857,12 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3883
3857
|
@ds.db.sqls.should == ['SELECT a.b FROM t ORDER BY a.b']
|
|
3884
3858
|
end
|
|
3885
3859
|
|
|
3860
|
+
specify "should raise if multiple arguments and can't determine alias" do
|
|
3861
|
+
proc{@ds.select_order_map([:a.sql_function, :b])}.should raise_error(Sequel::Error)
|
|
3862
|
+
proc{@ds.select_order_map(:a.sql_function){b}}.should raise_error(Sequel::Error)
|
|
3863
|
+
proc{@ds.select_order_map{[a{}, b]}}.should raise_error(Sequel::Error)
|
|
3864
|
+
end
|
|
3865
|
+
|
|
3886
3866
|
specify "should handle implicit aliases in arguments" do
|
|
3887
3867
|
@ds.select_order_map(:a___b).should == [1, 2]
|
|
3888
3868
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
@@ -3898,55 +3878,104 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3898
3878
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
3899
3879
|
end
|
|
3900
3880
|
|
|
3881
|
+
specify "should handle OrderedExpressions" do
|
|
3882
|
+
@ds.select_order_map(:a.desc).should == [1, 2]
|
|
3883
|
+
@ds.db.sqls.should == ['SELECT a FROM t ORDER BY a DESC']
|
|
3884
|
+
end
|
|
3885
|
+
|
|
3901
3886
|
specify "should accept a block" do
|
|
3902
3887
|
@ds.select_order_map{a(t__c)}.should == [1, 2]
|
|
3903
3888
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t ORDER BY a(t.c)']
|
|
3904
3889
|
end
|
|
3890
|
+
|
|
3891
|
+
specify "should accept a block with an array of columns" do
|
|
3892
|
+
@ds.select_order_map{[c.desc, a(t__c).as(c)]}.should == [[1, 1], [2, 2]]
|
|
3893
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c DESC, a(t.c)']
|
|
3894
|
+
end
|
|
3895
|
+
|
|
3896
|
+
specify "should accept a block with a column" do
|
|
3897
|
+
@ds.select_order_map(:c){a(t__c).as(c)}.should == [[1, 1], [2, 2]]
|
|
3898
|
+
@ds.db.sqls.should == ['SELECT c, a(t.c) AS c FROM t ORDER BY c, a(t.c)']
|
|
3899
|
+
end
|
|
3900
|
+
|
|
3901
|
+
specify "should accept a block and array of arguments" do
|
|
3902
|
+
@ds.select_order_map([:c, :c]){[a(t__c).as(c), c.desc]}.should == [[1, 1, 1, 1], [2, 2, 2, 2]]
|
|
3903
|
+
@ds.db.sqls.should == ['SELECT c, c, a(t.c) AS c, c FROM t ORDER BY c, c, a(t.c), c DESC']
|
|
3904
|
+
end
|
|
3905
|
+
|
|
3906
|
+
specify "should handle an array of columns" do
|
|
3907
|
+
@ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3908
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
|
|
3909
|
+
@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]]
|
|
3910
|
+
@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']
|
|
3911
|
+
end
|
|
3912
|
+
|
|
3913
|
+
specify "should handle an array with a single element" do
|
|
3914
|
+
@ds.select_order_map([:c]).should == [[1], [2]]
|
|
3915
|
+
@ds.db.sqls.should == ['SELECT c FROM t ORDER BY c']
|
|
3916
|
+
end
|
|
3905
3917
|
end
|
|
3906
3918
|
|
|
3907
3919
|
describe "Sequel::Dataset#select_hash" do
|
|
3908
3920
|
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
|
|
3921
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3922
|
+
@ds = @db[:t]
|
|
3918
3923
|
end
|
|
3919
3924
|
|
|
3920
|
-
specify "should do select and
|
|
3921
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3925
|
+
specify "should do select and to_hash in one step" do
|
|
3922
3926
|
@ds.select_hash(:a, :b).should == {1=>2, 3=>4}
|
|
3923
3927
|
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3924
3928
|
end
|
|
3925
3929
|
|
|
3926
3930
|
specify "should handle implicit qualifiers in arguments" do
|
|
3927
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3928
3931
|
@ds.select_hash(:t__a, :t__b).should == {1=>2, 3=>4}
|
|
3929
3932
|
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3930
3933
|
end
|
|
3931
3934
|
|
|
3932
3935
|
specify "should handle implicit aliases in arguments" do
|
|
3933
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3934
3936
|
@ds.select_hash(:c___a, :d___b).should == {1=>2, 3=>4}
|
|
3935
3937
|
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
3936
3938
|
end
|
|
3937
3939
|
|
|
3938
3940
|
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
3939
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3940
3941
|
@ds.select_hash(:t__c___a, :t__d___b).should == {1=>2, 3=>4}
|
|
3941
3942
|
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
3942
3943
|
end
|
|
3944
|
+
|
|
3945
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
3946
|
+
@ds.select_hash(:a.identifier, :b.identifier).should == {1=>2, 3=>4}
|
|
3947
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3948
|
+
end
|
|
3949
|
+
|
|
3950
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
3951
|
+
@ds.select_hash(:a.qualify(:t), :b.identifier.qualify(:t)).should == {1=>2, 3=>4}
|
|
3952
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3953
|
+
end
|
|
3954
|
+
|
|
3955
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
3956
|
+
@ds.select_hash(:c.as(:a), :t.as(:b)).should == {1=>2, 3=>4}
|
|
3957
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
3958
|
+
end
|
|
3959
|
+
|
|
3960
|
+
specify "should work with arrays of columns" do
|
|
3961
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
3962
|
+
@ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [4, 6]=>5}
|
|
3963
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
3964
|
+
@ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 4=>[5, 6]}
|
|
3965
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
3966
|
+
@ds.select_hash([:a, :b], [:b, :c]).should == {[1, 2]=>[2, 3], [4, 5]=>[5, 6]}
|
|
3967
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
3968
|
+
end
|
|
3969
|
+
|
|
3970
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
3971
|
+
proc{@ds.select_hash(:c.as(:a), :b.sql_function)}.should raise_error(Sequel::Error)
|
|
3972
|
+
end
|
|
3943
3973
|
end
|
|
3944
3974
|
|
|
3945
3975
|
describe "Modifying joined datasets" do
|
|
3946
3976
|
before do
|
|
3947
|
-
@ds =
|
|
3977
|
+
@ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
|
|
3948
3978
|
@ds.meta_def(:supports_modifying_joins?){true}
|
|
3949
|
-
@ds.db.reset
|
|
3950
3979
|
end
|
|
3951
3980
|
|
|
3952
3981
|
specify "should allow deleting from joined datasets" do
|
|
@@ -3962,7 +3991,7 @@ end
|
|
|
3962
3991
|
|
|
3963
3992
|
describe "Dataset#lock_style and for_update" do
|
|
3964
3993
|
before do
|
|
3965
|
-
@ds =
|
|
3994
|
+
@ds = Sequel::Dataset.new(nil).from(:t)
|
|
3966
3995
|
end
|
|
3967
3996
|
|
|
3968
3997
|
specify "#for_update should use FOR UPDATE" do
|
|
@@ -3977,3 +4006,89 @@ describe "Dataset#lock_style and for_update" do
|
|
|
3977
4006
|
@ds.lock_style("FOR SHARE").sql.should == "SELECT * FROM t FOR SHARE"
|
|
3978
4007
|
end
|
|
3979
4008
|
end
|
|
4009
|
+
|
|
4010
|
+
describe "Custom ASTTransformer" do
|
|
4011
|
+
specify "should transform given objects" do
|
|
4012
|
+
c = Class.new(Sequel::ASTTransformer) do
|
|
4013
|
+
def v(s)
|
|
4014
|
+
(s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
|
|
4015
|
+
end
|
|
4016
|
+
end.new
|
|
4017
|
+
ds = Sequel::Dataset.new(nil).from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
|
4018
|
+
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)'
|
|
4019
|
+
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)'
|
|
4020
|
+
end
|
|
4021
|
+
end
|
|
4022
|
+
|
|
4023
|
+
describe "Dataset#returning" do
|
|
4024
|
+
before do
|
|
4025
|
+
@ds = Sequel.mock(:fetch=>proc{|s| {:foo=>s}})[:t].returning(:foo)
|
|
4026
|
+
@pr = proc do
|
|
4027
|
+
[:insert, :update, :delete].each do |m|
|
|
4028
|
+
@ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_returning_sql"]}
|
|
4029
|
+
end
|
|
4030
|
+
end
|
|
4031
|
+
end
|
|
4032
|
+
|
|
4033
|
+
specify "should use RETURNING clause in the SQL if the dataset supports it" do
|
|
4034
|
+
@pr.call
|
|
4035
|
+
@ds.delete_sql.should == "DELETE FROM t RETURNING foo"
|
|
4036
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1) RETURNING foo"
|
|
4037
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1 RETURNING foo"
|
|
4038
|
+
end
|
|
4039
|
+
|
|
4040
|
+
specify "should not use RETURNING clause in the SQL if the dataset does not support it" do
|
|
4041
|
+
@ds.delete_sql.should == "DELETE FROM t"
|
|
4042
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1)"
|
|
4043
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1"
|
|
4044
|
+
end
|
|
4045
|
+
|
|
4046
|
+
specify "should have insert, update, and delete yield to blocks if RETURNING is used" do
|
|
4047
|
+
@pr.call
|
|
4048
|
+
h = {}
|
|
4049
|
+
@ds.delete{|r| h = r}
|
|
4050
|
+
h.should == {:foo=>"DELETE FROM t RETURNING foo"}
|
|
4051
|
+
@ds.insert(1){|r| h = r}
|
|
4052
|
+
h.should == {:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}
|
|
4053
|
+
@ds.update(:foo=>1){|r| h = r}
|
|
4054
|
+
h.should == {:foo=>"UPDATE t SET foo = 1 RETURNING foo"}
|
|
4055
|
+
end
|
|
4056
|
+
|
|
4057
|
+
specify "should have insert, update, and delete return arrays of hashes if RETURNING is used and a block is not given" do
|
|
4058
|
+
@pr.call
|
|
4059
|
+
h = {}
|
|
4060
|
+
@ds.delete.should == [{:foo=>"DELETE FROM t RETURNING foo"}]
|
|
4061
|
+
@ds.insert(1).should == [{:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}]
|
|
4062
|
+
@ds.update(:foo=>1).should == [{:foo=>"UPDATE t SET foo = 1 RETURNING foo"}]
|
|
4063
|
+
end
|
|
4064
|
+
end
|
|
4065
|
+
|
|
4066
|
+
describe "Dataset emulating bitwise operator support" do
|
|
4067
|
+
before do
|
|
4068
|
+
@ds = Sequel::Database.new.dataset
|
|
4069
|
+
@ds.quote_identifiers = true
|
|
4070
|
+
def @ds.complex_expression_sql_append(sql, op, args)
|
|
4071
|
+
sql << complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
|
4072
|
+
end
|
|
4073
|
+
end
|
|
4074
|
+
|
|
4075
|
+
it "should work with any numbers of arguments for operators" do
|
|
4076
|
+
@ds.select(Sequel::SQL::ComplexExpression.new(:&, :x)).sql.should == 'SELECT "x"'
|
|
4077
|
+
@ds.select(:x & 1).sql.should == 'SELECT bitand("x", 1)'
|
|
4078
|
+
@ds.select(:x & 1 & 2).sql.should == 'SELECT bitand(bitand("x", 1), 2)'
|
|
4079
|
+
end
|
|
4080
|
+
end
|
|
4081
|
+
|
|
4082
|
+
describe "Dataset feature defaults" do
|
|
4083
|
+
it "should not require aliases for recursive CTEs by default" do
|
|
4084
|
+
Sequel::Database.new.dataset.recursive_cte_requires_column_aliases?.should be_false
|
|
4085
|
+
end
|
|
4086
|
+
|
|
4087
|
+
it "should not require placeholder type specifiers by default" do
|
|
4088
|
+
Sequel::Database.new.dataset.requires_placeholder_type_specifiers?.should be_false
|
|
4089
|
+
end
|
|
4090
|
+
|
|
4091
|
+
it "offset use should be returning a separate row number column by default" do
|
|
4092
|
+
Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
|
|
4093
|
+
end
|
|
4094
|
+
end
|