sequel 3.21.0 → 3.29.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 +413 -3
- data/README.rdoc +20 -6
- data/Rakefile +23 -16
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +210 -43
- data/doc/dataset_basics.rdoc +4 -4
- 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 +86 -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/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +115 -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 +15 -7
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- 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 +5 -31
- data/lib/sequel/adapters/jdbc/db2.rb +44 -0
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +26 -17
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +67 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +6 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +41 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +107 -38
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +78 -182
- data/lib/sequel/adapters/mysql2.rb +24 -23
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +349 -51
- data/lib/sequel/adapters/postgres.rb +169 -21
- data/lib/sequel/adapters/shared/access.rb +21 -6
- data/lib/sequel/adapters/shared/db2.rb +288 -0
- data/lib/sequel/adapters/shared/firebird.rb +214 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +108 -65
- data/lib/sequel/adapters/shared/mysql.rb +56 -13
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -34
- data/lib/sequel/adapters/shared/postgres.rb +107 -58
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +168 -41
- data/lib/sequel/adapters/sqlite.rb +27 -18
- data/lib/sequel/adapters/swift/mysql.rb +9 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +152 -17
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +63 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +100 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +8 -5
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +194 -57
- data/lib/sequel/dataset/features.rb +81 -8
- data/lib/sequel/dataset/graph.rb +8 -7
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +32 -15
- data/lib/sequel/dataset/query.rb +223 -42
- data/lib/sequel/dataset/sql.rb +58 -61
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +997 -331
- data/lib/sequel/model/base.rb +386 -129
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +12 -25
- 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 +107 -51
- data/lib/sequel/timezones.rb +44 -35
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +65 -29
- data/spec/adapters/mysql_spec.rb +122 -123
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +213 -61
- 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 +20 -31
- data/spec/core/database_spec.rb +729 -508
- data/spec/core/dataset_spec.rb +980 -1044
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/identity_map_spec.rb +162 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/many_through_many_spec.rb +195 -20
- data/spec/extensions/migration_spec.rb +17 -17
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +4 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/single_table_inheritance_spec.rb +11 -0
- data/spec/extensions/spec_helper.rb +7 -1
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +522 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +375 -62
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +200 -120
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +174 -7
- data/spec/model/associations_spec.rb +849 -661
- data/spec/model/base_spec.rb +255 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +640 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +207 -167
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +321 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +95 -38
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
|
|
@@ -418,7 +403,7 @@ describe "Dataset#where" do
|
|
|
418
403
|
b.should == a
|
|
419
404
|
end
|
|
420
405
|
|
|
421
|
-
specify "should not replace named placeholders that don't
|
|
406
|
+
specify "should not replace named placeholders that don't exist in the hash" do
|
|
422
407
|
@dataset.where('price < :price AND id in :ids', :price=>100).select_sql.should ==
|
|
423
408
|
"SELECT * FROM test WHERE (price < 100 AND id in :ids)"
|
|
424
409
|
end
|
|
@@ -538,34 +523,33 @@ describe "Dataset#where" do
|
|
|
538
523
|
|
|
539
524
|
specify "should handle IN/NOT IN queries with multiple columns and a dataset where the database doesn't support it" do
|
|
540
525
|
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
@sql_used = sql
|
|
544
|
-
@columns = [:id1, :id2]
|
|
545
|
-
yield(:id1=>1, :id2=>2)
|
|
546
|
-
yield(:id1=>3, :id2=>4)
|
|
547
|
-
end
|
|
548
|
-
d1.instance_variable_get(:@sql_used).should == nil
|
|
526
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
527
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
549
528
|
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
550
|
-
|
|
551
|
-
d1.instance_variable_set(:@sql_used, nil)
|
|
529
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
552
530
|
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
553
|
-
|
|
531
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
554
532
|
end
|
|
555
533
|
|
|
556
534
|
specify "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it" do
|
|
557
535
|
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
@sql_used = sql
|
|
561
|
-
@columns = [:id1, :id2]
|
|
562
|
-
end
|
|
563
|
-
d1.instance_variable_get(:@sql_used).should == nil
|
|
536
|
+
db = Sequel.mock
|
|
537
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
564
538
|
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
|
|
565
|
-
|
|
566
|
-
d1.instance_variable_set(:@sql_used, nil)
|
|
539
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
567
540
|
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
568
|
-
|
|
541
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
specify "should handle IN/NOT IN queries for datasets with row_procs" do
|
|
545
|
+
@dataset.meta_def(:supports_multiple_column_in?){false}
|
|
546
|
+
db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
|
|
547
|
+
d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
|
|
548
|
+
d1.row_proc = proc{|h| Object.new}
|
|
549
|
+
@dataset.filter([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
|
|
550
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
551
|
+
@dataset.exclude([:id1, :id2] => d1).sql.should == "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
|
|
552
|
+
db.sqls.should == ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
|
|
569
553
|
end
|
|
570
554
|
|
|
571
555
|
specify "should accept a subquery for an EXISTS clause" do
|
|
@@ -601,10 +585,18 @@ describe "Dataset#where" do
|
|
|
601
585
|
end
|
|
602
586
|
|
|
603
587
|
specify "should accept true and false as arguments" do
|
|
604
|
-
@dataset.filter(true).sql.should ==
|
|
605
|
-
|
|
606
|
-
@dataset.filter(false).sql.should ==
|
|
607
|
-
|
|
588
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE 't'"
|
|
589
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE 't'"
|
|
590
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
591
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE 'f'"
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
specify "should use boolean expression if dataset does not support where true/false" do
|
|
595
|
+
def @dataset.supports_where_true?() false end
|
|
596
|
+
@dataset.filter(true).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
597
|
+
@dataset.filter(Sequel::SQLTRUE).sql.should == "SELECT * FROM test WHERE (1 = 1)"
|
|
598
|
+
@dataset.filter(false).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
599
|
+
@dataset.filter(Sequel::SQLFALSE).sql.should == "SELECT * FROM test WHERE (1 = 0)"
|
|
608
600
|
end
|
|
609
601
|
|
|
610
602
|
specify "should allow the use of multiple arguments" do
|
|
@@ -658,33 +650,25 @@ describe "Dataset#or" do
|
|
|
658
650
|
end
|
|
659
651
|
|
|
660
652
|
specify "should add an alternative expression to the where clause" do
|
|
661
|
-
@d1.or(:y => 2).sql.should ==
|
|
662
|
-
'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
|
653
|
+
@d1.or(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
|
663
654
|
end
|
|
664
655
|
|
|
665
656
|
specify "should accept all forms of filters" do
|
|
666
|
-
@d1.or('y > ?', 2).sql.should ==
|
|
667
|
-
|
|
668
|
-
@d1.or(:yy.sql_number > 3).sql.should ==
|
|
669
|
-
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
657
|
+
@d1.or('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
|
658
|
+
@d1.or(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
670
659
|
end
|
|
671
660
|
|
|
672
661
|
specify "should accept blocks passed to filter" do
|
|
673
|
-
@d1.or{:yy.sql_number > 3}.sql.should ==
|
|
674
|
-
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
662
|
+
@d1.or{:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
|
675
663
|
end
|
|
676
664
|
|
|
677
665
|
specify "should correctly add parens to give predictable results" do
|
|
678
|
-
@d1.filter(:y => 2).or(:z => 3).sql.should ==
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
@d1.or(:y => 2).filter(:z => 3).sql.should ==
|
|
682
|
-
'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
666
|
+
@d1.filter(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
667
|
+
@d1.or(:y => 2).filter(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
683
668
|
end
|
|
684
669
|
|
|
685
670
|
specify "should allow the use of blocks and arguments simultaneously" do
|
|
686
|
-
@d1.or(:zz.sql_number < 3){:yy.sql_number > 3}.sql.should ==
|
|
687
|
-
'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
|
671
|
+
@d1.or(:zz.sql_number < 3){:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
|
688
672
|
end
|
|
689
673
|
end
|
|
690
674
|
|
|
@@ -697,34 +681,25 @@ describe "Dataset#and" do
|
|
|
697
681
|
specify "should raise if no filter exists" do
|
|
698
682
|
proc {@dataset.and(:a => 1)}.should raise_error(Sequel::Error)
|
|
699
683
|
proc {@dataset.where(:a => 1).group(:t).and(:b => 2)}.should_not raise_error(Sequel::Error)
|
|
700
|
-
@dataset.where(:a => 1).group(:t).and(:b => 2).sql ==
|
|
701
|
-
"SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
|
|
684
|
+
@dataset.where(:a => 1).group(:t).and(:b => 2).sql == "SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
|
|
702
685
|
end
|
|
703
686
|
|
|
704
687
|
specify "should add an alternative expression to the where clause" do
|
|
705
|
-
@d1.and(:y => 2).sql.should ==
|
|
706
|
-
'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
|
688
|
+
@d1.and(:y => 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
|
707
689
|
end
|
|
708
690
|
|
|
709
|
-
specify "should accept
|
|
710
|
-
|
|
711
|
-
@d1.and(
|
|
712
|
-
'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
|
713
|
-
@d1.and(:yy.sql_number > 3).sql.should ==
|
|
714
|
-
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
691
|
+
specify "should accept different types of filters" do
|
|
692
|
+
@d1.and('y > ?', 2).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
|
693
|
+
@d1.and(:yy.sql_number > 3).sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
715
694
|
end
|
|
716
695
|
|
|
717
696
|
specify "should accept blocks passed to filter" do
|
|
718
|
-
@d1.and {:yy.sql_number > 3}.sql.should ==
|
|
719
|
-
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
697
|
+
@d1.and {:yy.sql_number > 3}.sql.should == 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
|
720
698
|
end
|
|
721
699
|
|
|
722
700
|
specify "should correctly add parens to give predictable results" do
|
|
723
|
-
@d1.or(:y => 2).and(:z => 3).sql.should ==
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
@d1.and(:y => 2).or(:z => 3).sql.should ==
|
|
727
|
-
'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
701
|
+
@d1.or(:y => 2).and(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
|
702
|
+
@d1.and(:y => 2).or(:z => 3).sql.should == 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
|
728
703
|
end
|
|
729
704
|
end
|
|
730
705
|
|
|
@@ -734,8 +709,11 @@ describe "Dataset#exclude" do
|
|
|
734
709
|
end
|
|
735
710
|
|
|
736
711
|
specify "should correctly negate the expression when one condition is given" do
|
|
737
|
-
@dataset.exclude(:region=>'Asia').select_sql.should ==
|
|
738
|
-
|
|
712
|
+
@dataset.exclude(:region=>'Asia').select_sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
specify "should affect the having clause if having clause is already used" do
|
|
716
|
+
@dataset.group_and_count(:name).having{count > 2}.exclude{count > 5}.sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name HAVING ((count > 2) AND (count <= 5))"
|
|
739
717
|
end
|
|
740
718
|
|
|
741
719
|
specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
|
|
@@ -745,30 +723,46 @@ describe "Dataset#exclude" do
|
|
|
745
723
|
end
|
|
746
724
|
|
|
747
725
|
specify "should parenthesize a single string condition correctly" do
|
|
748
|
-
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should ==
|
|
749
|
-
"SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
726
|
+
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
750
727
|
end
|
|
751
728
|
|
|
752
729
|
specify "should parenthesize an array condition correctly" do
|
|
753
|
-
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should ==
|
|
754
|
-
"SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
730
|
+
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should == "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
|
755
731
|
end
|
|
756
732
|
|
|
757
733
|
specify "should correctly parenthesize when it is used twice" do
|
|
758
|
-
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should ==
|
|
759
|
-
"SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
|
734
|
+
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
|
760
735
|
end
|
|
761
736
|
|
|
762
737
|
specify "should support proc expressions" do
|
|
763
|
-
@dataset.exclude{:id.sql_number < 6}.sql.should ==
|
|
764
|
-
'SELECT * FROM test WHERE (id >= 6)'
|
|
738
|
+
@dataset.exclude{:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE (id >= 6)'
|
|
765
739
|
end
|
|
766
740
|
|
|
767
741
|
specify "should allow the use of blocks and arguments simultaneously" do
|
|
768
|
-
@dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should ==
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
742
|
+
@dataset.exclude(:id => (7..11)){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id < 7) OR (id > 11) OR (id >= 6))'
|
|
743
|
+
@dataset.exclude([:id, 1], [:x, 3]){:id.sql_number < 6}.sql.should == 'SELECT * FROM test WHERE ((id != 1) OR (x != 3) OR (id >= 6))'
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
describe "Dataset#exclude_where" do
|
|
748
|
+
before do
|
|
749
|
+
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
specify "should correctly negate the expression and add it to the where clause" do
|
|
753
|
+
@dataset.exclude_where(:region=>'Asia').sql.should == "SELECT * FROM test WHERE (region != 'Asia')"
|
|
754
|
+
@dataset.exclude_where(:region=>'Asia').exclude_where(:region=>'NA').sql.should == "SELECT * FROM test WHERE ((region != 'Asia') AND (region != 'NA'))"
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
specify "should affect the where clause even if having clause is already used" do
|
|
758
|
+
@dataset.group_and_count(:name).having{count > 2}.exclude_where(:region=>'Asia').sql.should ==
|
|
759
|
+
"SELECT name, count(*) AS count FROM test WHERE (region != 'Asia') GROUP BY name HAVING (count > 2)"
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
describe "Dataset#exclude_having" do
|
|
764
|
+
specify "should correctly negate the expression and add it to the having clause" do
|
|
765
|
+
Sequel::Dataset.new(nil).from(:test).exclude_having{count > 2}.exclude_having{count < 0}.sql.should == "SELECT * FROM test HAVING ((count <= 2) AND (count >= 0))"
|
|
772
766
|
end
|
|
773
767
|
end
|
|
774
768
|
|
|
@@ -794,9 +788,6 @@ describe "Dataset#having" do
|
|
|
794
788
|
before do
|
|
795
789
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
|
796
790
|
@grouped = @dataset.group(:region).select(:region, :sum.sql_function(:population), :avg.sql_function(:gdp))
|
|
797
|
-
@d1 = @grouped.having('sum(population) > 10')
|
|
798
|
-
@d2 = @grouped.having(:region => 'Asia')
|
|
799
|
-
@columns = "region, sum(population), avg(gdp)"
|
|
800
791
|
end
|
|
801
792
|
|
|
802
793
|
specify "should just clone if given an empty argument" do
|
|
@@ -806,18 +797,15 @@ describe "Dataset#having" do
|
|
|
806
797
|
end
|
|
807
798
|
|
|
808
799
|
specify "should affect select statements" do
|
|
809
|
-
@
|
|
810
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
800
|
+
@grouped.having('sum(population) > 10').select_sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
811
801
|
end
|
|
812
802
|
|
|
813
803
|
specify "should support proc expressions" do
|
|
814
|
-
@grouped.having {:sum.sql_function(:population) > 10}.sql.should ==
|
|
815
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
804
|
+
@grouped.having {:sum.sql_function(:population) > 10}.sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
|
816
805
|
end
|
|
817
806
|
|
|
818
807
|
specify "should work with and on the having clause" do
|
|
819
|
-
@grouped.having( :a.sql_number > 1 ).and( :b.sql_number < 2 ).sql.should ==
|
|
820
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
|
|
808
|
+
@grouped.having( :a.sql_number > 1 ).and( :b.sql_number < 2 ).sql.should == "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
|
|
821
809
|
end
|
|
822
810
|
end
|
|
823
811
|
|
|
@@ -848,7 +836,7 @@ describe "a grouped dataset" do
|
|
|
848
836
|
end
|
|
849
837
|
|
|
850
838
|
specify "should format the right statement for counting (as a subquery)" do
|
|
851
|
-
db =
|
|
839
|
+
db = Sequel.mock
|
|
852
840
|
db[:test].select(:name).group(:name).count
|
|
853
841
|
db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT name FROM test GROUP BY name) AS t1 LIMIT 1"]
|
|
854
842
|
end
|
|
@@ -868,45 +856,43 @@ describe "Dataset#group_by" do
|
|
|
868
856
|
end
|
|
869
857
|
|
|
870
858
|
specify "should specify the grouping in generated select statement" do
|
|
871
|
-
@dataset.select_sql.should ==
|
|
872
|
-
|
|
873
|
-
@dataset.group_by(:
|
|
874
|
-
"SELECT * FROM test GROUP BY a, b"
|
|
875
|
-
@dataset.group_by(:type_id=>nil).select_sql.should ==
|
|
876
|
-
"SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
859
|
+
@dataset.select_sql.should == "SELECT * FROM test GROUP BY type_id"
|
|
860
|
+
@dataset.group_by(:a, :b).select_sql.should == "SELECT * FROM test GROUP BY a, b"
|
|
861
|
+
@dataset.group_by(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
877
862
|
end
|
|
878
863
|
|
|
879
|
-
specify "should ungroup when passed nil
|
|
880
|
-
@dataset.group_by.select_sql.should ==
|
|
881
|
-
|
|
882
|
-
@dataset.group_by(nil).select_sql.should ==
|
|
883
|
-
"SELECT * FROM test"
|
|
864
|
+
specify "should ungroup when passed nil or no arguments" do
|
|
865
|
+
@dataset.group_by.select_sql.should == "SELECT * FROM test"
|
|
866
|
+
@dataset.group_by(nil).select_sql.should == "SELECT * FROM test"
|
|
884
867
|
end
|
|
885
868
|
|
|
886
869
|
specify "should undo previous grouping" do
|
|
887
|
-
@dataset.group_by(:a).group_by(:b).select_sql.should ==
|
|
888
|
-
|
|
889
|
-
@dataset.group_by(:a, :b).group_by.select_sql.should ==
|
|
890
|
-
"SELECT * FROM test"
|
|
870
|
+
@dataset.group_by(:a).group_by(:b).select_sql.should == "SELECT * FROM test GROUP BY b"
|
|
871
|
+
@dataset.group_by(:a, :b).group_by.select_sql.should == "SELECT * FROM test"
|
|
891
872
|
end
|
|
892
873
|
|
|
893
874
|
specify "should be aliased as #group" do
|
|
894
|
-
@dataset.group(:type_id=>nil).select_sql.should ==
|
|
895
|
-
|
|
875
|
+
@dataset.group(:type_id=>nil).select_sql.should == "SELECT * FROM test GROUP BY (type_id IS NULL)"
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
specify "should take a virtual row block" do
|
|
879
|
+
@dataset.group{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
880
|
+
@dataset.group_by{type_id > 1}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1)"
|
|
881
|
+
@dataset.group{[type_id > 1, type_id < 2]}.sql.should == "SELECT * FROM test GROUP BY (type_id > 1), (type_id < 2)"
|
|
882
|
+
@dataset.group(:foo){type_id > 1}.sql.should == "SELECT * FROM test GROUP BY foo, (type_id > 1)"
|
|
896
883
|
end
|
|
897
884
|
end
|
|
898
885
|
|
|
899
886
|
describe "Dataset#as" do
|
|
900
887
|
specify "should set up an alias" do
|
|
901
888
|
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'
|
|
889
|
+
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
|
904
890
|
end
|
|
905
891
|
end
|
|
906
892
|
|
|
907
893
|
describe "Dataset#literal" do
|
|
908
894
|
before do
|
|
909
|
-
@dataset = Sequel::
|
|
895
|
+
@dataset = Sequel::Database.new.from(:test)
|
|
910
896
|
end
|
|
911
897
|
|
|
912
898
|
specify "should escape strings properly" do
|
|
@@ -965,6 +951,12 @@ describe "Dataset#literal" do
|
|
|
965
951
|
d.literal(d).should == "(#{d.sql})"
|
|
966
952
|
end
|
|
967
953
|
|
|
954
|
+
specify "should literalize Sequel::SQLTime properly" do
|
|
955
|
+
t = Sequel::SQLTime.now
|
|
956
|
+
s = t.strftime("'%H:%M:%S")
|
|
957
|
+
@dataset.literal(t).should == "#{s}.#{sprintf('%06i', t.usec)}'"
|
|
958
|
+
end
|
|
959
|
+
|
|
968
960
|
specify "should literalize Time properly" do
|
|
969
961
|
t = Time.now
|
|
970
962
|
s = t.strftime("'%Y-%m-%d %H:%M:%S")
|
|
@@ -1069,35 +1061,25 @@ describe "Dataset#from" do
|
|
|
1069
1061
|
end
|
|
1070
1062
|
|
|
1071
1063
|
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"
|
|
1064
|
+
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should == "SELECT * FROM (SELECT * FROM a WHERE (a = 1)) AS t1"
|
|
1074
1065
|
end
|
|
1075
1066
|
|
|
1076
1067
|
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"
|
|
1068
|
+
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS t1"
|
|
1079
1069
|
|
|
1080
1070
|
d1 = @dataset.from(:a).group(:b)
|
|
1081
1071
|
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"
|
|
1072
|
+
@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
1073
|
end
|
|
1086
1074
|
|
|
1087
1075
|
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"
|
|
1076
|
+
@dataset.from(:a => :b).sql.should == "SELECT * FROM a AS b"
|
|
1077
|
+
@dataset.from(:a => 'b').sql.should == "SELECT * FROM a AS b"
|
|
1078
|
+
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should == "SELECT * FROM (SELECT * FROM a GROUP BY b) AS c"
|
|
1096
1079
|
end
|
|
1097
1080
|
|
|
1098
1081
|
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"
|
|
1082
|
+
@dataset.from(@dataset.from(:a)).select_sql.should == "SELECT * FROM (SELECT * FROM a) AS t1"
|
|
1101
1083
|
end
|
|
1102
1084
|
|
|
1103
1085
|
specify "should remove all FROM tables if called with no arguments" do
|
|
@@ -1105,32 +1087,27 @@ describe "Dataset#from" do
|
|
|
1105
1087
|
end
|
|
1106
1088
|
|
|
1107
1089
|
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)"
|
|
1090
|
+
@dataset.from(:abc.sql_function(:def)).select_sql.should == "SELECT * FROM abc(def)"
|
|
1091
|
+
@dataset.from(:a.sql_function(:i)).select_sql.should == "SELECT * FROM a(i)"
|
|
1113
1092
|
end
|
|
1114
1093
|
|
|
1115
1094
|
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.
|
|
1129
|
-
|
|
1130
|
-
@dataset.from(:
|
|
1131
|
-
|
|
1132
|
-
@dataset.from(:'#___#').select_sql.should ==
|
|
1133
|
-
'SELECT * FROM # AS #'
|
|
1095
|
+
@dataset.from(:abc__def).select_sql.should == "SELECT * FROM abc.def"
|
|
1096
|
+
@dataset.from(:a_b__c).select_sql.should == "SELECT * FROM a_b.c"
|
|
1097
|
+
@dataset.from(:'#__#').select_sql.should == 'SELECT * FROM #.#'
|
|
1098
|
+
@dataset.from(:abc__def___d).select_sql.should == "SELECT * FROM abc.def AS d"
|
|
1099
|
+
@dataset.from(:a_b__d_e___f_g).select_sql.should == "SELECT * FROM a_b.d_e AS f_g"
|
|
1100
|
+
@dataset.from(:'#__#___#').select_sql.should == 'SELECT * FROM #.# AS #'
|
|
1101
|
+
@dataset.from(:abc___def).select_sql.should == "SELECT * FROM abc AS def"
|
|
1102
|
+
@dataset.from(:a_b___c_d).select_sql.should == "SELECT * FROM a_b AS c_d"
|
|
1103
|
+
@dataset.from(:'#___#').select_sql.should == 'SELECT * FROM # AS #'
|
|
1104
|
+
end
|
|
1105
|
+
|
|
1106
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
1107
|
+
@dataset.meta_def(:supports_cte?){true}
|
|
1108
|
+
@dataset.meta_def(:supports_cte_in_subselect?){false}
|
|
1109
|
+
@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'
|
|
1110
|
+
@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
1111
|
end
|
|
1135
1112
|
end
|
|
1136
1113
|
|
|
@@ -1147,18 +1124,17 @@ describe "Dataset#select" do
|
|
|
1147
1124
|
specify "should accept symbols and literal strings" do
|
|
1148
1125
|
@d.select('aaa'.lit).sql.should == 'SELECT aaa FROM test'
|
|
1149
1126
|
@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'
|
|
1127
|
+
@d.select(:test__cc, 'test.d AS e'.lit).sql.should == 'SELECT test.cc, test.d AS e FROM test'
|
|
1128
|
+
@d.select('test.d AS e'.lit, :test__cc).sql.should == 'SELECT test.d AS e, test.cc FROM test'
|
|
1129
|
+
@d.select(:test__name___n).sql.should == 'SELECT test.name AS n FROM test'
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
specify "should accept ColumnAlls" do
|
|
1133
|
+
@d.select(:test.*).sql.should == 'SELECT test.* FROM test'
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
specify "should accept QualifiedIdentifiers" do
|
|
1137
|
+
@d.select(:test__name.as(:n)).sql.should == 'SELECT test.name AS n FROM test'
|
|
1162
1138
|
end
|
|
1163
1139
|
|
|
1164
1140
|
specify "should use the wildcard if no arguments are given" do
|
|
@@ -1166,20 +1142,17 @@ describe "Dataset#select" do
|
|
|
1166
1142
|
end
|
|
1167
1143
|
|
|
1168
1144
|
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/
|
|
1145
|
+
@d.select(:name => 'n', :__ggh => 'age').sql.should =~ /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
|
1171
1146
|
end
|
|
1172
1147
|
|
|
1173
|
-
specify "should
|
|
1148
|
+
specify "should override the previous select option" do
|
|
1174
1149
|
@d.select!(:a, :b, :c).select.sql.should == 'SELECT * FROM test'
|
|
1175
1150
|
@d.select!(:price).select(:name).sql.should == 'SELECT name FROM test'
|
|
1176
1151
|
end
|
|
1177
1152
|
|
|
1178
1153
|
specify "should accept arbitrary objects and literalize them correctly" do
|
|
1179
1154
|
@d.select(1, :a, 't').sql.should == "SELECT 1, a, 't' FROM test"
|
|
1180
|
-
|
|
1181
1155
|
@d.select(nil, :sum.sql_function(:t), :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
|
|
1182
|
-
|
|
1183
1156
|
@d.select(nil, 1, :x => :y).sql.should == "SELECT NULL, 1, x AS y FROM test"
|
|
1184
1157
|
end
|
|
1185
1158
|
|
|
@@ -1198,6 +1171,27 @@ describe "Dataset#select" do
|
|
|
1198
1171
|
end
|
|
1199
1172
|
end
|
|
1200
1173
|
|
|
1174
|
+
describe "Dataset#select_group" do
|
|
1175
|
+
before do
|
|
1176
|
+
@d = Sequel::Dataset.new(nil).from(:test)
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
specify "should set both SELECT and GROUP" do
|
|
1180
|
+
@d.select_group(:name).sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1181
|
+
@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'
|
|
1182
|
+
end
|
|
1183
|
+
|
|
1184
|
+
specify "should remove from both SELECT and GROUP if no arguments" do
|
|
1185
|
+
@d.select_group(:name).select_group.sql.should == 'SELECT * FROM test'
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
specify "should accept virtual row blocks" do
|
|
1189
|
+
@d.select_group{name}.sql.should == 'SELECT name FROM test GROUP BY name'
|
|
1190
|
+
@d.select_group{[name, f(v).as(a)]}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1191
|
+
@d.select_group(:name){f(v).as(a)}.sql.should == 'SELECT name, f(v) AS a FROM test GROUP BY name, f(v)'
|
|
1192
|
+
end
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1201
1195
|
describe "Dataset#select_all" do
|
|
1202
1196
|
before do
|
|
1203
1197
|
@d = Sequel::Dataset.new(nil).from(:test)
|
|
@@ -1207,9 +1201,43 @@ describe "Dataset#select_all" do
|
|
|
1207
1201
|
@d.select_all.sql.should == 'SELECT * FROM test'
|
|
1208
1202
|
end
|
|
1209
1203
|
|
|
1210
|
-
specify "should
|
|
1204
|
+
specify "should override the previous select option" do
|
|
1211
1205
|
@d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
|
|
1212
1206
|
end
|
|
1207
|
+
|
|
1208
|
+
specify "should select all columns in a table if given an argument" do
|
|
1209
|
+
@d.select_all(:test).sql.should == 'SELECT test.* FROM test'
|
|
1210
|
+
end
|
|
1211
|
+
|
|
1212
|
+
specify "should select all columns all tables if given a multiple arguments" do
|
|
1213
|
+
@d.select_all(:test, :foo).sql.should == 'SELECT test.*, foo.* FROM test'
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
specify "should work correctly with qualified symbols" do
|
|
1217
|
+
@d.select_all(:sch__test).sql.should == 'SELECT sch.test.* FROM test'
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
specify "should work correctly with aliased symbols" do
|
|
1221
|
+
@d.select_all(:test___al).sql.should == 'SELECT al.* FROM test'
|
|
1222
|
+
@d.select_all(:sch__test___al).sql.should == 'SELECT al.* FROM test'
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
specify "should work correctly with SQL::Identifiers" do
|
|
1226
|
+
@d.select_all(:test.identifier).sql.should == 'SELECT test.* FROM test'
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1229
|
+
specify "should work correctly with SQL::QualifiedIdentifier" do
|
|
1230
|
+
@d.select_all(:test.qualify(:sch)).sql.should == 'SELECT sch.test.* FROM test'
|
|
1231
|
+
end
|
|
1232
|
+
|
|
1233
|
+
specify "should work correctly with SQL::AliasedExpressions" do
|
|
1234
|
+
@d.select_all(:test.as(:al)).sql.should == 'SELECT al.* FROM test'
|
|
1235
|
+
end
|
|
1236
|
+
|
|
1237
|
+
specify "should work correctly with SQL::JoinClauses" do
|
|
1238
|
+
d = @d.cross_join(:foo).cross_join(:test___al)
|
|
1239
|
+
@d.select_all(*d.opts[:join]).sql.should == 'SELECT foo.*, al.* FROM test'
|
|
1240
|
+
end
|
|
1213
1241
|
end
|
|
1214
1242
|
|
|
1215
1243
|
describe "Dataset#select_more" do
|
|
@@ -1254,6 +1282,14 @@ describe "Dataset#select_append" do
|
|
|
1254
1282
|
@d.select(:a).select_append{|o| o.b}.sql.should == 'SELECT a, b FROM test'
|
|
1255
1283
|
@d.select(:a.*).select_append(:b.*){b(1)}.sql.should == 'SELECT a.*, b.*, b(1) FROM test'
|
|
1256
1284
|
end
|
|
1285
|
+
|
|
1286
|
+
specify "should select from all from and join tables if SELECT *, column not supported" do
|
|
1287
|
+
@d.meta_def(:supports_select_all_and_column?){false}
|
|
1288
|
+
@d.select_append(:b).sql.should == 'SELECT test.*, b FROM test'
|
|
1289
|
+
@d.from(:test, :c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test, c'
|
|
1290
|
+
@d.cross_join(:c).select_append(:b).sql.should == 'SELECT test.*, c.*, b FROM test CROSS JOIN c'
|
|
1291
|
+
@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'
|
|
1292
|
+
end
|
|
1257
1293
|
end
|
|
1258
1294
|
|
|
1259
1295
|
describe "Dataset#order" do
|
|
@@ -1262,38 +1298,31 @@ describe "Dataset#order" do
|
|
|
1262
1298
|
end
|
|
1263
1299
|
|
|
1264
1300
|
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'
|
|
1301
|
+
@dataset.order(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1267
1302
|
end
|
|
1268
1303
|
|
|
1269
1304
|
specify "should accept multiple arguments" do
|
|
1270
|
-
@dataset.order(:name, :price.desc).sql.should ==
|
|
1271
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1305
|
+
@dataset.order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1272
1306
|
end
|
|
1273
1307
|
|
|
1274
1308
|
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'
|
|
1309
|
+
@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
1310
|
end
|
|
1278
1311
|
|
|
1279
|
-
specify "should
|
|
1280
|
-
@dataset.order(:name).order(:stamp).sql.should ==
|
|
1281
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1312
|
+
specify "should override a previous ordering" do
|
|
1313
|
+
@dataset.order(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1282
1314
|
end
|
|
1283
1315
|
|
|
1284
1316
|
specify "should accept a literal string" do
|
|
1285
|
-
@dataset.order('dada ASC'.lit).sql.should ==
|
|
1286
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1317
|
+
@dataset.order('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1287
1318
|
end
|
|
1288
1319
|
|
|
1289
1320
|
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)'
|
|
1321
|
+
@dataset.order(:name=>nil).sql.should == 'SELECT * FROM test ORDER BY (name IS NULL)'
|
|
1292
1322
|
end
|
|
1293
1323
|
|
|
1294
1324
|
specify "should accept a nil to remove ordering" do
|
|
1295
|
-
@dataset.order(:bah).order(nil).sql.should ==
|
|
1296
|
-
'SELECT * FROM test'
|
|
1325
|
+
@dataset.order(:bah).order(nil).sql.should == 'SELECT * FROM test'
|
|
1297
1326
|
end
|
|
1298
1327
|
|
|
1299
1328
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1355,6 +1384,13 @@ describe "Dataset#with_sql" do
|
|
|
1355
1384
|
specify "should keep row_proc" do
|
|
1356
1385
|
@dataset.with_sql('SELECT 1 FROM test').row_proc.should == @dataset.row_proc
|
|
1357
1386
|
end
|
|
1387
|
+
|
|
1388
|
+
specify "should work with method symbols and arguments" do
|
|
1389
|
+
@dataset.with_sql(:delete_sql).sql.should == 'DELETE FROM test'
|
|
1390
|
+
@dataset.with_sql(:insert_sql, :b=>1).sql.should == 'INSERT INTO test (b) VALUES (1)'
|
|
1391
|
+
@dataset.with_sql(:update_sql, :b=>1).sql.should == 'UPDATE test SET b = 1'
|
|
1392
|
+
end
|
|
1393
|
+
|
|
1358
1394
|
end
|
|
1359
1395
|
|
|
1360
1396
|
describe "Dataset#order_by" do
|
|
@@ -1363,28 +1399,23 @@ describe "Dataset#order_by" do
|
|
|
1363
1399
|
end
|
|
1364
1400
|
|
|
1365
1401
|
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'
|
|
1402
|
+
@dataset.order_by(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1368
1403
|
end
|
|
1369
1404
|
|
|
1370
1405
|
specify "should accept multiple arguments" do
|
|
1371
|
-
@dataset.order_by(:name, :price.desc).sql.should ==
|
|
1372
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
|
1406
|
+
@dataset.order_by(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name, price DESC'
|
|
1373
1407
|
end
|
|
1374
1408
|
|
|
1375
|
-
specify "should
|
|
1376
|
-
@dataset.order_by(:name).order(:stamp).sql.should ==
|
|
1377
|
-
'SELECT * FROM test ORDER BY stamp'
|
|
1409
|
+
specify "should override a previous ordering" do
|
|
1410
|
+
@dataset.order_by(:name).order(:stamp).sql.should == 'SELECT * FROM test ORDER BY stamp'
|
|
1378
1411
|
end
|
|
1379
1412
|
|
|
1380
1413
|
specify "should accept a string" do
|
|
1381
|
-
@dataset.order_by('dada ASC'.lit).sql.should ==
|
|
1382
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
|
1414
|
+
@dataset.order_by('dada ASC'.lit).sql.should == 'SELECT * FROM test ORDER BY dada ASC'
|
|
1383
1415
|
end
|
|
1384
1416
|
|
|
1385
1417
|
specify "should accept a nil to remove ordering" do
|
|
1386
|
-
@dataset.order_by(:bah).order_by(nil).sql.should ==
|
|
1387
|
-
'SELECT * FROM test'
|
|
1418
|
+
@dataset.order_by(:bah).order_by(nil).sql.should == 'SELECT * FROM test'
|
|
1388
1419
|
end
|
|
1389
1420
|
end
|
|
1390
1421
|
|
|
@@ -1417,13 +1448,11 @@ describe "Dataset#order_prepend" do
|
|
|
1417
1448
|
end
|
|
1418
1449
|
|
|
1419
1450
|
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'
|
|
1451
|
+
@dataset.order_prepend(:name).sql.should == 'SELECT * FROM test ORDER BY name'
|
|
1422
1452
|
end
|
|
1423
1453
|
|
|
1424
1454
|
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'
|
|
1455
|
+
@dataset.order(:name).order_prepend(:stamp.desc).sql.should == 'SELECT * FROM test ORDER BY stamp DESC, name'
|
|
1427
1456
|
end
|
|
1428
1457
|
|
|
1429
1458
|
specify "should accept a block that yields a virtual row" do
|
|
@@ -1438,45 +1467,36 @@ describe "Dataset#reverse_order" do
|
|
|
1438
1467
|
end
|
|
1439
1468
|
|
|
1440
1469
|
specify "should use DESC as default order" do
|
|
1441
|
-
@dataset.reverse_order(:name).sql.should ==
|
|
1442
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1470
|
+
@dataset.reverse_order(:name).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1443
1471
|
end
|
|
1444
1472
|
|
|
1445
1473
|
specify "should invert the order given" do
|
|
1446
|
-
@dataset.reverse_order(:name.desc).sql.should ==
|
|
1447
|
-
'SELECT * FROM test ORDER BY name ASC'
|
|
1474
|
+
@dataset.reverse_order(:name.desc).sql.should == 'SELECT * FROM test ORDER BY name ASC'
|
|
1448
1475
|
end
|
|
1449
1476
|
|
|
1450
1477
|
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'
|
|
1478
|
+
@dataset.reverse_order(:name.asc).sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1453
1479
|
end
|
|
1454
1480
|
|
|
1455
1481
|
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'
|
|
1482
|
+
@dataset.reverse_order(:name, :price.desc).sql.should == 'SELECT * FROM test ORDER BY name DESC, price ASC'
|
|
1458
1483
|
end
|
|
1459
1484
|
|
|
1460
1485
|
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'
|
|
1486
|
+
@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
1487
|
end
|
|
1464
1488
|
|
|
1465
1489
|
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'
|
|
1490
|
+
@dataset.order(:name).reverse_order.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1491
|
+
@dataset.order(:clumsy.desc, :fool).reverse_order.sql.should == 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
|
|
1470
1492
|
end
|
|
1471
1493
|
|
|
1472
1494
|
specify "should return an unordered dataset for a dataset with no order" do
|
|
1473
|
-
@dataset.unordered.reverse_order.sql.should ==
|
|
1474
|
-
'SELECT * FROM test'
|
|
1495
|
+
@dataset.unordered.reverse_order.sql.should == 'SELECT * FROM test'
|
|
1475
1496
|
end
|
|
1476
1497
|
|
|
1477
1498
|
specify "should have #reverse alias" do
|
|
1478
|
-
@dataset.order(:name).reverse.sql.should ==
|
|
1479
|
-
'SELECT * FROM test ORDER BY name DESC'
|
|
1499
|
+
@dataset.order(:name).reverse.sql.should == 'SELECT * FROM test ORDER BY name DESC'
|
|
1480
1500
|
end
|
|
1481
1501
|
end
|
|
1482
1502
|
|
|
@@ -1486,42 +1506,33 @@ describe "Dataset#limit" do
|
|
|
1486
1506
|
end
|
|
1487
1507
|
|
|
1488
1508
|
specify "should include a LIMIT clause in the select statement" do
|
|
1489
|
-
@dataset.limit(10).sql.should ==
|
|
1490
|
-
'SELECT * FROM test LIMIT 10'
|
|
1509
|
+
@dataset.limit(10).sql.should == 'SELECT * FROM test LIMIT 10'
|
|
1491
1510
|
end
|
|
1492
1511
|
|
|
1493
1512
|
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'
|
|
1513
|
+
@dataset.limit(3..7).sql.should == 'SELECT * FROM test LIMIT 5 OFFSET 3'
|
|
1514
|
+
@dataset.limit(3...7).sql.should == 'SELECT * FROM test LIMIT 4 OFFSET 3'
|
|
1499
1515
|
end
|
|
1500
1516
|
|
|
1501
1517
|
specify "should include an offset if a second argument is given" do
|
|
1502
|
-
@dataset.limit(6, 10).sql.should ==
|
|
1503
|
-
|
|
1504
|
-
end
|
|
1518
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 10'
|
|
1519
|
+
end
|
|
1505
1520
|
|
|
1506
1521
|
specify "should convert regular strings to integers" do
|
|
1507
|
-
@dataset.limit('6', 'a() - 1').sql.should ==
|
|
1508
|
-
'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1522
|
+
@dataset.limit('6', 'a() - 1').sql.should == 'SELECT * FROM test LIMIT 6 OFFSET 0'
|
|
1509
1523
|
end
|
|
1510
1524
|
|
|
1511
1525
|
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'
|
|
1526
|
+
@dataset.limit('6'.lit, 'a() - 1'.lit).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET a() - 1'
|
|
1514
1527
|
end
|
|
1515
1528
|
|
|
1516
1529
|
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)'
|
|
1530
|
+
@dataset.limit(6, :a.sql_function - 1).sql.should == 'SELECT * FROM test LIMIT 6 OFFSET (a() - 1)'
|
|
1519
1531
|
end
|
|
1520
1532
|
|
|
1521
1533
|
specify "should work with fixed sql datasets" do
|
|
1522
1534
|
@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'
|
|
1535
|
+
@dataset.limit(6, 10).sql.should == 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
|
|
1525
1536
|
end
|
|
1526
1537
|
|
|
1527
1538
|
specify "should raise an error if an invalid limit or offset is used" do
|
|
@@ -1535,15 +1546,10 @@ describe "Dataset#limit" do
|
|
|
1535
1546
|
end
|
|
1536
1547
|
|
|
1537
1548
|
describe "Dataset#naked" do
|
|
1538
|
-
before do
|
|
1539
|
-
@d1 = Sequel::Dataset.new(nil, {1 => 2, 3 => 4})
|
|
1540
|
-
@d2 = @d1.clone
|
|
1541
|
-
@d2.row_proc = Proc.new{|r| r}
|
|
1542
|
-
end
|
|
1543
|
-
|
|
1544
1549
|
specify "should remove any existing row_proc" do
|
|
1545
|
-
|
|
1546
|
-
|
|
1550
|
+
d = Sequel::Dataset.new(nil)
|
|
1551
|
+
d.row_proc = Proc.new{|r| r}
|
|
1552
|
+
d.naked.row_proc.should be_nil
|
|
1547
1553
|
end
|
|
1548
1554
|
end
|
|
1549
1555
|
|
|
@@ -1571,38 +1577,42 @@ describe "Dataset#qualified_column_name" do
|
|
|
1571
1577
|
end
|
|
1572
1578
|
end
|
|
1573
1579
|
|
|
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
1580
|
describe "Dataset#map" do
|
|
1586
1581
|
before do
|
|
1587
|
-
@d =
|
|
1582
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1588
1583
|
end
|
|
1589
1584
|
|
|
1590
1585
|
specify "should provide the usual functionality if no argument is given" do
|
|
1591
|
-
@d.map
|
|
1586
|
+
@d.map{|n| n[:a] + n[:b]}.should == [3, 7, 11]
|
|
1592
1587
|
end
|
|
1593
1588
|
|
|
1594
1589
|
specify "should map using #[column name] if column name is given" do
|
|
1595
1590
|
@d.map(:a).should == [1, 3, 5]
|
|
1596
1591
|
end
|
|
1597
1592
|
|
|
1593
|
+
specify "should support multiple column names if an array of column names is given" do
|
|
1594
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1595
|
+
end
|
|
1596
|
+
|
|
1597
|
+
specify "should not call the row_proc if an argument is given" do
|
|
1598
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1599
|
+
@d.map(:a).should == [1, 3, 5]
|
|
1600
|
+
@d.map([:a, :b]).should == [[1, 2], [3, 4], [5, 6]]
|
|
1601
|
+
end
|
|
1602
|
+
|
|
1603
|
+
specify "should call the row_proc if no argument is given" do
|
|
1604
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1605
|
+
@d.map{|n| n[:a] + n[:b]}.should == [6, 14, 22]
|
|
1606
|
+
end
|
|
1607
|
+
|
|
1598
1608
|
specify "should return the complete dataset values if nothing is given" do
|
|
1599
|
-
@d.map.to_a.should ==
|
|
1609
|
+
@d.map.to_a.should == [{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}]
|
|
1600
1610
|
end
|
|
1601
1611
|
end
|
|
1602
1612
|
|
|
1603
1613
|
describe "Dataset#to_hash" do
|
|
1604
1614
|
before do
|
|
1605
|
-
@d =
|
|
1615
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 5, :b => 6}])[:items]
|
|
1606
1616
|
end
|
|
1607
1617
|
|
|
1608
1618
|
specify "should provide a hash with the first column as key and the second as value" do
|
|
@@ -1614,11 +1624,35 @@ describe "Dataset#to_hash" do
|
|
|
1614
1624
|
@d.to_hash(:a).should == {1 => {:a => 1, :b => 2}, 3 => {:a => 3, :b => 4}, 5 => {:a => 5, :b => 6}}
|
|
1615
1625
|
@d.to_hash(:b).should == {2 => {:a => 1, :b => 2}, 4 => {:a => 3, :b => 4}, 6 => {:a => 5, :b => 6}}
|
|
1616
1626
|
end
|
|
1627
|
+
|
|
1628
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1629
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1630
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1631
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1632
|
+
@d.to_hash([:a, :b]).should == {[1, 2] => {:a => 1, :b => 2}, [3, 4] => {:a => 3, :b => 4}, [5, 6] => {:a => 5, :b => 6}}
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1635
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1636
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1637
|
+
@d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
|
|
1638
|
+
@d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
|
|
1639
|
+
@d.to_hash([:a, :b], :b).should == {[1, 2] => 2, [3, 4] => 4, [5, 6] => 6}
|
|
1640
|
+
@d.to_hash(:b, [:a, :b]).should == {2 => [1, 2], 4 => [3, 4], 6 => [5, 6]}
|
|
1641
|
+
@d.to_hash([:b, :a], [:a, :b]).should == {[2, 1] => [1, 2], [4, 3] => [3, 4], [6, 5] => [5, 6]}
|
|
1642
|
+
end
|
|
1643
|
+
|
|
1644
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1645
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1646
|
+
@d.to_hash(:a).should == {2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12}}
|
|
1647
|
+
@d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
|
|
1648
|
+
@d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
|
|
1649
|
+
end
|
|
1650
|
+
|
|
1617
1651
|
end
|
|
1618
1652
|
|
|
1619
1653
|
describe "Dataset#distinct" do
|
|
1620
1654
|
before do
|
|
1621
|
-
@db =
|
|
1655
|
+
@db = Sequel.mock
|
|
1622
1656
|
@dataset = @db[:test].select(:name)
|
|
1623
1657
|
end
|
|
1624
1658
|
|
|
@@ -1645,132 +1679,100 @@ end
|
|
|
1645
1679
|
|
|
1646
1680
|
describe "Dataset#count" do
|
|
1647
1681
|
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)
|
|
1682
|
+
@db = Sequel.mock(:fetch=>{:count=>1})
|
|
1683
|
+
@dataset = @db.from(:test).columns(:count)
|
|
1660
1684
|
end
|
|
1661
1685
|
|
|
1662
1686
|
specify "should format SQL properly" do
|
|
1663
1687
|
@dataset.count.should == 1
|
|
1664
|
-
@
|
|
1688
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LIMIT 1']
|
|
1665
1689
|
end
|
|
1666
1690
|
|
|
1667
1691
|
specify "should include the where clause if it's there" do
|
|
1668
1692
|
@dataset.filter(:abc.sql_number < 30).count.should == 1
|
|
1669
|
-
@
|
|
1693
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test WHERE (abc < 30) LIMIT 1']
|
|
1670
1694
|
end
|
|
1671
1695
|
|
|
1672
1696
|
specify "should count properly for datasets with fixed sql" do
|
|
1673
1697
|
@dataset.opts[:sql] = "select abc from xyz"
|
|
1674
1698
|
@dataset.count.should == 1
|
|
1675
|
-
@
|
|
1699
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
|
|
1676
1700
|
end
|
|
1677
1701
|
|
|
1678
1702
|
specify "should count properly when using UNION, INTERSECT, or EXCEPT" do
|
|
1679
1703
|
@dataset.union(@dataset).count.should == 1
|
|
1680
|
-
@
|
|
1704
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1681
1705
|
@dataset.intersect(@dataset).count.should == 1
|
|
1682
|
-
@
|
|
1706
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test INTERSECT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1683
1707
|
@dataset.except(@dataset).count.should == 1
|
|
1684
|
-
@
|
|
1708
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test EXCEPT SELECT * FROM test) AS t1 LIMIT 1"]
|
|
1685
1709
|
end
|
|
1686
1710
|
|
|
1687
1711
|
specify "should return limit if count is greater than it" do
|
|
1688
1712
|
@dataset.limit(5).count.should == 1
|
|
1689
|
-
@
|
|
1713
|
+
@db.sqls.should == ["SELECT COUNT(*) AS count FROM (SELECT * FROM test LIMIT 5) AS t1 LIMIT 1"]
|
|
1690
1714
|
end
|
|
1691
1715
|
|
|
1692
1716
|
it "should work on a graphed_dataset" do
|
|
1693
1717
|
@dataset.should_receive(:columns).twice.and_return([:a])
|
|
1694
1718
|
@dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
|
|
1695
|
-
@
|
|
1719
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
1696
1720
|
end
|
|
1697
1721
|
|
|
1698
1722
|
specify "should not cache the columns value" do
|
|
1699
|
-
ds = @dataset.from(:blah)
|
|
1723
|
+
ds = @dataset.from(:blah).columns(:a)
|
|
1700
1724
|
ds.columns.should == [:a]
|
|
1701
1725
|
ds.count.should == 1
|
|
1702
|
-
@
|
|
1726
|
+
@db.sqls.should == ['SELECT COUNT(*) AS count FROM blah LIMIT 1']
|
|
1703
1727
|
ds.columns.should == [:a]
|
|
1704
1728
|
end
|
|
1705
1729
|
end
|
|
1706
1730
|
|
|
1707
|
-
|
|
1708
1731
|
describe "Dataset#group_and_count" do
|
|
1709
1732
|
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)
|
|
1733
|
+
@ds = Sequel::Dataset.new(nil).from(:test)
|
|
1721
1734
|
end
|
|
1722
1735
|
|
|
1723
1736
|
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"
|
|
1737
|
+
@ds.group_and_count(:name).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1726
1738
|
end
|
|
1727
1739
|
|
|
1728
1740
|
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"
|
|
1741
|
+
@ds.group_and_count(:a, :b).sql.should == "SELECT a, b, count(*) AS count FROM test GROUP BY a, b"
|
|
1731
1742
|
end
|
|
1732
1743
|
|
|
1733
1744
|
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"
|
|
1745
|
+
@ds.group_and_count(:name___n).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1746
|
+
@ds.group_and_count(:name__n).sql.should == "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
|
1738
1747
|
end
|
|
1739
1748
|
|
|
1740
1749
|
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"
|
|
1750
|
+
@ds.group_and_count(:name___n.identifier).sql.should == "SELECT name___n, count(*) AS count FROM test GROUP BY name___n"
|
|
1743
1751
|
end
|
|
1744
1752
|
|
|
1745
1753
|
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"
|
|
1754
|
+
@ds.group_and_count("name".lit).sql.should == "SELECT name, count(*) AS count FROM test GROUP BY name"
|
|
1748
1755
|
end
|
|
1749
1756
|
|
|
1750
1757
|
specify "should handle aliased expressions" do
|
|
1751
|
-
@ds.group_and_count(:name.as(:n)).sql.should ==
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1758
|
+
@ds.group_and_count(:name.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1759
|
+
@ds.group_and_count(:name.identifier.as(:n)).sql.should == "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
|
1760
|
+
end
|
|
1761
|
+
|
|
1762
|
+
specify "should take a virtual row block" do
|
|
1763
|
+
@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)"
|
|
1764
|
+
@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)"
|
|
1765
|
+
@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
1766
|
end
|
|
1756
1767
|
end
|
|
1757
1768
|
|
|
1758
1769
|
describe "Dataset#empty?" do
|
|
1759
1770
|
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"
|
|
1771
|
+
db = Sequel.mock(:fetch=>proc{|sql| {1=>1} unless sql =~ /WHERE 'f'/})
|
|
1772
|
+
db.from(:test).should_not be_empty
|
|
1773
|
+
db.sqls.should == ['SELECT 1 FROM test LIMIT 1']
|
|
1774
|
+
db.from(:test).filter(false).should be_empty
|
|
1775
|
+
db.sqls.should == ["SELECT 1 FROM test WHERE 'f' LIMIT 1"]
|
|
1774
1776
|
end
|
|
1775
1777
|
end
|
|
1776
1778
|
|
|
@@ -1849,25 +1851,31 @@ describe "Dataset#from_self" do
|
|
|
1849
1851
|
'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
|
|
1850
1852
|
end
|
|
1851
1853
|
|
|
1852
|
-
specify "should not options such as server" do
|
|
1854
|
+
specify "should not remove non-SQL options such as :server" do
|
|
1853
1855
|
@ds.server(:blah).from_self(:alias=>:some_name).opts[:server].should == :blah
|
|
1854
1856
|
end
|
|
1855
1857
|
|
|
1858
|
+
specify "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
|
|
1859
|
+
ds = Sequel::Dataset.new(nil)
|
|
1860
|
+
ds.meta_def(:supports_cte?){true}
|
|
1861
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
1862
|
+
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'
|
|
1863
|
+
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'
|
|
1864
|
+
end
|
|
1856
1865
|
end
|
|
1857
1866
|
|
|
1858
1867
|
describe "Dataset#join_table" do
|
|
1859
1868
|
before do
|
|
1860
|
-
@d =
|
|
1869
|
+
@d = Sequel::Dataset.new(nil).from(:items)
|
|
1861
1870
|
@d.quote_identifiers = true
|
|
1862
1871
|
end
|
|
1863
1872
|
|
|
1864
1873
|
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")'
|
|
1874
|
+
@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
1875
|
end
|
|
1868
1876
|
|
|
1869
1877
|
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 ==
|
|
1878
|
+
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
|
1871
1879
|
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND ("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100))'
|
|
1872
1880
|
end
|
|
1873
1881
|
|
|
@@ -1877,45 +1885,30 @@ describe "Dataset#join_table" do
|
|
|
1877
1885
|
end
|
|
1878
1886
|
|
|
1879
1887
|
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"'
|
|
1888
|
+
@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
1889
|
end
|
|
1883
1890
|
|
|
1884
1891
|
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")'
|
|
1892
|
+
@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
1893
|
end
|
|
1888
1894
|
|
|
1889
1895
|
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")'
|
|
1896
|
+
@d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1892
1897
|
end
|
|
1893
1898
|
|
|
1894
1899
|
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"'
|
|
1900
|
+
@d.left_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1901
|
+
@d.right_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1902
|
+
@d.full_outer_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1903
|
+
@d.inner_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1904
|
+
@d.left_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" LEFT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1905
|
+
@d.right_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" RIGHT JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1906
|
+
@d.full_join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" FULL JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1907
|
+
@d.natural_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
1908
|
+
@d.natural_left_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL LEFT JOIN "categories"'
|
|
1909
|
+
@d.natural_right_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL RIGHT JOIN "categories"'
|
|
1910
|
+
@d.natural_full_join(:categories).sql.should == 'SELECT * FROM "items" NATURAL FULL JOIN "categories"'
|
|
1911
|
+
@d.cross_join(:categories).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
1919
1912
|
end
|
|
1920
1913
|
|
|
1921
1914
|
specify "should raise an error if additional arguments are provided to join methods that don't take conditions" do
|
|
@@ -1935,95 +1928,68 @@ describe "Dataset#join_table" do
|
|
|
1935
1928
|
end
|
|
1936
1929
|
|
|
1937
1930
|
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")'
|
|
1931
|
+
@d.join_table(nil, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1940
1932
|
end
|
|
1941
1933
|
|
|
1942
1934
|
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")'
|
|
1935
|
+
@d.join(:categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
|
1945
1936
|
end
|
|
1946
1937
|
|
|
1947
1938
|
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")'
|
|
1939
|
+
@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
1940
|
end
|
|
1951
1941
|
|
|
1952
1942
|
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")'
|
|
1943
|
+
@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
1944
|
end
|
|
1956
1945
|
|
|
1957
1946
|
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")'
|
|
1947
|
+
@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
1948
|
end
|
|
1961
1949
|
|
|
1962
1950
|
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")'
|
|
1951
|
+
@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
1952
|
end
|
|
1968
1953
|
|
|
1969
1954
|
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")'
|
|
1955
|
+
@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
1956
|
end
|
|
1973
1957
|
|
|
1974
1958
|
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")'
|
|
1959
|
+
@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")'
|
|
1960
|
+
@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
1961
|
end
|
|
1980
1962
|
|
|
1981
1963
|
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")'
|
|
1964
|
+
@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
1965
|
end
|
|
1985
1966
|
|
|
1986
1967
|
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")'
|
|
1968
|
+
@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
1969
|
end
|
|
1990
1970
|
|
|
1991
1971
|
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))'
|
|
1972
|
+
@d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
|
1973
|
+
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
|
1974
|
+
@d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
|
1975
|
+
@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
1976
|
end
|
|
2001
1977
|
|
|
2002
1978
|
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)
|
|
1979
|
+
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}.should raise_error(Sequel::Error)
|
|
2005
1980
|
end
|
|
2006
1981
|
|
|
2007
1982
|
specify "should support joining datasets" do
|
|
2008
1983
|
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
|
-
|
|
1984
|
+
@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
1985
|
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")'
|
|
1986
|
+
@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")'
|
|
1987
|
+
@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
1988
|
end
|
|
2021
1989
|
|
|
2022
1990
|
specify "should support joining datasets and aliasing the join" do
|
|
2023
1991
|
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")'
|
|
1992
|
+
@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
1993
|
end
|
|
2028
1994
|
|
|
2029
1995
|
specify "should support joining multiple datasets" do
|
|
@@ -2040,40 +2006,30 @@ describe "Dataset#join_table" do
|
|
|
2040
2006
|
specify "should support joining objects that respond to :table_name" do
|
|
2041
2007
|
ds = Object.new
|
|
2042
2008
|
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")'
|
|
2009
|
+
@d.join(ds, :item_id => :id).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
|
|
2046
2010
|
end
|
|
2047
2011
|
|
|
2048
|
-
specify "should support using
|
|
2049
|
-
@d.join(:categories,
|
|
2050
|
-
'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
|
2012
|
+
specify "should support using an SQL String as the join condition" do
|
|
2013
|
+
@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
2014
|
end
|
|
2052
2015
|
|
|
2053
2016
|
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"'
|
|
2017
|
+
@d.join(:categories, :active).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
|
2056
2018
|
end
|
|
2057
2019
|
|
|
2058
2020
|
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)'
|
|
2021
|
+
@d.join(:categories, :number.sql_number > 10).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
|
2061
2022
|
end
|
|
2062
2023
|
|
|
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"'
|
|
2024
|
+
specify "should support natural and cross joins" do
|
|
2025
|
+
@d.join_table(:natural, :categories).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories"'
|
|
2026
|
+
@d.join_table(:cross, :categories, nil).sql.should == 'SELECT * FROM "items" CROSS JOIN "categories"'
|
|
2027
|
+
@d.join_table(:natural, :categories, nil, :c).sql.should == 'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
|
2070
2028
|
end
|
|
2071
2029
|
|
|
2072
2030
|
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")'
|
|
2031
|
+
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
|
|
2032
|
+
@d.join(:categories, [:id1, :id2]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
|
2077
2033
|
end
|
|
2078
2034
|
|
|
2079
2035
|
specify "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
|
|
@@ -2081,6 +2037,12 @@ describe "Dataset#join_table" do
|
|
|
2081
2037
|
@d.join(:categories, [:id]).sql.should == 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."id" = "items"."id")'
|
|
2082
2038
|
end
|
|
2083
2039
|
|
|
2040
|
+
specify "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
|
|
2041
|
+
@d.meta_def(:supports_cte?){true}
|
|
2042
|
+
@d.meta_def(:supports_cte_in_subselect?){false}
|
|
2043
|
+
@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")'
|
|
2044
|
+
end
|
|
2045
|
+
|
|
2084
2046
|
specify "should raise an error if using an array of symbols with a block" do
|
|
2085
2047
|
proc{@d.join(:categories, [:id]){|j,lj,js|}}.should raise_error(Sequel::Error)
|
|
2086
2048
|
end
|
|
@@ -2135,27 +2097,21 @@ describe "Dataset#join_table" do
|
|
|
2135
2097
|
end
|
|
2136
2098
|
|
|
2137
2099
|
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")'
|
|
2100
|
+
@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")'
|
|
2101
|
+
@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
2102
|
end
|
|
2143
2103
|
|
|
2144
2104
|
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"))'
|
|
2105
|
+
@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"))'
|
|
2106
|
+
@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
2107
|
end
|
|
2150
2108
|
|
|
2151
2109
|
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")'
|
|
2110
|
+
@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
2111
|
@d.from(:items.as(:i)).join(:categories.as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.should ==
|
|
2155
2112
|
'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
|
2156
2113
|
end
|
|
2157
2114
|
|
|
2158
|
-
|
|
2159
2115
|
specify "should not allow insert, update, delete, or truncate" do
|
|
2160
2116
|
proc{@d.join(:categories, :a=>:d).insert_sql}.should raise_error(Sequel::InvalidOperation)
|
|
2161
2117
|
proc{@d.join(:categories, :a=>:d).update_sql(:a=>1)}.should raise_error(Sequel::InvalidOperation)
|
|
@@ -2170,81 +2126,48 @@ describe "Dataset#join_table" do
|
|
|
2170
2126
|
end
|
|
2171
2127
|
|
|
2172
2128
|
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
2129
|
specify "should perform an update on the specified filter" do
|
|
2188
|
-
|
|
2189
|
-
|
|
2130
|
+
db = Sequel.mock
|
|
2131
|
+
ds = db[:items]
|
|
2132
|
+
ds[:a => 1] = {:x => 3}
|
|
2133
|
+
db.sqls.should == ['UPDATE items SET x = 3 WHERE (a = 1)']
|
|
2190
2134
|
end
|
|
2191
2135
|
end
|
|
2192
2136
|
|
|
2193
2137
|
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
2138
|
specify "should act as alias to #update" do
|
|
2209
|
-
|
|
2210
|
-
|
|
2139
|
+
db = Sequel.mock
|
|
2140
|
+
ds = db[:items]
|
|
2141
|
+
ds.set({:x => 3})
|
|
2142
|
+
db.sqls.should == ['UPDATE items SET x = 3']
|
|
2211
2143
|
end
|
|
2212
2144
|
end
|
|
2213
2145
|
|
|
2214
|
-
|
|
2215
2146
|
describe "Dataset#insert_multiple" do
|
|
2216
2147
|
before do
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
def insert(arg)
|
|
2220
|
-
@inserts ||= []
|
|
2221
|
-
@inserts << arg
|
|
2222
|
-
end
|
|
2223
|
-
end
|
|
2224
|
-
|
|
2225
|
-
@d = c.new(nil)
|
|
2148
|
+
@db = Sequel.mock
|
|
2149
|
+
@ds = @db[:items]
|
|
2226
2150
|
end
|
|
2227
2151
|
|
|
2228
2152
|
specify "should insert all items in the supplied array" do
|
|
2229
|
-
@
|
|
2230
|
-
@
|
|
2153
|
+
@ds.insert_multiple(['aa', 5, 3, {:a => 2}])
|
|
2154
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('aa')",
|
|
2155
|
+
"INSERT INTO items VALUES (5)",
|
|
2156
|
+
"INSERT INTO items VALUES (3)",
|
|
2157
|
+
"INSERT INTO items (a) VALUES (2)"]
|
|
2231
2158
|
end
|
|
2232
2159
|
|
|
2233
2160
|
specify "should pass array items through the supplied block if given" do
|
|
2234
|
-
|
|
2235
|
-
@
|
|
2236
|
-
|
|
2161
|
+
@ds.insert_multiple(["inevitable", "hello", "the ticking clock"]){|i| i.gsub('l', 'r')}
|
|
2162
|
+
@db.sqls.should == ["INSERT INTO items VALUES ('inevitabre')",
|
|
2163
|
+
"INSERT INTO items VALUES ('herro')",
|
|
2164
|
+
"INSERT INTO items VALUES ('the ticking crock')"]
|
|
2237
2165
|
end
|
|
2238
2166
|
end
|
|
2239
2167
|
|
|
2240
2168
|
describe "Dataset aggregate methods" do
|
|
2241
2169
|
before do
|
|
2242
|
-
|
|
2243
|
-
def fetch_rows(sql)
|
|
2244
|
-
yield({1 => sql})
|
|
2245
|
-
end
|
|
2246
|
-
end
|
|
2247
|
-
@d = c.new(nil).from(:test)
|
|
2170
|
+
@d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
|
|
2248
2171
|
end
|
|
2249
2172
|
|
|
2250
2173
|
specify "should include min" do
|
|
@@ -2278,116 +2201,88 @@ end
|
|
|
2278
2201
|
|
|
2279
2202
|
describe "Dataset#range" do
|
|
2280
2203
|
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)
|
|
2204
|
+
@db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
|
|
2205
|
+
@ds = @db[:test]
|
|
2292
2206
|
end
|
|
2293
2207
|
|
|
2294
2208
|
specify "should generate a correct SQL statement" do
|
|
2295
|
-
@
|
|
2296
|
-
@
|
|
2209
|
+
@ds.range(:stamp)
|
|
2210
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
|
|
2297
2211
|
|
|
2298
|
-
@
|
|
2299
|
-
@
|
|
2212
|
+
@ds.filter(:price.sql_number > 100).range(:stamp)
|
|
2213
|
+
@db.sqls.should == ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
|
|
2300
2214
|
end
|
|
2301
2215
|
|
|
2302
2216
|
specify "should return a range object" do
|
|
2303
|
-
@
|
|
2217
|
+
@ds.range(:tryme).should == (1..10)
|
|
2304
2218
|
end
|
|
2305
2219
|
|
|
2306
2220
|
specify "should use a subselect for the same conditions as count" do
|
|
2307
|
-
@
|
|
2308
|
-
@
|
|
2221
|
+
@ds.order(:stamp).limit(5).range(:stamp).should == (1..10)
|
|
2222
|
+
@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
2223
|
end
|
|
2310
2224
|
end
|
|
2311
2225
|
|
|
2312
2226
|
describe "Dataset#interval" do
|
|
2313
2227
|
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)
|
|
2228
|
+
@db = Sequel.mock(:fetch=>{:v => 1234})
|
|
2229
|
+
@ds = @db[:test]
|
|
2325
2230
|
end
|
|
2326
2231
|
|
|
2327
|
-
specify "should generate
|
|
2328
|
-
@
|
|
2329
|
-
@
|
|
2232
|
+
specify "should generate the correct SQL statement" do
|
|
2233
|
+
@ds.interval(:stamp)
|
|
2234
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"]
|
|
2330
2235
|
|
|
2331
|
-
@
|
|
2332
|
-
@
|
|
2333
|
-
end
|
|
2334
|
-
|
|
2335
|
-
specify "should return an integer" do
|
|
2336
|
-
@d.interval(:tryme).should == 1234
|
|
2236
|
+
@ds.filter(:price.sql_number > 100).interval(:stamp)
|
|
2237
|
+
@db.sqls.should == ["SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"]
|
|
2337
2238
|
end
|
|
2338
2239
|
|
|
2339
2240
|
specify "should use a subselect for the same conditions as count" do
|
|
2340
|
-
@
|
|
2341
|
-
@
|
|
2241
|
+
@ds.order(:stamp).limit(5).interval(:stamp).should == 1234
|
|
2242
|
+
@db.sqls.should == ['SELECT (max(stamp) - min(stamp)) FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
|
|
2342
2243
|
end
|
|
2343
2244
|
end
|
|
2344
2245
|
|
|
2345
2246
|
describe "Dataset #first and #last" do
|
|
2346
2247
|
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)
|
|
2248
|
+
@db = Sequel.mock(:fetch=>proc{|s| {:s=>s}})
|
|
2249
|
+
@d = @db[:test]
|
|
2355
2250
|
end
|
|
2356
2251
|
|
|
2357
2252
|
specify "should return a single record if no argument is given" do
|
|
2358
|
-
@d.order(:a).first.should ==
|
|
2359
|
-
@d.order(:a).last.should ==
|
|
2253
|
+
@d.order(:a).first.should == {:s=>'SELECT * FROM test ORDER BY a LIMIT 1'}
|
|
2254
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2360
2255
|
end
|
|
2361
2256
|
|
|
2362
2257
|
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 ==
|
|
2258
|
+
@d.order(:a).first(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1'}
|
|
2259
|
+
@d.order(:a).first('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1'}
|
|
2260
|
+
@d.order(:a).last(:z => 26).should == {:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1'}
|
|
2261
|
+
@d.order(:a).last('z = ?', 15).should == {:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1'}
|
|
2367
2262
|
end
|
|
2368
2263
|
|
|
2369
2264
|
specify "should set the limit and return an array of records if the given number is > 1" do
|
|
2370
2265
|
i = rand(10) + 10
|
|
2371
|
-
r = @d.order(:a).first(i).should == [
|
|
2266
|
+
r = @d.order(:a).first(i).should == [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
|
|
2372
2267
|
i = rand(10) + 10
|
|
2373
|
-
r = @d.order(:a).last(i).should == [
|
|
2268
|
+
r = @d.order(:a).last(i).should == [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
|
|
2374
2269
|
end
|
|
2375
2270
|
|
|
2376
2271
|
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 ==
|
|
2272
|
+
@d.first{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1'}
|
|
2273
|
+
@d.order(:name).last{:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1'}
|
|
2379
2274
|
end
|
|
2380
2275
|
|
|
2381
2276
|
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 ==
|
|
2277
|
+
@d.first(:y=>25){:z.sql_number > 26}.should == {:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1'}
|
|
2278
|
+
@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
2279
|
end
|
|
2385
2280
|
|
|
2386
2281
|
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
|
2387
2282
|
i = rand(10) + 10
|
|
2388
|
-
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [
|
|
2283
|
+
r = @d.order(:a).first(i){:z.sql_number > 26}.should == [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
|
|
2389
2284
|
i = rand(10) + 10
|
|
2390
|
-
r = @d.order(:a).last(i){:z.sql_number > 26}.should == [
|
|
2285
|
+
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
2286
|
end
|
|
2392
2287
|
|
|
2393
2288
|
specify "#last should raise if no order is given" do
|
|
@@ -2398,10 +2293,10 @@ describe "Dataset #first and #last" do
|
|
|
2398
2293
|
end
|
|
2399
2294
|
|
|
2400
2295
|
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.
|
|
2296
|
+
@d.order(:a).last.should == {:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1'}
|
|
2297
|
+
@d.order(:b.desc).last.should == {:s=>'SELECT * FROM test ORDER BY b ASC LIMIT 1'}
|
|
2298
|
+
@d.order(:c, :d).last.should == {:s=>'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'}
|
|
2299
|
+
@d.order(:e.desc, :f).last.should == {:s=>'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'}
|
|
2405
2300
|
end
|
|
2406
2301
|
end
|
|
2407
2302
|
|
|
@@ -2412,55 +2307,37 @@ describe "Dataset compound operations" do
|
|
|
2412
2307
|
end
|
|
2413
2308
|
|
|
2414
2309
|
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"
|
|
2310
|
+
@a.union(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2311
|
+
@b.union(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2312
|
+
@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
2313
|
end
|
|
2422
2314
|
|
|
2423
2315
|
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"
|
|
2316
|
+
@a.intersect(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2317
|
+
@b.intersect(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2318
|
+
@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
2319
|
end
|
|
2431
2320
|
|
|
2432
2321
|
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"
|
|
2322
|
+
@a.except(@b).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)) AS t1"
|
|
2323
|
+
@b.except(@a, true).sql.should == "SELECT * FROM (SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)) AS t1"
|
|
2324
|
+
@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
2325
|
end
|
|
2440
2326
|
|
|
2441
2327
|
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"
|
|
2328
|
+
@a.union(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2329
|
+
@a.intersect(@b, :alias=>:xx).sql.should == "SELECT * FROM (SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)) AS xx"
|
|
2330
|
+
@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
2331
|
end
|
|
2449
2332
|
|
|
2450
2333
|
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)"
|
|
2334
|
+
@b.union(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) UNION SELECT * FROM a WHERE (z = 1)"
|
|
2335
|
+
@b.intersect(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT SELECT * FROM a WHERE (z = 1)"
|
|
2336
|
+
@b.except(@a, :from_self=>false).sql.should == "SELECT * FROM b WHERE (z = 2) EXCEPT SELECT * FROM a WHERE (z = 1)"
|
|
2457
2337
|
|
|
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)"
|
|
2338
|
+
@b.union(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
|
|
2339
|
+
@b.intersect(@a, :from_self=>false, :all=>true).sql.should == "SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
|
2340
|
+
@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
2341
|
end
|
|
2465
2342
|
|
|
2466
2343
|
specify "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
|
|
@@ -2480,141 +2357,105 @@ describe "Dataset compound operations" do
|
|
|
2480
2357
|
end
|
|
2481
2358
|
|
|
2482
2359
|
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"
|
|
2360
|
+
@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"
|
|
2361
|
+
@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"
|
|
2362
|
+
@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
2363
|
end
|
|
2490
2364
|
|
|
2491
2365
|
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"
|
|
2366
|
+
@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"
|
|
2367
|
+
@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"
|
|
2368
|
+
@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
2369
|
end
|
|
2499
2370
|
|
|
2500
2371
|
specify "should order and limit properly when using UNION, INTERSECT, or EXCEPT" do
|
|
2501
2372
|
@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"
|
|
2373
|
+
@dataset.union(@dataset).limit(2).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 LIMIT 2"
|
|
2374
|
+
@dataset.limit(2).intersect(@dataset).sql.should == "SELECT * FROM (SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1 INTERSECT SELECT * FROM test) AS t1"
|
|
2375
|
+
@dataset.except(@dataset.limit(2)).sql.should == "SELECT * FROM (SELECT * FROM test EXCEPT SELECT * FROM (SELECT * FROM test LIMIT 2) AS t1) AS t1"
|
|
2376
|
+
|
|
2377
|
+
@dataset.union(@dataset).order(:num).sql.should == "SELECT * FROM (SELECT * FROM test UNION SELECT * FROM test) AS t1 ORDER BY num"
|
|
2378
|
+
@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"
|
|
2379
|
+
@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
2380
|
|
|
2516
2381
|
@dataset.limit(2).order(:a).union(@dataset.limit(3).order(:b)).order(:c).limit(4).sql.should ==
|
|
2517
2382
|
"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
2383
|
end
|
|
2519
2384
|
|
|
2385
|
+
specify "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
|
|
2386
|
+
ds = Sequel::Dataset.new(nil)
|
|
2387
|
+
ds.meta_def(:supports_cte?){true}
|
|
2388
|
+
ds.meta_def(:supports_cte_in_subselect?){false}
|
|
2389
|
+
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'
|
|
2390
|
+
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'
|
|
2391
|
+
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'
|
|
2392
|
+
end
|
|
2520
2393
|
end
|
|
2521
2394
|
|
|
2522
2395
|
describe "Dataset#[]" do
|
|
2523
2396
|
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)
|
|
2397
|
+
@db = Sequel.mock(:fetch=>{1 => 2, 3 => 4})
|
|
2398
|
+
@d = @db[:items]
|
|
2537
2399
|
end
|
|
2538
2400
|
|
|
2539
2401
|
specify "should return a single record filtered according to the given conditions" do
|
|
2540
2402
|
@d[:name => 'didi'].should == {1 => 2, 3 => 4}
|
|
2541
|
-
@
|
|
2403
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (name = 'didi') LIMIT 1"]
|
|
2542
2404
|
|
|
2543
2405
|
@d[:id => 5..45].should == {1 => 2, 3 => 4}
|
|
2544
|
-
@
|
|
2406
|
+
@db.sqls.should == ["SELECT * FROM items WHERE ((id >= 5) AND (id <= 45)) LIMIT 1"]
|
|
2545
2407
|
end
|
|
2546
2408
|
end
|
|
2547
2409
|
|
|
2548
2410
|
describe "Dataset#single_record" do
|
|
2549
2411
|
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)
|
|
2412
|
+
@db = Sequel.mock
|
|
2561
2413
|
end
|
|
2562
2414
|
|
|
2563
2415
|
specify "should call each with a limit of 1 and return the record" do
|
|
2564
|
-
@
|
|
2416
|
+
@db.fetch = {:a=>1}
|
|
2417
|
+
@db[:test].single_record.should == {:a=>1}
|
|
2418
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2565
2419
|
end
|
|
2566
2420
|
|
|
2567
2421
|
specify "should return nil if no record is present" do
|
|
2568
|
-
@
|
|
2422
|
+
@db[:test].single_record.should be_nil
|
|
2423
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2569
2424
|
end
|
|
2570
2425
|
end
|
|
2571
2426
|
|
|
2572
2427
|
describe "Dataset#single_value" do
|
|
2573
2428
|
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)
|
|
2429
|
+
@db = Sequel.mock
|
|
2585
2430
|
end
|
|
2586
2431
|
|
|
2587
2432
|
specify "should call each and return the first value of the first record" do
|
|
2588
|
-
@
|
|
2433
|
+
@db.fetch = {:a=>1}
|
|
2434
|
+
@db[:test].single_value.should == 1
|
|
2435
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2589
2436
|
end
|
|
2590
2437
|
|
|
2591
2438
|
specify "should return nil if no records" do
|
|
2592
|
-
@
|
|
2439
|
+
@db[:test].single_value.should be_nil
|
|
2440
|
+
@db.sqls.should == ['SELECT * FROM test LIMIT 1']
|
|
2593
2441
|
end
|
|
2594
2442
|
|
|
2595
2443
|
it "should work on a graphed_dataset" do
|
|
2596
|
-
@
|
|
2597
|
-
@
|
|
2444
|
+
@db.fetch = {:a=>1}
|
|
2445
|
+
ds = @db[:test].columns(:a)
|
|
2446
|
+
ds.graph(ds, [:a], :table_alias=>:test2).single_value.should == 1
|
|
2447
|
+
@db.sqls.should == ['SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
|
|
2598
2448
|
end
|
|
2599
2449
|
end
|
|
2600
2450
|
|
|
2601
2451
|
describe "Dataset#get" do
|
|
2602
2452
|
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)
|
|
2453
|
+
@d = Sequel.mock(:fetch=>proc{|s| {:name=>s}})[:test]
|
|
2613
2454
|
end
|
|
2614
2455
|
|
|
2615
2456
|
specify "should select the specified column and fetch its value" do
|
|
2616
2457
|
@d.get(:name).should == "SELECT name FROM test LIMIT 1"
|
|
2617
|
-
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2458
|
+
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1"
|
|
2618
2459
|
end
|
|
2619
2460
|
|
|
2620
2461
|
specify "should work with filters" do
|
|
@@ -2637,239 +2478,206 @@ end
|
|
|
2637
2478
|
|
|
2638
2479
|
describe "Dataset#set_row_proc" do
|
|
2639
2480
|
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)
|
|
2481
|
+
@db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
|
|
2482
|
+
@dataset = @db[:items]
|
|
2483
|
+
@dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
|
|
2647
2484
|
end
|
|
2648
2485
|
|
|
2649
2486
|
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
2487
|
rows = @dataset.all
|
|
2653
|
-
rows.
|
|
2654
|
-
|
|
2655
|
-
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
|
2488
|
+
rows.map{|h| h[:der]}.should == [3, 4]
|
|
2489
|
+
@db.sqls.should == ['SELECT * FROM items']
|
|
2656
2490
|
end
|
|
2657
2491
|
|
|
2658
2492
|
specify "should be copied over when dataset is cloned" do
|
|
2659
|
-
@dataset.
|
|
2660
|
-
|
|
2661
|
-
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
|
2493
|
+
@dataset.filter(:a => 1).all.should == [{:a=>1, :der=>3}, {:a=>2, :der=>4}]
|
|
2662
2494
|
end
|
|
2663
2495
|
end
|
|
2664
2496
|
|
|
2665
2497
|
describe "Dataset#<<" do
|
|
2666
2498
|
before do
|
|
2667
|
-
@
|
|
2668
|
-
@d.meta_def(:insert) do |*args|
|
|
2669
|
-
1234567890
|
|
2670
|
-
end
|
|
2499
|
+
@db = Sequel.mock
|
|
2671
2500
|
end
|
|
2672
|
-
|
|
2501
|
+
|
|
2673
2502
|
specify "should call #insert" do
|
|
2674
|
-
|
|
2503
|
+
@db[:items] << {:name => 1}
|
|
2504
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)']
|
|
2505
|
+
end
|
|
2506
|
+
|
|
2507
|
+
specify "should be chainable" do
|
|
2508
|
+
@db[:items] << {:name => 1} << @db[:old_items].select(:name)
|
|
2509
|
+
@db.sqls.should == ['INSERT INTO items (name) VALUES (1)', 'INSERT INTO items SELECT name FROM old_items']
|
|
2675
2510
|
end
|
|
2676
2511
|
end
|
|
2677
2512
|
|
|
2678
2513
|
describe "Dataset#columns" do
|
|
2679
2514
|
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}
|
|
2515
|
+
@dataset = Sequel.mock[:items]
|
|
2684
2516
|
end
|
|
2685
2517
|
|
|
2686
2518
|
specify "should return the value of @columns if @columns is not nil" do
|
|
2687
|
-
@dataset.columns
|
|
2688
|
-
@dataset.
|
|
2519
|
+
@dataset.columns(:a, :b, :c).columns.should == [:a, :b, :c]
|
|
2520
|
+
@dataset.db.sqls.should == []
|
|
2689
2521
|
end
|
|
2690
2522
|
|
|
2691
2523
|
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
|
-
|
|
2524
|
+
@dataset.db.columns = [:a]
|
|
2525
|
+
@dataset.columns.should == [:a]
|
|
2526
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2527
|
+
end
|
|
2528
|
+
|
|
2529
|
+
specify "should be cleared if you change the selected columns" do
|
|
2530
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2531
|
+
@dataset.columns.should == [:a]
|
|
2532
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2533
|
+
@dataset.columns.should == [:a]
|
|
2534
|
+
@dataset.db.sqls.should == []
|
|
2535
|
+
ds = @dataset.select{foo{}}
|
|
2536
|
+
ds.columns.should == [:b]
|
|
2537
|
+
@dataset.db.sqls.should == ['SELECT foo() FROM items LIMIT 1']
|
|
2538
|
+
end
|
|
2539
|
+
|
|
2540
|
+
specify "should be cleared if you change the FROM table" do
|
|
2541
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2542
|
+
@dataset.columns.should == [:a]
|
|
2543
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2544
|
+
ds = @dataset.from(:foo)
|
|
2545
|
+
ds.columns.should == [:b]
|
|
2546
|
+
@dataset.db.sqls.should == ['SELECT * FROM foo LIMIT 1']
|
|
2547
|
+
end
|
|
2548
|
+
|
|
2549
|
+
specify "should be cleared if you join a table to the dataset" do
|
|
2550
|
+
@dataset.db.columns = [[:a], [:a, :b]]
|
|
2551
|
+
@dataset.columns.should == [:a]
|
|
2552
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2553
|
+
ds = @dataset.cross_join(:foo)
|
|
2554
|
+
ds.columns.should == [:a, :b]
|
|
2555
|
+
@dataset.db.sqls.should == ['SELECT * FROM items CROSS JOIN foo LIMIT 1']
|
|
2556
|
+
end
|
|
2557
|
+
|
|
2558
|
+
specify "should be cleared if you set custom SQL for the dataset" do
|
|
2559
|
+
@dataset.db.columns = [[:a], [:b]]
|
|
2560
|
+
@dataset.columns.should == [:a]
|
|
2561
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2562
|
+
ds = @dataset.with_sql('SELECT b FROM foo')
|
|
2563
|
+
ds.columns.should == [:b]
|
|
2564
|
+
@dataset.db.sqls.should == ['SELECT b FROM foo']
|
|
2696
2565
|
end
|
|
2697
2566
|
|
|
2698
2567
|
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
|
2568
|
+
@dataset.db.columns = [:a]
|
|
2699
2569
|
@dataset.filter!(:b=>100).order!(:b).distinct!
|
|
2700
|
-
@dataset.columns
|
|
2701
|
-
@dataset.
|
|
2570
|
+
@dataset.columns.should == [:a]
|
|
2571
|
+
@dataset.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2702
2572
|
end
|
|
2703
2573
|
end
|
|
2704
2574
|
|
|
2705
2575
|
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
2576
|
specify "should always attempt to get a record and return @columns" do
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2577
|
+
ds = Sequel.mock(:columns=>[[:a, :b, :c], [:d, :e, :f]])[:items]
|
|
2578
|
+
ds.columns!.should == [:a, :b, :c]
|
|
2579
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2580
|
+
ds.columns!.should == [:d, :e, :f]
|
|
2581
|
+
ds.db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
|
2717
2582
|
end
|
|
2718
2583
|
end
|
|
2719
2584
|
|
|
2720
2585
|
describe "Dataset#import" do
|
|
2721
2586
|
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'}]
|
|
2587
|
+
@db = Sequel.mock
|
|
2588
|
+
@ds = @db[:items]
|
|
2743
2589
|
end
|
|
2744
2590
|
|
|
2745
2591
|
specify "should accept string keys as column names" do
|
|
2746
2592
|
@ds.import(['x', 'y'], [[1, 2], [3, 4]])
|
|
2747
|
-
@db.sqls.should == [
|
|
2748
|
-
'BEGIN',
|
|
2593
|
+
@db.sqls.should == ['BEGIN',
|
|
2749
2594
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2750
2595
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2751
|
-
'COMMIT'
|
|
2752
|
-
]
|
|
2596
|
+
'COMMIT']
|
|
2753
2597
|
end
|
|
2754
2598
|
|
|
2755
2599
|
specify "should accept a columns array and a values array" do
|
|
2756
2600
|
@ds.import([:x, :y], [[1, 2], [3, 4]])
|
|
2757
|
-
@db.sqls.should == [
|
|
2758
|
-
'BEGIN',
|
|
2601
|
+
@db.sqls.should == ['BEGIN',
|
|
2759
2602
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2760
2603
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2761
|
-
'COMMIT'
|
|
2762
|
-
]
|
|
2604
|
+
'COMMIT']
|
|
2763
2605
|
end
|
|
2764
2606
|
|
|
2765
2607
|
specify "should accept a columns array and a dataset" do
|
|
2766
|
-
@ds2 =
|
|
2608
|
+
@ds2 = @ds.from(:cats).filter(:purr => true).select(:a, :b)
|
|
2767
2609
|
|
|
2768
2610
|
@ds.import([:x, :y], @ds2)
|
|
2769
|
-
@db.sqls.should == [
|
|
2770
|
-
'BEGIN',
|
|
2611
|
+
@db.sqls.should == ['BEGIN',
|
|
2771
2612
|
"INSERT INTO items (x, y) SELECT a, b FROM cats WHERE (purr IS TRUE)",
|
|
2772
|
-
'COMMIT'
|
|
2773
|
-
]
|
|
2613
|
+
'COMMIT']
|
|
2774
2614
|
end
|
|
2775
2615
|
|
|
2776
2616
|
specify "should accept a columns array and a values array with :commit_every option" do
|
|
2777
2617
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :commit_every => 3)
|
|
2778
|
-
@db.sqls.should == [
|
|
2779
|
-
'BEGIN',
|
|
2618
|
+
@db.sqls.should == ['BEGIN',
|
|
2780
2619
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2781
2620
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2782
2621
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2783
|
-
'COMMIT'
|
|
2784
|
-
]
|
|
2622
|
+
'COMMIT']
|
|
2785
2623
|
end
|
|
2786
|
-
specify "should accept a columns array and a values array with slice option" do
|
|
2624
|
+
specify "should accept a columns array and a values array with :slice option" do
|
|
2787
2625
|
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
|
2788
|
-
@db.sqls.should == [
|
|
2789
|
-
'BEGIN',
|
|
2626
|
+
@db.sqls.should == ['BEGIN',
|
|
2790
2627
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2791
2628
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2792
2629
|
'COMMIT',
|
|
2793
2630
|
'BEGIN',
|
|
2794
2631
|
"INSERT INTO items (x, y) VALUES (5, 6)",
|
|
2795
|
-
'COMMIT'
|
|
2796
|
-
]
|
|
2632
|
+
'COMMIT']
|
|
2797
2633
|
end
|
|
2798
2634
|
end
|
|
2799
2635
|
|
|
2800
2636
|
describe "Dataset#multi_insert" do
|
|
2801
2637
|
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
|
-
|
|
2638
|
+
@db = Sequel.mock
|
|
2639
|
+
@ds = @db[:items]
|
|
2822
2640
|
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
|
2823
2641
|
end
|
|
2824
2642
|
|
|
2825
2643
|
specify "should issue multiple insert statements inside a transaction" do
|
|
2826
2644
|
@ds.multi_insert(@list)
|
|
2827
|
-
@db.sqls.should == [
|
|
2828
|
-
'BEGIN',
|
|
2645
|
+
@db.sqls.should == ['BEGIN',
|
|
2829
2646
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2830
2647
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2831
2648
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2832
|
-
'COMMIT'
|
|
2833
|
-
]
|
|
2649
|
+
'COMMIT']
|
|
2834
2650
|
end
|
|
2835
2651
|
|
|
2836
2652
|
specify "should handle different formats for tables" do
|
|
2837
2653
|
@ds = @ds.from(:sch__tab)
|
|
2838
2654
|
@ds.multi_insert(@list)
|
|
2839
|
-
@db.sqls.should == [
|
|
2840
|
-
'BEGIN',
|
|
2655
|
+
@db.sqls.should == ['BEGIN',
|
|
2841
2656
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2842
2657
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2843
2658
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2844
|
-
'COMMIT'
|
|
2845
|
-
]
|
|
2846
|
-
@db.sqls.clear
|
|
2659
|
+
'COMMIT']
|
|
2847
2660
|
|
|
2848
2661
|
@ds = @ds.from(:tab.qualify(:sch))
|
|
2849
2662
|
@ds.multi_insert(@list)
|
|
2850
|
-
@db.sqls.should == [
|
|
2851
|
-
'BEGIN',
|
|
2663
|
+
@db.sqls.should == ['BEGIN',
|
|
2852
2664
|
"INSERT INTO sch.tab (name) VALUES ('abc')",
|
|
2853
2665
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
|
2854
2666
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
|
2855
|
-
'COMMIT'
|
|
2856
|
-
|
|
2857
|
-
@db.sqls.clear
|
|
2667
|
+
'COMMIT']
|
|
2668
|
+
|
|
2858
2669
|
@ds = @ds.from(:sch__tab.identifier)
|
|
2859
2670
|
@ds.multi_insert(@list)
|
|
2860
|
-
@db.sqls.should == [
|
|
2861
|
-
'BEGIN',
|
|
2671
|
+
@db.sqls.should == ['BEGIN',
|
|
2862
2672
|
"INSERT INTO sch__tab (name) VALUES ('abc')",
|
|
2863
2673
|
"INSERT INTO sch__tab (name) VALUES ('def')",
|
|
2864
2674
|
"INSERT INTO sch__tab (name) VALUES ('ghi')",
|
|
2865
|
-
'COMMIT'
|
|
2866
|
-
]
|
|
2675
|
+
'COMMIT']
|
|
2867
2676
|
end
|
|
2868
2677
|
|
|
2869
2678
|
specify "should accept the :commit_every option for committing every x records" do
|
|
2870
2679
|
@ds.multi_insert(@list, :commit_every => 1)
|
|
2871
|
-
@db.sqls.should == [
|
|
2872
|
-
'BEGIN',
|
|
2680
|
+
@db.sqls.should == ['BEGIN',
|
|
2873
2681
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2874
2682
|
'COMMIT',
|
|
2875
2683
|
'BEGIN',
|
|
@@ -2877,36 +2685,31 @@ describe "Dataset#multi_insert" do
|
|
|
2877
2685
|
'COMMIT',
|
|
2878
2686
|
'BEGIN',
|
|
2879
2687
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2880
|
-
'COMMIT'
|
|
2881
|
-
]
|
|
2688
|
+
'COMMIT']
|
|
2882
2689
|
end
|
|
2883
2690
|
|
|
2884
2691
|
specify "should accept the :slice option for committing every x records" do
|
|
2885
2692
|
@ds.multi_insert(@list, :slice => 2)
|
|
2886
|
-
@db.sqls.should == [
|
|
2887
|
-
'BEGIN',
|
|
2693
|
+
@db.sqls.should == ['BEGIN',
|
|
2888
2694
|
"INSERT INTO items (name) VALUES ('abc')",
|
|
2889
2695
|
"INSERT INTO items (name) VALUES ('def')",
|
|
2890
2696
|
'COMMIT',
|
|
2891
2697
|
'BEGIN',
|
|
2892
2698
|
"INSERT INTO items (name) VALUES ('ghi')",
|
|
2893
|
-
'COMMIT'
|
|
2894
|
-
]
|
|
2699
|
+
'COMMIT']
|
|
2895
2700
|
end
|
|
2896
2701
|
|
|
2897
2702
|
specify "should accept string keys as column names" do
|
|
2898
2703
|
@ds.multi_insert([{'x'=>1, 'y'=>2}, {'x'=>3, 'y'=>4}])
|
|
2899
|
-
@db.sqls.should == [
|
|
2900
|
-
'BEGIN',
|
|
2704
|
+
@db.sqls.should == ['BEGIN',
|
|
2901
2705
|
"INSERT INTO items (x, y) VALUES (1, 2)",
|
|
2902
2706
|
"INSERT INTO items (x, y) VALUES (3, 4)",
|
|
2903
|
-
'COMMIT'
|
|
2904
|
-
]
|
|
2707
|
+
'COMMIT']
|
|
2905
2708
|
end
|
|
2906
2709
|
|
|
2907
2710
|
specify "should not do anything if no hashes are provided" do
|
|
2908
2711
|
@ds.multi_insert([])
|
|
2909
|
-
@db.sqls.should
|
|
2712
|
+
@db.sqls.should == []
|
|
2910
2713
|
end
|
|
2911
2714
|
end
|
|
2912
2715
|
|
|
@@ -2951,41 +2754,21 @@ describe "Dataset" do
|
|
|
2951
2754
|
end
|
|
2952
2755
|
|
|
2953
2756
|
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"
|
|
2757
|
+
@d.order!(:y).filter!(:y => 1).sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
|
2957
2758
|
end
|
|
2958
2759
|
end
|
|
2959
2760
|
|
|
2960
2761
|
describe "Dataset#to_csv" do
|
|
2961
2762
|
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} ]
|
|
2763
|
+
@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
2764
|
end
|
|
2980
2765
|
|
|
2981
2766
|
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"
|
|
2767
|
+
@ds.to_csv.should == "a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2984
2768
|
end
|
|
2985
2769
|
|
|
2986
2770
|
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"
|
|
2771
|
+
@ds.to_csv(false).should == "1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
|
2989
2772
|
end
|
|
2990
2773
|
end
|
|
2991
2774
|
|
|
@@ -3083,66 +2866,40 @@ describe "Dataset#insert_sql" do
|
|
|
3083
2866
|
end
|
|
3084
2867
|
end
|
|
3085
2868
|
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
true
|
|
2869
|
+
describe "Dataset#inspect" do
|
|
2870
|
+
before do
|
|
2871
|
+
class ::InspectDataset < Sequel::Dataset; end
|
|
3090
2872
|
end
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
class DummyMummyDatabase < Sequel::Database
|
|
3094
|
-
attr_reader :sqls
|
|
3095
|
-
|
|
3096
|
-
def execute(sql)
|
|
3097
|
-
@sqls ||= []
|
|
3098
|
-
@sqls << sql
|
|
2873
|
+
after do
|
|
2874
|
+
Object.send(:remove_const, :InspectDataset) if defined?(::InspectDataset)
|
|
3099
2875
|
end
|
|
3100
|
-
|
|
3101
|
-
def transaction; yield; end
|
|
3102
2876
|
|
|
3103
|
-
|
|
3104
|
-
|
|
2877
|
+
specify "should include the class name and the corresponding SQL statement" do
|
|
2878
|
+
Sequel::Dataset.new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
2879
|
+
InspectDataset.new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3105
2880
|
end
|
|
3106
|
-
end
|
|
3107
2881
|
|
|
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]
|
|
2882
|
+
specify "should skip anonymous classes" do
|
|
2883
|
+
Class.new(Class.new(Sequel::Dataset)).new(nil).from(:blah).inspect.should == '#<Sequel::Dataset: "SELECT * FROM blah">'
|
|
2884
|
+
Class.new(InspectDataset).new(nil).from(:blah).inspect.should == '#<InspectDataset: "SELECT * FROM blah">'
|
|
3115
2885
|
end
|
|
3116
2886
|
end
|
|
3117
2887
|
|
|
3118
2888
|
describe "Dataset#all" do
|
|
3119
2889
|
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)
|
|
2890
|
+
@dataset = Sequel.mock(:fetch=>[{:x => 1, :y => 2}, {:x => 3, :y => 4}])[:items]
|
|
3128
2891
|
end
|
|
3129
2892
|
|
|
3130
2893
|
specify "should return an array with all records" do
|
|
3131
|
-
@dataset.all.should == [
|
|
3132
|
-
|
|
3133
|
-
{:x => 3, :y => 4},
|
|
3134
|
-
"SELECT * FROM items"
|
|
3135
|
-
]
|
|
2894
|
+
@dataset.all.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
2895
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3136
2896
|
end
|
|
3137
2897
|
|
|
3138
2898
|
specify "should iterate over the array if a block is given" do
|
|
3139
2899
|
a = []
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
end
|
|
3144
|
-
|
|
3145
|
-
a.should == [1, 3, "SELECT * FROM items"]
|
|
2900
|
+
@dataset.all{|r| a << r.values_at(:x, :y)}.should == [{:x => 1, :y => 2}, {:x => 3, :y => 4}]
|
|
2901
|
+
a.should == [[1, 2], [3, 4]]
|
|
2902
|
+
@dataset.db.sqls.should == ["SELECT * FROM items"]
|
|
3146
2903
|
end
|
|
3147
2904
|
end
|
|
3148
2905
|
|
|
@@ -3152,71 +2909,56 @@ describe "Dataset#grep" do
|
|
|
3152
2909
|
end
|
|
3153
2910
|
|
|
3154
2911
|
specify "should format a SQL filter correctly" do
|
|
3155
|
-
@ds.grep(:title, 'ruby').sql.should ==
|
|
3156
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
2912
|
+
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
|
3157
2913
|
end
|
|
3158
2914
|
|
|
3159
2915
|
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'))"
|
|
2916
|
+
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
|
3162
2917
|
end
|
|
3163
2918
|
|
|
3164
2919
|
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'))"
|
|
2920
|
+
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
|
3167
2921
|
end
|
|
3168
2922
|
|
|
3169
2923
|
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'))"
|
|
2924
|
+
@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
2925
|
end
|
|
3173
2926
|
|
|
3174
2927
|
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')))"
|
|
2928
|
+
@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
2929
|
end
|
|
3178
2930
|
|
|
3179
2931
|
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')))"
|
|
2932
|
+
@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
2933
|
end
|
|
3183
2934
|
|
|
3184
2935
|
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'))"
|
|
2936
|
+
@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
2937
|
end
|
|
3188
2938
|
|
|
3189
2939
|
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'))"
|
|
2940
|
+
@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
2941
|
end
|
|
3193
2942
|
|
|
3194
2943
|
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')))"
|
|
2944
|
+
@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
2945
|
end
|
|
3198
2946
|
|
|
3199
2947
|
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')))"
|
|
2948
|
+
@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
2949
|
end
|
|
3203
2950
|
|
|
3204
2951
|
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'))"
|
|
2952
|
+
@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
2953
|
end
|
|
3208
2954
|
|
|
3209
2955
|
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'))"
|
|
2956
|
+
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
|
2957
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
|
3215
2958
|
end
|
|
3216
2959
|
|
|
3217
2960
|
specify "should support searching against other columns" do
|
|
3218
|
-
@ds.grep(:title, :body).sql.should ==
|
|
3219
|
-
"SELECT * FROM posts WHERE ((title LIKE body))"
|
|
2961
|
+
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
|
|
3220
2962
|
end
|
|
3221
2963
|
end
|
|
3222
2964
|
|
|
@@ -3270,19 +3012,9 @@ end
|
|
|
3270
3012
|
|
|
3271
3013
|
describe "Dataset prepared statements and bound variables " do
|
|
3272
3014
|
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
|
|
3015
|
+
@db = Sequel.mock
|
|
3285
3016
|
@ds = @db[:items]
|
|
3017
|
+
@ds.meta_def(:insert_sql){|*v| "#{super(*v)}#{' RETURNING *' if opts.has_key?(:returning)}" }
|
|
3286
3018
|
end
|
|
3287
3019
|
|
|
3288
3020
|
specify "#call should take a type and bind hash and interpolate it" do
|
|
@@ -3291,11 +3023,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3291
3023
|
@ds.filter(:num=>:$n).call(:delete, :n=>1)
|
|
3292
3024
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
|
3293
3025
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
|
3026
|
+
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
|
3294
3027
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3295
3028
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3296
3029
|
'DELETE FROM items WHERE (num = 1)',
|
|
3297
3030
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3298
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3031
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3032
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3299
3033
|
end
|
|
3300
3034
|
|
|
3301
3035
|
specify "#prepare should take a type and name and store it in the database for later use with call" do
|
|
@@ -3305,23 +3039,26 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3305
3039
|
pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
|
|
3306
3040
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
|
3307
3041
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
|
3308
|
-
@
|
|
3309
|
-
[:
|
|
3042
|
+
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
|
3043
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sn, :un]
|
|
3044
|
+
[:sn, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3310
3045
|
@db.call(:sn, :n=>1)
|
|
3311
3046
|
@db.call(:fn, :n=>1)
|
|
3312
3047
|
@db.call(:dn, :n=>1)
|
|
3313
3048
|
@db.call(:un, :n=>1, :n2=>2)
|
|
3314
3049
|
@db.call(:in, :n=>1)
|
|
3050
|
+
@db.call(:ins, :n=>1)
|
|
3315
3051
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3316
3052
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
3317
3053
|
'DELETE FROM items WHERE (num = 1)',
|
|
3318
3054
|
'UPDATE items SET num = 2 WHERE (num = 1)',
|
|
3319
|
-
'INSERT INTO items (num) VALUES (1)'
|
|
3055
|
+
'INSERT INTO items (num) VALUES (1)',
|
|
3056
|
+
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
|
3320
3057
|
end
|
|
3321
3058
|
|
|
3322
3059
|
specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
|
|
3323
3060
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
|
3324
|
-
'<Sequel::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3061
|
+
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
|
3325
3062
|
end
|
|
3326
3063
|
|
|
3327
3064
|
specify "should handle literal strings" do
|
|
@@ -3357,23 +3094,16 @@ end
|
|
|
3357
3094
|
|
|
3358
3095
|
describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3359
3096
|
before do
|
|
3360
|
-
@db = Sequel
|
|
3361
|
-
@db.meta_def(:sqls){@sqls||=[]}
|
|
3362
|
-
def @db.execute(sql, opts={})
|
|
3363
|
-
sqls << [sql, *opts[:arguments]]
|
|
3364
|
-
end
|
|
3097
|
+
@db = Sequel.mock
|
|
3365
3098
|
@ds = @db[:items].filter(:num=>:$n)
|
|
3366
|
-
def @ds.fetch_rows(sql, &block)
|
|
3367
|
-
execute(sql)
|
|
3368
|
-
end
|
|
3369
3099
|
def @ds.execute(sql, opts={}, &block)
|
|
3370
|
-
|
|
3100
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3371
3101
|
end
|
|
3372
|
-
def @ds.execute_dui(
|
|
3373
|
-
|
|
3102
|
+
def @ds.execute_dui(sql, opts={}, &block)
|
|
3103
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3374
3104
|
end
|
|
3375
|
-
def @ds.execute_insert(
|
|
3376
|
-
|
|
3105
|
+
def @ds.execute_insert(sql, opts={}, &block)
|
|
3106
|
+
super(sql, opts.merge({:arguments=>bind_arguments}), &block)
|
|
3377
3107
|
end
|
|
3378
3108
|
@ps = []
|
|
3379
3109
|
@ps << @ds.prepare(:select, :s)
|
|
@@ -3386,64 +3116,43 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
|
3386
3116
|
end
|
|
3387
3117
|
|
|
3388
3118
|
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 = ?)">'
|
|
3119
|
+
@ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
|
3390
3120
|
end
|
|
3391
3121
|
|
|
3392
3122
|
specify "should submitted the SQL to the database with placeholders and bind variables" do
|
|
3393
3123
|
@ps.each{|p| p.prepared_sql; p.call(:n=>1)}
|
|
3394
|
-
@db.sqls.should == [
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
]
|
|
3124
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3125
|
+
"SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
|
3126
|
+
"SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
|
|
3127
|
+
"DELETE FROM items WHERE (num = ?) -- args: [1]",
|
|
3128
|
+
"INSERT INTO items (num) VALUES (?) -- args: [1]",
|
|
3129
|
+
"UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
|
|
3401
3130
|
end
|
|
3402
3131
|
end
|
|
3403
3132
|
|
|
3404
3133
|
describe "Sequel::Dataset#server" do
|
|
3405
3134
|
specify "should set the server to use for the dataset" do
|
|
3406
|
-
@db = Sequel
|
|
3135
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}, :d=>{}, :u=>{}})
|
|
3407
3136
|
@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
3137
|
@ds.all
|
|
3416
3138
|
@ds.server(:i).insert(:a=>1)
|
|
3417
3139
|
@ds.server(:d).delete
|
|
3418
3140
|
@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]]
|
|
3141
|
+
@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
3142
|
end
|
|
3424
3143
|
end
|
|
3425
3144
|
|
|
3426
3145
|
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
3146
|
specify "should yield a dataset for each server" do
|
|
3147
|
+
@db = Sequel.mock(:servers=>{:s=>{}, :i=>{}})
|
|
3148
|
+
@ds = @db[:items]
|
|
3440
3149
|
@ds.each_server do |ds|
|
|
3441
3150
|
ds.should be_a_kind_of(Sequel::Dataset)
|
|
3442
3151
|
ds.should_not == @ds
|
|
3443
3152
|
ds.sql.should == @ds.sql
|
|
3444
3153
|
ds.all
|
|
3445
3154
|
end
|
|
3446
|
-
@sqls.
|
|
3155
|
+
@db.sqls.sort.should == ['SELECT * FROM items', 'SELECT * FROM items -- i', 'SELECT * FROM items -- s']
|
|
3447
3156
|
end
|
|
3448
3157
|
end
|
|
3449
3158
|
|
|
@@ -3493,23 +3202,23 @@ end
|
|
|
3493
3202
|
|
|
3494
3203
|
describe "Sequel::Dataset#qualify" do
|
|
3495
3204
|
specify "should qualify to the given table" do
|
|
3496
|
-
|
|
3205
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3497
3206
|
end
|
|
3498
3207
|
|
|
3499
3208
|
specify "should qualify to the first source if no table if given" do
|
|
3500
|
-
|
|
3209
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify.sql.should == 'SELECT t.* FROM t WHERE (t.a < t.b)'
|
|
3501
3210
|
end
|
|
3502
3211
|
end
|
|
3503
3212
|
|
|
3504
3213
|
describe "Sequel::Dataset#qualify_to" do
|
|
3505
3214
|
specify "should qualify to the given table" do
|
|
3506
|
-
|
|
3215
|
+
Sequel::Dataset.new(nil).from(:t).filter{a<b}.qualify_to(:e).sql.should == 'SELECT e.* FROM t WHERE (e.a < e.b)'
|
|
3507
3216
|
end
|
|
3508
3217
|
end
|
|
3509
3218
|
|
|
3510
3219
|
describe "Sequel::Dataset#qualify_to_first_source" do
|
|
3511
3220
|
before do
|
|
3512
|
-
@ds =
|
|
3221
|
+
@ds = Sequel::Database.new[:t]
|
|
3513
3222
|
end
|
|
3514
3223
|
|
|
3515
3224
|
specify "should qualify_to the first source" do
|
|
@@ -3519,13 +3228,11 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3519
3228
|
end
|
|
3520
3229
|
|
|
3521
3230
|
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'
|
|
3231
|
+
@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
3232
|
end
|
|
3525
3233
|
|
|
3526
3234
|
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'
|
|
3235
|
+
@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
3236
|
end
|
|
3530
3237
|
|
|
3531
3238
|
specify "should handle hashes in select option" do
|
|
@@ -3594,14 +3301,83 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3594
3301
|
end
|
|
3595
3302
|
|
|
3596
3303
|
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
|
-
|
|
3304
|
+
@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"
|
|
3305
|
+
end
|
|
3306
|
+
end
|
|
3307
|
+
|
|
3308
|
+
describe "Sequel::Dataset#unbind" do
|
|
3309
|
+
before do
|
|
3310
|
+
@ds = Sequel::Database.new[:t]
|
|
3311
|
+
@u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
|
|
3312
|
+
end
|
|
3313
|
+
|
|
3314
|
+
specify "should unbind values assigned to equality and inequality statements" do
|
|
3315
|
+
@ds.filter(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo = $foo)"
|
|
3316
|
+
@ds.exclude(:foo=>1).unbind.first.sql.should == "SELECT * FROM t WHERE (foo != $foo)"
|
|
3317
|
+
@ds.filter{foo > 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo > $foo)"
|
|
3318
|
+
@ds.filter{foo >= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo >= $foo)"
|
|
3319
|
+
@ds.filter{foo < 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo < $foo)"
|
|
3320
|
+
@ds.filter{foo <= 1}.unbind.first.sql.should == "SELECT * FROM t WHERE (foo <= $foo)"
|
|
3321
|
+
end
|
|
3322
|
+
|
|
3323
|
+
specify "should return variables that could be used bound to recreate the previous query" do
|
|
3324
|
+
@ds.filter(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3325
|
+
@ds.exclude(:foo=>1).unbind.last.should == {:foo=>1}
|
|
3326
|
+
end
|
|
3327
|
+
|
|
3328
|
+
specify "should handle numerics, strings, dates, times, and datetimes" do
|
|
3329
|
+
@u[@ds.filter(:foo=>1)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1}]
|
|
3330
|
+
@u[@ds.filter(:foo=>1.0)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>1.0}]
|
|
3331
|
+
@u[@ds.filter(:foo=>BigDecimal.new('1.0'))].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>BigDecimal.new('1.0')}]
|
|
3332
|
+
@u[@ds.filter(:foo=>'a')].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>'a'}]
|
|
3333
|
+
@u[@ds.filter(:foo=>Date.today)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>Date.today}]
|
|
3334
|
+
t = Time.now
|
|
3335
|
+
@u[@ds.filter(:foo=>t)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>t}]
|
|
3336
|
+
dt = DateTime.now
|
|
3337
|
+
@u[@ds.filter(:foo=>dt)].should == ["SELECT * FROM t WHERE (foo = $foo)", {:foo=>dt}]
|
|
3338
|
+
end
|
|
3339
|
+
|
|
3340
|
+
specify "should not unbind literal strings" do
|
|
3341
|
+
@u[@ds.filter(:foo=>'a'.lit)].should == ["SELECT * FROM t WHERE (foo = a)", {}]
|
|
3342
|
+
end
|
|
3343
|
+
|
|
3344
|
+
specify "should not unbind Identifiers, QualifiedIdentifiers, or Symbols used as booleans" do
|
|
3345
|
+
@u[@ds.filter(:foo).filter{bar}.filter{foo__bar}].should == ["SELECT * FROM t WHERE (foo AND bar AND foo.bar)", {}]
|
|
3346
|
+
end
|
|
3347
|
+
|
|
3348
|
+
specify "should not unbind for values it doesn't understand" do
|
|
3349
|
+
@u[@ds.filter(:foo=>Class.new{def sql_literal(ds) 'bar' end}.new)].should == ["SELECT * FROM t WHERE (foo = bar)", {}]
|
|
3350
|
+
end
|
|
3351
|
+
|
|
3352
|
+
specify "should handle QualifiedIdentifiers" do
|
|
3353
|
+
@u[@ds.filter{foo__bar > 1}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3354
|
+
end
|
|
3355
|
+
|
|
3356
|
+
specify "should handle deep nesting" do
|
|
3357
|
+
@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}]
|
|
3358
|
+
end
|
|
3359
|
+
|
|
3360
|
+
specify "should handle JOIN ON" do
|
|
3361
|
+
@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}]
|
|
3362
|
+
end
|
|
3363
|
+
|
|
3364
|
+
specify "should raise an UnbindDuplicate exception if same variable is used with multiple different values" do
|
|
3365
|
+
proc{@ds.filter(:foo=>1).or(:foo=>2).unbind}.should raise_error(Sequel::UnbindDuplicate)
|
|
3366
|
+
end
|
|
3367
|
+
|
|
3368
|
+
specify "should handle case where the same variable has the same value in multiple places " do
|
|
3369
|
+
@u[@ds.filter(:foo=>1).or(:foo=>1)].should == ["SELECT * FROM t WHERE ((foo = $foo) OR (foo = $foo))", {:foo=>1}]
|
|
3370
|
+
end
|
|
3371
|
+
|
|
3372
|
+
specify "should raise Error for unhandled objects inside Identifiers and QualifiedIndentifiers" do
|
|
3373
|
+
proc{@ds.filter(Sequel::SQL::Identifier.new([]) > 1).unbind}.should raise_error(Sequel::Error)
|
|
3374
|
+
proc{@ds.filter{foo.qualify({}) > 1}.unbind}.should raise_error(Sequel::Error)
|
|
3599
3375
|
end
|
|
3600
3376
|
end
|
|
3601
3377
|
|
|
3602
3378
|
describe "Sequel::Dataset #with and #with_recursive" do
|
|
3603
3379
|
before do
|
|
3604
|
-
@db =
|
|
3380
|
+
@db = Sequel::Database.new
|
|
3605
3381
|
@ds = @db[:t]
|
|
3606
3382
|
end
|
|
3607
3383
|
|
|
@@ -3633,11 +3409,27 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
|
3633
3409
|
proc{@ds.with(:t, @db[:x], :args=>[:b])}.should raise_error(Sequel::Error)
|
|
3634
3410
|
proc{@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c])}.should raise_error(Sequel::Error)
|
|
3635
3411
|
end
|
|
3412
|
+
|
|
3413
|
+
specify "#with should work on insert, update, and delete statements if they support it" do
|
|
3414
|
+
[:insert, :update, :delete].each do |m|
|
|
3415
|
+
@ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_with_sql"]}
|
|
3416
|
+
end
|
|
3417
|
+
@ds.with(:t, @db[:x]).insert_sql(1).should == 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
|
|
3418
|
+
@ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
|
|
3419
|
+
@ds.with(:t, @db[:x]).delete_sql.should == 'WITH t AS (SELECT * FROM x) DELETE FROM t'
|
|
3420
|
+
end
|
|
3421
|
+
|
|
3422
|
+
specify "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
|
|
3423
|
+
@ds.meta_def(:supports_cte?){true}
|
|
3424
|
+
@ds.meta_def(:supports_cte_in_subselect?){false}
|
|
3425
|
+
@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'
|
|
3426
|
+
@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'
|
|
3427
|
+
end
|
|
3636
3428
|
end
|
|
3637
3429
|
|
|
3638
3430
|
describe Sequel::SQL::Constants do
|
|
3639
3431
|
before do
|
|
3640
|
-
@db =
|
|
3432
|
+
@db = Sequel::Database.new
|
|
3641
3433
|
end
|
|
3642
3434
|
|
|
3643
3435
|
it "should have CURRENT_DATE" do
|
|
@@ -3682,7 +3474,7 @@ end
|
|
|
3682
3474
|
|
|
3683
3475
|
describe "Sequel timezone support" do
|
|
3684
3476
|
before do
|
|
3685
|
-
@db =
|
|
3477
|
+
@db = Sequel::Database.new
|
|
3686
3478
|
@dataset = @db.dataset
|
|
3687
3479
|
@dataset.meta_def(:supports_timestamp_timezones?){true}
|
|
3688
3480
|
@dataset.meta_def(:supports_timestamp_usecs?){false}
|
|
@@ -3717,6 +3509,30 @@ describe "Sequel timezone support" do
|
|
|
3717
3509
|
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3718
3510
|
end
|
|
3719
3511
|
|
|
3512
|
+
specify "should have Database#timezone override Sequel.database_timezone" do
|
|
3513
|
+
Sequel.database_timezone = :local
|
|
3514
|
+
@db.timezone = :utc
|
|
3515
|
+
|
|
3516
|
+
t = Time.now
|
|
3517
|
+
s = t.getutc.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3518
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3519
|
+
|
|
3520
|
+
t = DateTime.now
|
|
3521
|
+
s = t.new_offset(0).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3522
|
+
@dataset.literal(t).should == "#{s}+0000'"
|
|
3523
|
+
|
|
3524
|
+
Sequel.database_timezone = :utc
|
|
3525
|
+
@db.timezone = :local
|
|
3526
|
+
|
|
3527
|
+
t = Time.now.utc
|
|
3528
|
+
s = t.getlocal.strftime("'%Y-%m-%d %H:%M:%S")
|
|
3529
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3530
|
+
|
|
3531
|
+
t = DateTime.now.new_offset(0)
|
|
3532
|
+
s = t.new_offset(DateTime.now.offset).strftime("'%Y-%m-%d %H:%M:%S")
|
|
3533
|
+
@dataset.literal(t).should == "#{s}#{@offset}'"
|
|
3534
|
+
end
|
|
3535
|
+
|
|
3720
3536
|
specify "should handle converting database timestamps into application timestamps" do
|
|
3721
3537
|
Sequel.database_timezone = :utc
|
|
3722
3538
|
Sequel.application_timezone = :local
|
|
@@ -3827,13 +3643,7 @@ end
|
|
|
3827
3643
|
|
|
3828
3644
|
describe "Sequel::Dataset#select_map" do
|
|
3829
3645
|
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
|
|
3646
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3837
3647
|
end
|
|
3838
3648
|
|
|
3839
3649
|
specify "should do select and map in one step" do
|
|
@@ -3860,17 +3670,23 @@ describe "Sequel::Dataset#select_map" do
|
|
|
3860
3670
|
@ds.select_map{a(t__c)}.should == [1, 2]
|
|
3861
3671
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t']
|
|
3862
3672
|
end
|
|
3673
|
+
|
|
3674
|
+
specify "should handle an array of columns" do
|
|
3675
|
+
@ds.select_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3676
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t']
|
|
3677
|
+
@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]]
|
|
3678
|
+
@ds.db.sqls.should == ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
|
|
3679
|
+
end
|
|
3680
|
+
|
|
3681
|
+
specify "should handle an array with a single element" do
|
|
3682
|
+
@ds.select_map([:c]).should == [[1], [2]]
|
|
3683
|
+
@ds.db.sqls.should == ['SELECT c FROM t']
|
|
3684
|
+
end
|
|
3863
3685
|
end
|
|
3864
3686
|
|
|
3865
3687
|
describe "Sequel::Dataset#select_order_map" do
|
|
3866
3688
|
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
|
|
3689
|
+
@ds = Sequel.mock(:fetch=>[{:c=>1}, {:c=>2}])[:t]
|
|
3874
3690
|
end
|
|
3875
3691
|
|
|
3876
3692
|
specify "should do select and map in one step" do
|
|
@@ -3898,55 +3714,89 @@ describe "Sequel::Dataset#select_order_map" do
|
|
|
3898
3714
|
@ds.db.sqls.should == ['SELECT a AS b FROM t ORDER BY a']
|
|
3899
3715
|
end
|
|
3900
3716
|
|
|
3717
|
+
specify "should handle OrderedExpressions" do
|
|
3718
|
+
@ds.select_order_map(:a.desc).should == [1, 2]
|
|
3719
|
+
@ds.db.sqls.should == ['SELECT a FROM t ORDER BY a DESC']
|
|
3720
|
+
end
|
|
3721
|
+
|
|
3901
3722
|
specify "should accept a block" do
|
|
3902
3723
|
@ds.select_order_map{a(t__c)}.should == [1, 2]
|
|
3903
3724
|
@ds.db.sqls.should == ['SELECT a(t.c) FROM t ORDER BY a(t.c)']
|
|
3904
3725
|
end
|
|
3726
|
+
|
|
3727
|
+
specify "should handle an array of columns" do
|
|
3728
|
+
@ds.select_order_map([:c, :c]).should == [[1, 1], [2, 2]]
|
|
3729
|
+
@ds.db.sqls.should == ['SELECT c, c FROM t ORDER BY c, c']
|
|
3730
|
+
@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]]
|
|
3731
|
+
@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']
|
|
3732
|
+
end
|
|
3733
|
+
|
|
3734
|
+
specify "should handle an array with a single element" do
|
|
3735
|
+
@ds.select_order_map([:c]).should == [[1], [2]]
|
|
3736
|
+
@ds.db.sqls.should == ['SELECT c FROM t ORDER BY c']
|
|
3737
|
+
end
|
|
3905
3738
|
end
|
|
3906
3739
|
|
|
3907
3740
|
describe "Sequel::Dataset#select_hash" do
|
|
3908
3741
|
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
|
|
3742
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3743
|
+
@ds = @db[:t]
|
|
3918
3744
|
end
|
|
3919
3745
|
|
|
3920
|
-
specify "should do select and
|
|
3921
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3746
|
+
specify "should do select and to_hash in one step" do
|
|
3922
3747
|
@ds.select_hash(:a, :b).should == {1=>2, 3=>4}
|
|
3923
3748
|
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3924
3749
|
end
|
|
3925
3750
|
|
|
3926
3751
|
specify "should handle implicit qualifiers in arguments" do
|
|
3927
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3928
3752
|
@ds.select_hash(:t__a, :t__b).should == {1=>2, 3=>4}
|
|
3929
3753
|
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3930
3754
|
end
|
|
3931
3755
|
|
|
3932
3756
|
specify "should handle implicit aliases in arguments" do
|
|
3933
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3934
3757
|
@ds.select_hash(:c___a, :d___b).should == {1=>2, 3=>4}
|
|
3935
3758
|
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
3936
3759
|
end
|
|
3937
3760
|
|
|
3938
3761
|
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
3939
|
-
@ds.set_fr_yield([{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
3940
3762
|
@ds.select_hash(:t__c___a, :t__d___b).should == {1=>2, 3=>4}
|
|
3941
3763
|
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
3942
3764
|
end
|
|
3765
|
+
|
|
3766
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
3767
|
+
@ds.select_hash(:a.identifier, :b.identifier).should == {1=>2, 3=>4}
|
|
3768
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
3769
|
+
end
|
|
3770
|
+
|
|
3771
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
3772
|
+
@ds.select_hash(:a.qualify(:t), :b.identifier.qualify(:t)).should == {1=>2, 3=>4}
|
|
3773
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
3774
|
+
end
|
|
3775
|
+
|
|
3776
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
3777
|
+
@ds.select_hash(:c.as(:a), :t.as(:b)).should == {1=>2, 3=>4}
|
|
3778
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
3779
|
+
end
|
|
3780
|
+
|
|
3781
|
+
specify "should work with arrays of columns" do
|
|
3782
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
3783
|
+
@ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [4, 6]=>5}
|
|
3784
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
3785
|
+
@ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 4=>[5, 6]}
|
|
3786
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
3787
|
+
@ds.select_hash([:a, :b], [:b, :c]).should == {[1, 2]=>[2, 3], [4, 5]=>[5, 6]}
|
|
3788
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
3789
|
+
end
|
|
3790
|
+
|
|
3791
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
3792
|
+
proc{@ds.select_hash(:c.as(:a), 'foo')}.should raise_error(Sequel::Error)
|
|
3793
|
+
end
|
|
3943
3794
|
end
|
|
3944
3795
|
|
|
3945
3796
|
describe "Modifying joined datasets" do
|
|
3946
3797
|
before do
|
|
3947
|
-
@ds =
|
|
3798
|
+
@ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
|
|
3948
3799
|
@ds.meta_def(:supports_modifying_joins?){true}
|
|
3949
|
-
@ds.db.reset
|
|
3950
3800
|
end
|
|
3951
3801
|
|
|
3952
3802
|
specify "should allow deleting from joined datasets" do
|
|
@@ -3962,7 +3812,7 @@ end
|
|
|
3962
3812
|
|
|
3963
3813
|
describe "Dataset#lock_style and for_update" do
|
|
3964
3814
|
before do
|
|
3965
|
-
@ds =
|
|
3815
|
+
@ds = Sequel::Dataset.new(nil).from(:t)
|
|
3966
3816
|
end
|
|
3967
3817
|
|
|
3968
3818
|
specify "#for_update should use FOR UPDATE" do
|
|
@@ -3977,3 +3827,89 @@ describe "Dataset#lock_style and for_update" do
|
|
|
3977
3827
|
@ds.lock_style("FOR SHARE").sql.should == "SELECT * FROM t FOR SHARE"
|
|
3978
3828
|
end
|
|
3979
3829
|
end
|
|
3830
|
+
|
|
3831
|
+
describe "Custom ASTTransformer" do
|
|
3832
|
+
specify "should transform given objects" do
|
|
3833
|
+
c = Class.new(Sequel::ASTTransformer) do
|
|
3834
|
+
def v(s)
|
|
3835
|
+
(s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
|
|
3836
|
+
end
|
|
3837
|
+
end.new
|
|
3838
|
+
ds = Sequel::Dataset.new(nil).from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
|
3839
|
+
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)'
|
|
3840
|
+
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)'
|
|
3841
|
+
end
|
|
3842
|
+
end
|
|
3843
|
+
|
|
3844
|
+
describe "Dataset#returning" do
|
|
3845
|
+
before do
|
|
3846
|
+
@ds = Sequel.mock(:fetch=>proc{|s| {:foo=>s}})[:t].returning(:foo)
|
|
3847
|
+
@pr = proc do
|
|
3848
|
+
[:insert, :update, :delete].each do |m|
|
|
3849
|
+
@ds.meta_def(:"#{m}_clause_methods"){super() + [:"#{m}_returning_sql"]}
|
|
3850
|
+
end
|
|
3851
|
+
end
|
|
3852
|
+
end
|
|
3853
|
+
|
|
3854
|
+
specify "should use RETURNING clause in the SQL if the dataset supports it" do
|
|
3855
|
+
@pr.call
|
|
3856
|
+
@ds.delete_sql.should == "DELETE FROM t RETURNING foo"
|
|
3857
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1) RETURNING foo"
|
|
3858
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1 RETURNING foo"
|
|
3859
|
+
end
|
|
3860
|
+
|
|
3861
|
+
specify "should not use RETURNING clause in the SQL if the dataset does not support it" do
|
|
3862
|
+
@ds.delete_sql.should == "DELETE FROM t"
|
|
3863
|
+
@ds.insert_sql(1).should == "INSERT INTO t VALUES (1)"
|
|
3864
|
+
@ds.update_sql(:foo=>1).should == "UPDATE t SET foo = 1"
|
|
3865
|
+
end
|
|
3866
|
+
|
|
3867
|
+
specify "should have insert, update, and delete yield to blocks if RETURNING is used" do
|
|
3868
|
+
@pr.call
|
|
3869
|
+
h = {}
|
|
3870
|
+
@ds.delete{|r| h = r}
|
|
3871
|
+
h.should == {:foo=>"DELETE FROM t RETURNING foo"}
|
|
3872
|
+
@ds.insert(1){|r| h = r}
|
|
3873
|
+
h.should == {:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}
|
|
3874
|
+
@ds.update(:foo=>1){|r| h = r}
|
|
3875
|
+
h.should == {:foo=>"UPDATE t SET foo = 1 RETURNING foo"}
|
|
3876
|
+
end
|
|
3877
|
+
|
|
3878
|
+
specify "should have insert, update, and delete return arrays of hashes if RETURNING is used and a block is not given" do
|
|
3879
|
+
@pr.call
|
|
3880
|
+
h = {}
|
|
3881
|
+
@ds.delete.should == [{:foo=>"DELETE FROM t RETURNING foo"}]
|
|
3882
|
+
@ds.insert(1).should == [{:foo=>"INSERT INTO t VALUES (1) RETURNING foo"}]
|
|
3883
|
+
@ds.update(:foo=>1).should == [{:foo=>"UPDATE t SET foo = 1 RETURNING foo"}]
|
|
3884
|
+
end
|
|
3885
|
+
end
|
|
3886
|
+
|
|
3887
|
+
describe "Dataset emulating bitwise operator support" do
|
|
3888
|
+
before do
|
|
3889
|
+
@ds = Sequel::Database.new.dataset
|
|
3890
|
+
@ds.quote_identifiers = true
|
|
3891
|
+
def @ds.complex_expression_sql(op, args)
|
|
3892
|
+
complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
|
3893
|
+
end
|
|
3894
|
+
end
|
|
3895
|
+
|
|
3896
|
+
it "should work with any numbers of arguments for operators" do
|
|
3897
|
+
@ds.select(Sequel::SQL::ComplexExpression.new(:&, :x)).sql.should == 'SELECT "x"'
|
|
3898
|
+
@ds.select(:x & 1).sql.should == 'SELECT bitand("x", 1)'
|
|
3899
|
+
@ds.select(:x & 1 & 2).sql.should == 'SELECT bitand(bitand("x", 1), 2)'
|
|
3900
|
+
end
|
|
3901
|
+
end
|
|
3902
|
+
|
|
3903
|
+
describe "Dataset feature defaults" do
|
|
3904
|
+
it "should not require aliases for recursive CTEs by default" do
|
|
3905
|
+
Sequel::Database.new.dataset.recursive_cte_requires_column_aliases?.should be_false
|
|
3906
|
+
end
|
|
3907
|
+
|
|
3908
|
+
it "should not require placeholder type specifiers by default" do
|
|
3909
|
+
Sequel::Database.new.dataset.requires_placeholder_type_specifiers?.should be_false
|
|
3910
|
+
end
|
|
3911
|
+
|
|
3912
|
+
it "offset use should be returning a separate row number column by default" do
|
|
3913
|
+
Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
|
|
3914
|
+
end
|
|
3915
|
+
end
|