sequel_core 2.2.0 → 3.8.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.
- metadata +30 -101
- data/CHANGELOG +0 -1519
- data/COPYING +0 -19
- data/README +0 -313
- data/Rakefile +0 -158
- data/bin/sequel +0 -117
- data/doc/cheat_sheet.rdoc +0 -225
- data/doc/dataset_filtering.rdoc +0 -182
- data/lib/sequel_core.rb +0 -136
- data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
- data/lib/sequel_core/adapters/ado.rb +0 -90
- data/lib/sequel_core/adapters/db2.rb +0 -160
- data/lib/sequel_core/adapters/dbi.rb +0 -127
- data/lib/sequel_core/adapters/informix.rb +0 -89
- data/lib/sequel_core/adapters/jdbc.rb +0 -110
- data/lib/sequel_core/adapters/mysql.rb +0 -486
- data/lib/sequel_core/adapters/odbc.rb +0 -167
- data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
- data/lib/sequel_core/adapters/openbase.rb +0 -76
- data/lib/sequel_core/adapters/oracle.rb +0 -182
- data/lib/sequel_core/adapters/postgres.rb +0 -560
- data/lib/sequel_core/adapters/sqlite.rb +0 -270
- data/lib/sequel_core/connection_pool.rb +0 -194
- data/lib/sequel_core/core_ext.rb +0 -197
- data/lib/sequel_core/core_sql.rb +0 -184
- data/lib/sequel_core/database.rb +0 -462
- data/lib/sequel_core/database/schema.rb +0 -156
- data/lib/sequel_core/dataset.rb +0 -457
- data/lib/sequel_core/dataset/callback.rb +0 -13
- data/lib/sequel_core/dataset/convenience.rb +0 -245
- data/lib/sequel_core/dataset/pagination.rb +0 -96
- data/lib/sequel_core/dataset/query.rb +0 -41
- data/lib/sequel_core/dataset/schema.rb +0 -15
- data/lib/sequel_core/dataset/sql.rb +0 -889
- data/lib/sequel_core/deprecated.rb +0 -26
- data/lib/sequel_core/exceptions.rb +0 -42
- data/lib/sequel_core/migration.rb +0 -187
- data/lib/sequel_core/object_graph.rb +0 -216
- data/lib/sequel_core/pretty_table.rb +0 -71
- data/lib/sequel_core/schema.rb +0 -2
- data/lib/sequel_core/schema/generator.rb +0 -239
- data/lib/sequel_core/schema/sql.rb +0 -326
- data/lib/sequel_core/sql.rb +0 -812
- data/lib/sequel_core/worker.rb +0 -68
- data/spec/adapters/informix_spec.rb +0 -96
- data/spec/adapters/mysql_spec.rb +0 -765
- data/spec/adapters/oracle_spec.rb +0 -222
- data/spec/adapters/postgres_spec.rb +0 -441
- data/spec/adapters/sqlite_spec.rb +0 -413
- data/spec/connection_pool_spec.rb +0 -363
- data/spec/core_ext_spec.rb +0 -156
- data/spec/core_sql_spec.rb +0 -427
- data/spec/database_spec.rb +0 -963
- data/spec/dataset_spec.rb +0 -2933
- data/spec/expression_filters_spec.rb +0 -316
- data/spec/migration_spec.rb +0 -261
- data/spec/object_graph_spec.rb +0 -230
- data/spec/pretty_table_spec.rb +0 -58
- data/spec/rcov.opts +0 -6
- data/spec/schema_generator_spec.rb +0 -122
- data/spec/schema_spec.rb +0 -422
- data/spec/spec.opts +0 -0
- data/spec/spec_config.rb +0 -7
- data/spec/spec_config.rb.example +0 -8
- data/spec/spec_helper.rb +0 -55
- data/spec/worker_spec.rb +0 -96
data/spec/dataset_spec.rb
DELETED
@@ -1,2933 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
-
|
3
|
-
context "Dataset" do
|
4
|
-
setup do
|
5
|
-
@dataset = Sequel::Dataset.new("db")
|
6
|
-
end
|
7
|
-
|
8
|
-
specify "should accept database and opts in initialize" do
|
9
|
-
db = "db"
|
10
|
-
opts = {:from => :test}
|
11
|
-
d = Sequel::Dataset.new(db, opts)
|
12
|
-
d.db.should be(db)
|
13
|
-
d.opts.should be(opts)
|
14
|
-
|
15
|
-
d = Sequel::Dataset.new(db)
|
16
|
-
d.db.should be(db)
|
17
|
-
d.opts.should be_a_kind_of(Hash)
|
18
|
-
d.opts.should == {}
|
19
|
-
end
|
20
|
-
|
21
|
-
specify "should provide clone for chainability" do
|
22
|
-
d1 = @dataset.clone(:from => [:test])
|
23
|
-
d1.class.should == @dataset.class
|
24
|
-
d1.should_not == @dataset
|
25
|
-
d1.db.should be(@dataset.db)
|
26
|
-
d1.opts[:from].should == [:test]
|
27
|
-
@dataset.opts[:from].should be_nil
|
28
|
-
|
29
|
-
d2 = d1.clone(:order => [:name])
|
30
|
-
d2.class.should == @dataset.class
|
31
|
-
d2.should_not == d1
|
32
|
-
d2.should_not == @dataset
|
33
|
-
d2.db.should be(@dataset.db)
|
34
|
-
d2.opts[:from].should == [:test]
|
35
|
-
d2.opts[:order].should == [:name]
|
36
|
-
d1.opts[:order].should be_nil
|
37
|
-
end
|
38
|
-
|
39
|
-
specify "should include Enumerable" do
|
40
|
-
Sequel::Dataset.included_modules.should include(Enumerable)
|
41
|
-
end
|
42
|
-
|
43
|
-
specify "should raise ImplementedError for the dataset interface methods" do
|
44
|
-
proc {@dataset.fetch_rows('abc')}.should raise_error(NotImplementedError)
|
45
|
-
proc {@dataset.insert(1, 2, 3)}.should raise_error(NotImplementedError)
|
46
|
-
proc {@dataset.update(:name => 'abc')}.should raise_error(NotImplementedError)
|
47
|
-
proc {@dataset.delete}.should raise_error(NotImplementedError)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context "Dataset#clone" do
|
52
|
-
setup do
|
53
|
-
@dataset = Sequel::Dataset.new(nil).from(:items)
|
54
|
-
end
|
55
|
-
|
56
|
-
specify "should create an exact copy of the dataset" do
|
57
|
-
@c = Class.new
|
58
|
-
@dataset.set_model(@c)
|
59
|
-
@clone = @dataset.clone
|
60
|
-
|
61
|
-
@clone.should_not === @dataset
|
62
|
-
@clone.class.should == @dataset.class
|
63
|
-
@clone.model_classes.should == @dataset.model_classes
|
64
|
-
end
|
65
|
-
|
66
|
-
specify "should deep-copy the dataset opts" do
|
67
|
-
@clone = @dataset.clone
|
68
|
-
|
69
|
-
@clone.opts.should_not equal(@dataset.opts)
|
70
|
-
@dataset.filter!(:a => 'b')
|
71
|
-
@clone.opts[:filter].should be_nil
|
72
|
-
end
|
73
|
-
|
74
|
-
specify "should return a clone self" do
|
75
|
-
clone = @dataset.clone({})
|
76
|
-
clone.class.should == @dataset.class
|
77
|
-
clone.db.should == @dataset.db
|
78
|
-
clone.opts.should == @dataset.opts
|
79
|
-
end
|
80
|
-
|
81
|
-
specify "should merge the specified options" do
|
82
|
-
clone = @dataset.clone(1 => 2)
|
83
|
-
clone.opts.should == {1 => 2, :from => [:items]}
|
84
|
-
end
|
85
|
-
|
86
|
-
specify "should overwrite existing options" do
|
87
|
-
clone = @dataset.clone(:from => [:other])
|
88
|
-
clone.opts.should == {:from => [:other]}
|
89
|
-
end
|
90
|
-
|
91
|
-
specify "should create a clone with a deep copy of options" do
|
92
|
-
clone = @dataset.clone(:from => [:other])
|
93
|
-
@dataset.opts[:from].should == [:items]
|
94
|
-
clone.opts[:from].should == [:other]
|
95
|
-
end
|
96
|
-
|
97
|
-
specify "should return an object with the same modules included" do
|
98
|
-
m = Module.new do
|
99
|
-
def __xyz__; "xyz"; end
|
100
|
-
end
|
101
|
-
@dataset.extend(m)
|
102
|
-
@dataset.clone({}).should respond_to(:__xyz__)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
context "A simple dataset" do
|
107
|
-
setup do
|
108
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
109
|
-
end
|
110
|
-
|
111
|
-
specify "should format a select statement" do
|
112
|
-
@dataset.select_sql.should == 'SELECT * FROM test'
|
113
|
-
end
|
114
|
-
|
115
|
-
specify "should format a delete statement" do
|
116
|
-
@dataset.delete_sql.should == 'DELETE FROM test'
|
117
|
-
end
|
118
|
-
|
119
|
-
specify "should format an insert statement with default values" do
|
120
|
-
@dataset.insert_sql.should == 'INSERT INTO test DEFAULT VALUES'
|
121
|
-
end
|
122
|
-
|
123
|
-
specify "should format an insert statement with hash" do
|
124
|
-
@dataset.insert_sql(:name => 'wxyz', :price => 342).
|
125
|
-
should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
|
126
|
-
|
127
|
-
@dataset.insert_sql({}).should == "INSERT INTO test DEFAULT VALUES"
|
128
|
-
end
|
129
|
-
|
130
|
-
specify "should format an insert statement with string keys" do
|
131
|
-
@dataset.insert_sql('name' => 'wxyz', 'price' => 342).
|
132
|
-
should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
|
133
|
-
end
|
134
|
-
|
135
|
-
specify "should format an insert statement with an object that respond_to? :values" do
|
136
|
-
dbb = Sequel::Database.new
|
137
|
-
|
138
|
-
v = Object.new
|
139
|
-
def v.values; {:a => 1}; end
|
140
|
-
|
141
|
-
@dataset.insert_sql(v).should == "INSERT INTO test (a) VALUES (1)"
|
142
|
-
|
143
|
-
def v.values; {}; end
|
144
|
-
@dataset.insert_sql(v).should == "INSERT INTO test DEFAULT VALUES"
|
145
|
-
end
|
146
|
-
|
147
|
-
specify "should format an insert statement with an arbitrary value" do
|
148
|
-
@dataset.insert_sql(123).should == "INSERT INTO test VALUES (123)"
|
149
|
-
end
|
150
|
-
|
151
|
-
specify "should format an insert statement with sub-query" do
|
152
|
-
@sub = Sequel::Dataset.new(nil).from(:something).filter(:x => 2)
|
153
|
-
@dataset.insert_sql(@sub).should == \
|
154
|
-
"INSERT INTO test (SELECT * FROM something WHERE (x = 2))"
|
155
|
-
end
|
156
|
-
|
157
|
-
specify "should format an insert statement with array" do
|
158
|
-
@dataset.insert_sql('a', 2, 6.5).should ==
|
159
|
-
"INSERT INTO test VALUES ('a', 2, 6.5)"
|
160
|
-
end
|
161
|
-
|
162
|
-
specify "should format an update statement" do
|
163
|
-
@dataset.update_sql(:name => 'abc').should ==
|
164
|
-
"UPDATE test SET name = 'abc'"
|
165
|
-
end
|
166
|
-
|
167
|
-
specify "should be able to return rows for arbitrary SQL" do
|
168
|
-
@dataset.select_sql(:sql => 'xxx yyy zzz').should ==
|
169
|
-
"xxx yyy zzz"
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
context "A dataset with multiple tables in its FROM clause" do
|
174
|
-
setup do
|
175
|
-
@dataset = Sequel::Dataset.new(nil).from(:t1, :t2)
|
176
|
-
end
|
177
|
-
|
178
|
-
specify "should raise on #update_sql" do
|
179
|
-
proc {@dataset.update_sql(:a=>1)}.should raise_error(Sequel::Error::InvalidOperation)
|
180
|
-
end
|
181
|
-
|
182
|
-
specify "should raise on #delete_sql" do
|
183
|
-
proc {@dataset.delete_sql}.should raise_error(Sequel::Error::InvalidOperation)
|
184
|
-
end
|
185
|
-
|
186
|
-
specify "should generate a select query FROM all specified tables" do
|
187
|
-
@dataset.select_sql.should == "SELECT * FROM t1, t2"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
context "Dataset#where" do
|
192
|
-
setup do
|
193
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
194
|
-
@d1 = @dataset.where(:region => 'Asia')
|
195
|
-
@d2 = @dataset.where('region = ?', 'Asia')
|
196
|
-
@d3 = @dataset.where("a = 1")
|
197
|
-
end
|
198
|
-
|
199
|
-
specify "should work with hashes" do
|
200
|
-
@dataset.where(:name => 'xyz', :price => 342).select_sql.
|
201
|
-
should match(/WHERE \(\(name = 'xyz'\) AND \(price = 342\)\)|WHERE \(\(price = 342\) AND \(name = 'xyz'\)\)/)
|
202
|
-
end
|
203
|
-
|
204
|
-
specify "should work with arrays (ala ActiveRecord)" do
|
205
|
-
@dataset.where('price < ? AND id in ?', 100, [1, 2, 3]).select_sql.should ==
|
206
|
-
"SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
207
|
-
end
|
208
|
-
|
209
|
-
specify "should work with strings (custom SQL expressions)" do
|
210
|
-
@dataset.where('(a = 1 AND b = 2)').select_sql.should ==
|
211
|
-
"SELECT * FROM test WHERE ((a = 1 AND b = 2))"
|
212
|
-
end
|
213
|
-
|
214
|
-
specify "should affect select, delete and update statements" do
|
215
|
-
@d1.select_sql.should == "SELECT * FROM test WHERE (region = 'Asia')"
|
216
|
-
@d1.delete_sql.should == "DELETE FROM test WHERE (region = 'Asia')"
|
217
|
-
@d1.update_sql(:GDP => 0).should == "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
|
218
|
-
|
219
|
-
@d2.select_sql.should == "SELECT * FROM test WHERE (region = 'Asia')"
|
220
|
-
@d2.delete_sql.should == "DELETE FROM test WHERE (region = 'Asia')"
|
221
|
-
@d2.update_sql(:GDP => 0).should == "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
|
222
|
-
|
223
|
-
@d3.select_sql.should == "SELECT * FROM test WHERE (a = 1)"
|
224
|
-
@d3.delete_sql.should == "DELETE FROM test WHERE (a = 1)"
|
225
|
-
@d3.update_sql(:GDP => 0).should == "UPDATE test SET GDP = 0 WHERE (a = 1)"
|
226
|
-
|
227
|
-
end
|
228
|
-
|
229
|
-
specify "should be composable using AND operator (for scoping)" do
|
230
|
-
# hashes are merged, no problem
|
231
|
-
@d1.where(:size => 'big').select_sql.should ==
|
232
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (size = 'big'))"
|
233
|
-
|
234
|
-
# hash and string
|
235
|
-
@d1.where('population > 1000').select_sql.should ==
|
236
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (population > 1000))"
|
237
|
-
@d1.where('(a > 1) OR (b < 2)').select_sql.should ==
|
238
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND ((a > 1) OR (b < 2)))"
|
239
|
-
|
240
|
-
# hash and array
|
241
|
-
@d1.where('GDP > ?', 1000).select_sql.should ==
|
242
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
243
|
-
|
244
|
-
# array and array
|
245
|
-
@d2.where('GDP > ?', 1000).select_sql.should ==
|
246
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
247
|
-
|
248
|
-
# array and hash
|
249
|
-
@d2.where(:name => ['Japan', 'China']).select_sql.should ==
|
250
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
|
251
|
-
|
252
|
-
# array and string
|
253
|
-
@d2.where('GDP > ?').select_sql.should ==
|
254
|
-
"SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
|
255
|
-
|
256
|
-
# string and string
|
257
|
-
@d3.where('b = 2').select_sql.should ==
|
258
|
-
"SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
|
259
|
-
|
260
|
-
# string and hash
|
261
|
-
@d3.where(:c => 3).select_sql.should ==
|
262
|
-
"SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
|
263
|
-
|
264
|
-
# string and array
|
265
|
-
@d3.where('d = ?', 4).select_sql.should ==
|
266
|
-
"SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
|
267
|
-
end
|
268
|
-
|
269
|
-
specify "should be composable using AND operator (for scoping) with block" do
|
270
|
-
@d3.where{:e < 5}.select_sql.should ==
|
271
|
-
"SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
|
272
|
-
end
|
273
|
-
|
274
|
-
specify "should raise if the dataset is grouped" do
|
275
|
-
proc {@dataset.group(:t).where(:a => 1)}.should_not raise_error
|
276
|
-
@dataset.group(:t).where(:a => 1).sql.should ==
|
277
|
-
"SELECT * FROM test WHERE (a = 1) GROUP BY t"
|
278
|
-
end
|
279
|
-
|
280
|
-
specify "should accept ranges" do
|
281
|
-
@dataset.filter(:id => 4..7).sql.should ==
|
282
|
-
'SELECT * FROM test WHERE ((id >= 4) AND (id <= 7))'
|
283
|
-
@dataset.filter(:id => 4...7).sql.should ==
|
284
|
-
'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
|
285
|
-
|
286
|
-
@dataset.filter(:table__id => 4..7).sql.should ==
|
287
|
-
'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id <= 7))'
|
288
|
-
@dataset.filter(:table__id => 4...7).sql.should ==
|
289
|
-
'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id < 7))'
|
290
|
-
end
|
291
|
-
|
292
|
-
specify "should accept nil" do
|
293
|
-
@dataset.filter(:owner_id => nil).sql.should ==
|
294
|
-
'SELECT * FROM test WHERE (owner_id IS NULL)'
|
295
|
-
end
|
296
|
-
|
297
|
-
specify "should accept a subquery" do
|
298
|
-
@dataset.filter('gdp > ?', @d1.select(:avg[:gdp])).sql.should ==
|
299
|
-
"SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
300
|
-
|
301
|
-
@dataset.filter(:id => @d1.select(:id)).sql.should ==
|
302
|
-
"SELECT * FROM test WHERE (id IN (SELECT id FROM test WHERE (region = 'Asia')))"
|
303
|
-
end
|
304
|
-
|
305
|
-
specify "should accept a subquery for an EXISTS clause" do
|
306
|
-
a = @dataset.filter(:price < 100)
|
307
|
-
@dataset.filter(a.exists).sql.should ==
|
308
|
-
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
309
|
-
end
|
310
|
-
|
311
|
-
specify "should accept proc expressions" do
|
312
|
-
d = @d1.select(:avg[:gdp])
|
313
|
-
@dataset.filter {:gdp > d}.sql.should ==
|
314
|
-
"SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
315
|
-
|
316
|
-
@dataset.filter {:a < 1}.sql.should ==
|
317
|
-
'SELECT * FROM test WHERE (a < 1)'
|
318
|
-
|
319
|
-
@dataset.filter {(:a >= 1) & (:b <= 2)}.sql.should ==
|
320
|
-
'SELECT * FROM test WHERE ((a >= 1) AND (b <= 2))'
|
321
|
-
|
322
|
-
@dataset.filter {:c.like 'ABC%'}.sql.should ==
|
323
|
-
"SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
324
|
-
|
325
|
-
@dataset.filter {:c.like 'ABC%'}.sql.should ==
|
326
|
-
"SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
327
|
-
|
328
|
-
@dataset.filter {:c.like 'ABC%', '%XYZ'}.sql.should ==
|
329
|
-
"SELECT * FROM test WHERE ((c LIKE 'ABC%') OR (c LIKE '%XYZ'))"
|
330
|
-
end
|
331
|
-
|
332
|
-
specify "should work for grouped datasets" do
|
333
|
-
@dataset.group(:a).filter(:b => 1).sql.should ==
|
334
|
-
'SELECT * FROM test WHERE (b = 1) GROUP BY a'
|
335
|
-
end
|
336
|
-
|
337
|
-
specify "should accept true and false as arguments" do
|
338
|
-
@dataset.filter(true).sql.should ==
|
339
|
-
"SELECT * FROM test WHERE 't'"
|
340
|
-
@dataset.filter(false).sql.should ==
|
341
|
-
"SELECT * FROM test WHERE 'f'"
|
342
|
-
end
|
343
|
-
|
344
|
-
specify "should allow the use of blocks and arguments simultaneously" do
|
345
|
-
@dataset.filter(:zz < 3){:yy > 3}.sql.should ==
|
346
|
-
'SELECT * FROM test WHERE ((zz < 3) AND (yy > 3))'
|
347
|
-
end
|
348
|
-
|
349
|
-
specify "should yield a VirtualRow to the block" do
|
350
|
-
x = nil
|
351
|
-
@dataset.filter{|r| x = r; false}
|
352
|
-
x.should be_a_kind_of(Sequel::SQL::VirtualRow)
|
353
|
-
@dataset.filter{|r| ((r.name < 'b') & {r.table__id => 1}) | r.is_active(r.blah, r.xx, r.x__y_z)}.sql.should ==
|
354
|
-
"SELECT * FROM test WHERE (((name < 'b') AND (table.id = 1)) OR is_active(blah, xx, x.y_z))"
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
context "Dataset#or" do
|
359
|
-
setup do
|
360
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
361
|
-
@d1 = @dataset.where(:x => 1)
|
362
|
-
end
|
363
|
-
|
364
|
-
specify "should raise if no filter exists" do
|
365
|
-
proc {@dataset.or(:a => 1)}.should raise_error(Sequel::Error)
|
366
|
-
end
|
367
|
-
|
368
|
-
specify "should add an alternative expression to the where clause" do
|
369
|
-
@d1.or(:y => 2).sql.should ==
|
370
|
-
'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
371
|
-
end
|
372
|
-
|
373
|
-
specify "should accept all forms of filters" do
|
374
|
-
@d1.or('y > ?', 2).sql.should ==
|
375
|
-
'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
376
|
-
@d1.or(:yy > 3).sql.should ==
|
377
|
-
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
378
|
-
end
|
379
|
-
|
380
|
-
specify "should accept blocks passed to filter" do
|
381
|
-
@d1.or{:yy > 3}.sql.should ==
|
382
|
-
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
383
|
-
end
|
384
|
-
|
385
|
-
specify "should correctly add parens to give predictable results" do
|
386
|
-
@d1.filter(:y => 2).or(:z => 3).sql.should ==
|
387
|
-
'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
388
|
-
|
389
|
-
@d1.or(:y => 2).filter(:z => 3).sql.should ==
|
390
|
-
'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
391
|
-
end
|
392
|
-
|
393
|
-
specify "should allow the use of blocks and arguments simultaneously" do
|
394
|
-
@d1.or(:zz < 3){:yy > 3}.sql.should ==
|
395
|
-
'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
context "Dataset#and" do
|
400
|
-
setup do
|
401
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
402
|
-
@d1 = @dataset.where(:x => 1)
|
403
|
-
end
|
404
|
-
|
405
|
-
specify "should raise if no filter exists" do
|
406
|
-
proc {@dataset.and(:a => 1)}.should raise_error(Sequel::Error)
|
407
|
-
proc {@dataset.where(:a => 1).group(:t).and(:b => 2)}.should_not raise_error(Sequel::Error)
|
408
|
-
@dataset.where(:a => 1).group(:t).and(:b => 2).sql ==
|
409
|
-
"SELECT * FROM test WHERE (a = 1) AND (b = 2) GROUP BY t"
|
410
|
-
end
|
411
|
-
|
412
|
-
specify "should add an alternative expression to the where clause" do
|
413
|
-
@d1.and(:y => 2).sql.should ==
|
414
|
-
'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
415
|
-
end
|
416
|
-
|
417
|
-
specify "should accept all forms of filters" do
|
418
|
-
# probably not exhaustive, but good enough
|
419
|
-
@d1.and('y > ?', 2).sql.should ==
|
420
|
-
'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
421
|
-
@d1.and(:yy > 3).sql.should ==
|
422
|
-
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
423
|
-
end
|
424
|
-
|
425
|
-
specify "should accept blocks passed to filter" do
|
426
|
-
@d1.and {:yy > 3}.sql.should ==
|
427
|
-
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
428
|
-
end
|
429
|
-
|
430
|
-
specify "should correctly add parens to give predictable results" do
|
431
|
-
@d1.or(:y => 2).and(:z => 3).sql.should ==
|
432
|
-
'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
433
|
-
|
434
|
-
@d1.and(:y => 2).or(:z => 3).sql.should ==
|
435
|
-
'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
|
-
context "Dataset#exclude" do
|
440
|
-
setup do
|
441
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
442
|
-
end
|
443
|
-
|
444
|
-
specify "should correctly include the NOT operator when one condition is given" do
|
445
|
-
@dataset.exclude(:region=>'Asia').select_sql.should ==
|
446
|
-
"SELECT * FROM test WHERE (region != 'Asia')"
|
447
|
-
end
|
448
|
-
|
449
|
-
specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
|
450
|
-
@dataset.exclude(:region => 'Asia', :name => 'Japan').select_sql.
|
451
|
-
should match(Regexp.union(/WHERE \(\(region != 'Asia'\) AND \(name != 'Japan'\)\)/,
|
452
|
-
/WHERE \(\(name != 'Japan'\) AND \(region != 'Asia'\)\)/))
|
453
|
-
end
|
454
|
-
|
455
|
-
specify "should parenthesize a single string condition correctly" do
|
456
|
-
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should ==
|
457
|
-
"SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
458
|
-
end
|
459
|
-
|
460
|
-
specify "should parenthesize an array condition correctly" do
|
461
|
-
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should ==
|
462
|
-
"SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
463
|
-
end
|
464
|
-
|
465
|
-
specify "should correctly parenthesize when it is used twice" do
|
466
|
-
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should ==
|
467
|
-
"SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
468
|
-
end
|
469
|
-
|
470
|
-
specify "should support proc expressions" do
|
471
|
-
@dataset.exclude{:id < 6}.sql.should ==
|
472
|
-
'SELECT * FROM test WHERE (id >= 6)'
|
473
|
-
end
|
474
|
-
|
475
|
-
specify "should allow the use of blocks and arguments simultaneously" do
|
476
|
-
@dataset.exclude(:id => (7..11)){:id < 6}.sql.should ==
|
477
|
-
'SELECT * FROM test WHERE (((id < 7) OR (id > 11)) OR (id >= 6))'
|
478
|
-
end
|
479
|
-
end
|
480
|
-
|
481
|
-
context "Dataset#invert" do
|
482
|
-
setup do
|
483
|
-
@d = Sequel::Dataset.new(nil).from(:test)
|
484
|
-
end
|
485
|
-
|
486
|
-
specify "should raise error if the dataset is not filtered" do
|
487
|
-
proc{@d.invert}.should raise_error(Sequel::Error)
|
488
|
-
end
|
489
|
-
|
490
|
-
specify "should invert current filter if dataset is filtered" do
|
491
|
-
@d.filter(:x).invert.sql.should == 'SELECT * FROM test WHERE NOT x'
|
492
|
-
end
|
493
|
-
|
494
|
-
specify "should invert both having and where if both are preset" do
|
495
|
-
@d.filter(:x).group(:x).having(:x).invert.sql.should == 'SELECT * FROM test WHERE NOT x GROUP BY x HAVING NOT x'
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
context "Dataset#having" do
|
500
|
-
setup do
|
501
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
502
|
-
@grouped = @dataset.group(:region).select(:region, :sum[:population], :avg[:gdp])
|
503
|
-
@d1 = @grouped.having('sum(population) > 10')
|
504
|
-
@d2 = @grouped.having(:region => 'Asia')
|
505
|
-
@columns = "region, sum(population), avg(gdp)"
|
506
|
-
end
|
507
|
-
|
508
|
-
specify "should raise if the dataset is not grouped" do
|
509
|
-
proc {@dataset.having('avg(gdp) > 10')}.should raise_error(Sequel::Error::InvalidOperation)
|
510
|
-
end
|
511
|
-
|
512
|
-
specify "should affect select statements" do
|
513
|
-
@d1.select_sql.should ==
|
514
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
515
|
-
end
|
516
|
-
|
517
|
-
specify "should support proc expressions" do
|
518
|
-
@grouped.having {:sum[:population] > 10}.sql.should ==
|
519
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
520
|
-
end
|
521
|
-
|
522
|
-
specify "should work with and on the having clause" do
|
523
|
-
@grouped.having( :a > 1 ).and( :b < 2 ).sql.should ==
|
524
|
-
"SELECT #{@columns} FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
|
525
|
-
end
|
526
|
-
end
|
527
|
-
|
528
|
-
context "a grouped dataset" do
|
529
|
-
setup do
|
530
|
-
@dataset = Sequel::Dataset.new(nil).from(:test).group(:type_id)
|
531
|
-
end
|
532
|
-
|
533
|
-
specify "should raise when trying to generate an update statement" do
|
534
|
-
proc {@dataset.update_sql(:id => 0)}.should raise_error
|
535
|
-
end
|
536
|
-
|
537
|
-
specify "should raise when trying to generate a delete statement" do
|
538
|
-
proc {@dataset.delete_sql}.should raise_error
|
539
|
-
end
|
540
|
-
|
541
|
-
specify "should specify the grouping in generated select statement" do
|
542
|
-
@dataset.select_sql.should ==
|
543
|
-
"SELECT * FROM test GROUP BY type_id"
|
544
|
-
end
|
545
|
-
|
546
|
-
specify "should format the right statement for counting (as a subquery)" do
|
547
|
-
db = MockDatabase.new
|
548
|
-
db[:test].select(:name).group(:name).count
|
549
|
-
db.sqls.should == ["SELECT COUNT(*) FROM (SELECT name FROM test GROUP BY name) t1 LIMIT 1"]
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
context "Dataset#group_by" do
|
554
|
-
setup do
|
555
|
-
@dataset = Sequel::Dataset.new(nil).from(:test).group_by(:type_id)
|
556
|
-
end
|
557
|
-
|
558
|
-
specify "should raise when trying to generate an update statement" do
|
559
|
-
proc {@dataset.update_sql(:id => 0)}.should raise_error
|
560
|
-
end
|
561
|
-
|
562
|
-
specify "should raise when trying to generate a delete statement" do
|
563
|
-
proc {@dataset.delete_sql}.should raise_error
|
564
|
-
end
|
565
|
-
|
566
|
-
specify "should specify the grouping in generated select statement" do
|
567
|
-
@dataset.select_sql.should ==
|
568
|
-
"SELECT * FROM test GROUP BY type_id"
|
569
|
-
@dataset.group_by(:a, :b).select_sql.should ==
|
570
|
-
"SELECT * FROM test GROUP BY a, b"
|
571
|
-
end
|
572
|
-
|
573
|
-
specify "should specify the grouping in generated select statement" do
|
574
|
-
@dataset.group_by(:type_id=>nil).select_sql.should ==
|
575
|
-
"SELECT * FROM test GROUP BY (type_id IS NULL)"
|
576
|
-
end
|
577
|
-
|
578
|
-
specify "should be aliased as #group" do
|
579
|
-
@dataset.group(:type_id=>nil).select_sql.should ==
|
580
|
-
"SELECT * FROM test GROUP BY (type_id IS NULL)"
|
581
|
-
end
|
582
|
-
end
|
583
|
-
|
584
|
-
context "Dataset#as" do
|
585
|
-
specify "should set up an alias" do
|
586
|
-
dataset = Sequel::Dataset.new(nil).from(:test)
|
587
|
-
dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == \
|
588
|
-
'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
|
589
|
-
end
|
590
|
-
end
|
591
|
-
|
592
|
-
context "Dataset#literal" do
|
593
|
-
setup do
|
594
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
595
|
-
end
|
596
|
-
|
597
|
-
specify "should escape strings properly" do
|
598
|
-
@dataset.literal('abc').should == "'abc'"
|
599
|
-
@dataset.literal('a"x"bc').should == "'a\"x\"bc'"
|
600
|
-
@dataset.literal("a'bc").should == "'a''bc'"
|
601
|
-
@dataset.literal("a''bc").should == "'a''''bc'"
|
602
|
-
@dataset.literal("a\\bc").should == "'a\\\\bc'"
|
603
|
-
@dataset.literal("a\\\\bc").should == "'a\\\\\\\\bc'"
|
604
|
-
@dataset.literal("a\\'bc").should == "'a\\\\''bc'"
|
605
|
-
end
|
606
|
-
|
607
|
-
specify "should literalize numbers properly" do
|
608
|
-
@dataset.literal(1).should == "1"
|
609
|
-
@dataset.literal(1.5).should == "1.5"
|
610
|
-
end
|
611
|
-
|
612
|
-
specify "should literalize nil as NULL" do
|
613
|
-
@dataset.literal(nil).should == "NULL"
|
614
|
-
end
|
615
|
-
|
616
|
-
specify "should literalize an array properly" do
|
617
|
-
@dataset.literal([]).should == "(NULL)"
|
618
|
-
@dataset.literal([1, 'abc', 3]).should == "(1, 'abc', 3)"
|
619
|
-
@dataset.literal([1, "a'b''c", 3]).should == "(1, 'a''b''''c', 3)"
|
620
|
-
end
|
621
|
-
|
622
|
-
specify "should literalize symbols as column references" do
|
623
|
-
@dataset.literal(:name).should == "name"
|
624
|
-
@dataset.literal(:items__name).should == "items.name"
|
625
|
-
end
|
626
|
-
|
627
|
-
specify "should raise an error for unsupported types" do
|
628
|
-
proc {@dataset.literal({})}.should raise_error
|
629
|
-
end
|
630
|
-
|
631
|
-
specify "should literalize datasets as subqueries" do
|
632
|
-
d = @dataset.from(:test)
|
633
|
-
d.literal(d).should == "(#{d.sql})"
|
634
|
-
end
|
635
|
-
|
636
|
-
specify "should literalize Time properly" do
|
637
|
-
t = Time.now
|
638
|
-
s = t.strftime("TIMESTAMP '%Y-%m-%d %H:%M:%S'")
|
639
|
-
@dataset.literal(t).should == s
|
640
|
-
end
|
641
|
-
|
642
|
-
specify "should literalize Date properly" do
|
643
|
-
d = Date.today
|
644
|
-
s = d.strftime("DATE '%Y-%m-%d'")
|
645
|
-
@dataset.literal(d).should == s
|
646
|
-
end
|
647
|
-
|
648
|
-
specify "should not literalize expression strings" do
|
649
|
-
@dataset.literal('col1 + 2'.expr).should == 'col1 + 2'
|
650
|
-
|
651
|
-
@dataset.update_sql(:a => 'a + 2'.expr).should ==
|
652
|
-
'UPDATE test SET a = a + 2'
|
653
|
-
end
|
654
|
-
|
655
|
-
specify "should literalize BigDecimal instances correctly" do
|
656
|
-
@dataset.literal(BigDecimal.new("80")).should == "80.0"
|
657
|
-
end
|
658
|
-
end
|
659
|
-
|
660
|
-
context "Dataset#from" do
|
661
|
-
setup do
|
662
|
-
@dataset = Sequel::Dataset.new(nil)
|
663
|
-
end
|
664
|
-
|
665
|
-
specify "should accept a Dataset" do
|
666
|
-
proc {@dataset.from(@dataset)}.should_not raise_error
|
667
|
-
end
|
668
|
-
|
669
|
-
specify "should format a Dataset as a subquery if it has had options set" do
|
670
|
-
@dataset.from(@dataset.from(:a).where(:a=>1)).select_sql.should ==
|
671
|
-
"SELECT * FROM (SELECT * FROM a WHERE (a = 1)) t1"
|
672
|
-
end
|
673
|
-
|
674
|
-
specify "should automatically alias sub-queries" do
|
675
|
-
@dataset.from(@dataset.from(:a).group(:b)).select_sql.should ==
|
676
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) t1"
|
677
|
-
|
678
|
-
d1 = @dataset.from(:a).group(:b)
|
679
|
-
d2 = @dataset.from(:c).group(:d)
|
680
|
-
|
681
|
-
@dataset.from(d1, d2).sql.should ==
|
682
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) t1, (SELECT * FROM c GROUP BY d) t2"
|
683
|
-
end
|
684
|
-
|
685
|
-
specify "should accept a hash for aliasing" do
|
686
|
-
@dataset.from(:a => :b).sql.should ==
|
687
|
-
"SELECT * FROM a b"
|
688
|
-
|
689
|
-
@dataset.from(:a => 'b').sql.should ==
|
690
|
-
"SELECT * FROM a b"
|
691
|
-
|
692
|
-
@dataset.from(:a => :c[:d]).sql.should ==
|
693
|
-
"SELECT * FROM a c(d)"
|
694
|
-
|
695
|
-
@dataset.from(@dataset.from(:a).group(:b) => :c).sql.should ==
|
696
|
-
"SELECT * FROM (SELECT * FROM a GROUP BY b) c"
|
697
|
-
end
|
698
|
-
|
699
|
-
specify "should always use a subquery if given a dataset" do
|
700
|
-
@dataset.from(@dataset.from(:a)).select_sql.should ==
|
701
|
-
"SELECT * FROM (SELECT * FROM a) t1"
|
702
|
-
end
|
703
|
-
|
704
|
-
specify "should raise if no source is given" do
|
705
|
-
proc {@dataset.from(@dataset.from).select_sql}.should raise_error(Sequel::Error)
|
706
|
-
end
|
707
|
-
|
708
|
-
specify "should accept sql functions" do
|
709
|
-
@dataset.from(:abc[:def]).select_sql.should ==
|
710
|
-
"SELECT * FROM abc(def)"
|
711
|
-
|
712
|
-
@dataset.from(:a[:i]).select_sql.should ==
|
713
|
-
"SELECT * FROM a(i)"
|
714
|
-
end
|
715
|
-
end
|
716
|
-
|
717
|
-
context "Dataset#select" do
|
718
|
-
setup do
|
719
|
-
@d = Sequel::Dataset.new(nil).from(:test)
|
720
|
-
end
|
721
|
-
|
722
|
-
specify "should accept variable arity" do
|
723
|
-
@d.select(:name).sql.should == 'SELECT name FROM test'
|
724
|
-
@d.select(:a, :b, :test__c).sql.should == 'SELECT a, b, test.c FROM test'
|
725
|
-
end
|
726
|
-
|
727
|
-
specify "should accept symbols and literal strings" do
|
728
|
-
@d.select('aaa'.lit).sql.should == 'SELECT aaa FROM test'
|
729
|
-
@d.select(:a, 'b'.lit).sql.should == 'SELECT a, b FROM test'
|
730
|
-
@d.select(:test__cc, 'test.d AS e'.lit).sql.should ==
|
731
|
-
'SELECT test.cc, test.d AS e FROM test'
|
732
|
-
@d.select('test.d AS e'.lit, :test__cc).sql.should ==
|
733
|
-
'SELECT test.d AS e, test.cc FROM test'
|
734
|
-
|
735
|
-
# symbol helpers
|
736
|
-
@d.select(:test.*).sql.should ==
|
737
|
-
'SELECT test.* FROM test'
|
738
|
-
@d.select(:test__name.as(:n)).sql.should ==
|
739
|
-
'SELECT test.name AS n FROM test'
|
740
|
-
@d.select(:test__name___n).sql.should ==
|
741
|
-
'SELECT test.name AS n FROM test'
|
742
|
-
end
|
743
|
-
|
744
|
-
specify "should use the wildcard if no arguments are given" do
|
745
|
-
@d.select.sql.should == 'SELECT * FROM test'
|
746
|
-
end
|
747
|
-
|
748
|
-
specify "should accept a hash for AS values" do
|
749
|
-
@d.select(:name => 'n', :__ggh => 'age').sql.should =~
|
750
|
-
/SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
751
|
-
end
|
752
|
-
|
753
|
-
specify "should overrun the previous select option" do
|
754
|
-
@d.select!(:a, :b, :c).select.sql.should == 'SELECT * FROM test'
|
755
|
-
@d.select!(:price).select(:name).sql.should == 'SELECT name FROM test'
|
756
|
-
end
|
757
|
-
|
758
|
-
specify "should accept arbitrary objects and literalize them correctly" do
|
759
|
-
@d.select(1, :a, 't').sql.should == "SELECT 1, a, 't' FROM test"
|
760
|
-
|
761
|
-
@d.select(nil, :sum[:t], :x___y).sql.should == "SELECT NULL, sum(t), x AS y FROM test"
|
762
|
-
|
763
|
-
@d.select(nil, 1, :x => :y).sql.should == "SELECT NULL, 1, x AS y FROM test"
|
764
|
-
end
|
765
|
-
end
|
766
|
-
|
767
|
-
context "Dataset#select_all" do
|
768
|
-
setup do
|
769
|
-
@d = Sequel::Dataset.new(nil).from(:test)
|
770
|
-
end
|
771
|
-
|
772
|
-
specify "should select the wildcard" do
|
773
|
-
@d.select_all.sql.should == 'SELECT * FROM test'
|
774
|
-
end
|
775
|
-
|
776
|
-
specify "should overrun the previous select option" do
|
777
|
-
@d.select!(:a, :b, :c).select_all.sql.should == 'SELECT * FROM test'
|
778
|
-
end
|
779
|
-
end
|
780
|
-
|
781
|
-
context "Dataset#select_more" do
|
782
|
-
setup do
|
783
|
-
@d = Sequel::Dataset.new(nil).from(:test)
|
784
|
-
end
|
785
|
-
|
786
|
-
specify "should act like #select for datasets with no selection" do
|
787
|
-
@d.select_more(:a, :b).sql.should == 'SELECT a, b FROM test'
|
788
|
-
@d.select_all.select_more(:a, :b).sql.should == 'SELECT a, b FROM test'
|
789
|
-
@d.select(:blah).select_all.select_more(:a, :b).sql.should == 'SELECT a, b FROM test'
|
790
|
-
end
|
791
|
-
|
792
|
-
specify "should add to the currently selected columns" do
|
793
|
-
@d.select(:a).select_more(:b).sql.should == 'SELECT a, b FROM test'
|
794
|
-
@d.select(:a.*).select_more(:b.*).sql.should == 'SELECT a.*, b.* FROM test'
|
795
|
-
end
|
796
|
-
end
|
797
|
-
|
798
|
-
context "Dataset#order" do
|
799
|
-
setup do
|
800
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
801
|
-
end
|
802
|
-
|
803
|
-
specify "should include an ORDER BY clause in the select statement" do
|
804
|
-
@dataset.order(:name).sql.should ==
|
805
|
-
'SELECT * FROM test ORDER BY name'
|
806
|
-
end
|
807
|
-
|
808
|
-
specify "should accept multiple arguments" do
|
809
|
-
@dataset.order(:name, :price.desc).sql.should ==
|
810
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
811
|
-
end
|
812
|
-
|
813
|
-
specify "should overrun a previous ordering" do
|
814
|
-
@dataset.order(:name).order(:stamp).sql.should ==
|
815
|
-
'SELECT * FROM test ORDER BY stamp'
|
816
|
-
end
|
817
|
-
|
818
|
-
specify "should accept a literal string" do
|
819
|
-
@dataset.order('dada ASC'.lit).sql.should ==
|
820
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
821
|
-
end
|
822
|
-
|
823
|
-
specify "should accept a hash as an expression" do
|
824
|
-
@dataset.order(:name=>nil).sql.should ==
|
825
|
-
'SELECT * FROM test ORDER BY (name IS NULL)'
|
826
|
-
end
|
827
|
-
|
828
|
-
specify "should accept a nil to remove ordering" do
|
829
|
-
@dataset.order(:bah).order(nil).sql.should ==
|
830
|
-
'SELECT * FROM test'
|
831
|
-
end
|
832
|
-
end
|
833
|
-
|
834
|
-
context "Dataset#unfiltered" do
|
835
|
-
setup do
|
836
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
837
|
-
end
|
838
|
-
|
839
|
-
specify "should remove filtering from the dataset" do
|
840
|
-
@dataset.filter(:score=>1).unfiltered.sql.should ==
|
841
|
-
'SELECT * FROM test'
|
842
|
-
end
|
843
|
-
end
|
844
|
-
|
845
|
-
context "Dataset#unordered" do
|
846
|
-
setup do
|
847
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
848
|
-
end
|
849
|
-
|
850
|
-
specify "should remove ordering from the dataset" do
|
851
|
-
@dataset.order(:name).unordered.sql.should ==
|
852
|
-
'SELECT * FROM test'
|
853
|
-
end
|
854
|
-
end
|
855
|
-
|
856
|
-
context "Dataset#order_by" do
|
857
|
-
setup do
|
858
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
859
|
-
end
|
860
|
-
|
861
|
-
specify "should include an ORDER BY clause in the select statement" do
|
862
|
-
@dataset.order_by(:name).sql.should ==
|
863
|
-
'SELECT * FROM test ORDER BY name'
|
864
|
-
end
|
865
|
-
|
866
|
-
specify "should accept multiple arguments" do
|
867
|
-
@dataset.order_by(:name, :price.desc).sql.should ==
|
868
|
-
'SELECT * FROM test ORDER BY name, price DESC'
|
869
|
-
end
|
870
|
-
|
871
|
-
specify "should overrun a previous ordering" do
|
872
|
-
@dataset.order_by(:name).order(:stamp).sql.should ==
|
873
|
-
'SELECT * FROM test ORDER BY stamp'
|
874
|
-
end
|
875
|
-
|
876
|
-
specify "should accept a string" do
|
877
|
-
@dataset.order_by('dada ASC'.lit).sql.should ==
|
878
|
-
'SELECT * FROM test ORDER BY dada ASC'
|
879
|
-
end
|
880
|
-
|
881
|
-
specify "should accept a nil to remove ordering" do
|
882
|
-
@dataset.order_by(:bah).order_by(nil).sql.should ==
|
883
|
-
'SELECT * FROM test'
|
884
|
-
end
|
885
|
-
end
|
886
|
-
|
887
|
-
context "Dataset#order_more" do
|
888
|
-
setup do
|
889
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
890
|
-
end
|
891
|
-
|
892
|
-
specify "should include an ORDER BY clause in the select statement" do
|
893
|
-
@dataset.order_more(:name).sql.should ==
|
894
|
-
'SELECT * FROM test ORDER BY name'
|
895
|
-
end
|
896
|
-
|
897
|
-
specify "should add to a previous ordering" do
|
898
|
-
@dataset.order(:name).order_more(:stamp.desc).sql.should ==
|
899
|
-
'SELECT * FROM test ORDER BY name, stamp DESC'
|
900
|
-
end
|
901
|
-
end
|
902
|
-
|
903
|
-
context "Dataset#reverse_order" do
|
904
|
-
setup do
|
905
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
906
|
-
end
|
907
|
-
|
908
|
-
specify "should use DESC as default order" do
|
909
|
-
@dataset.reverse_order(:name).sql.should ==
|
910
|
-
'SELECT * FROM test ORDER BY name DESC'
|
911
|
-
end
|
912
|
-
|
913
|
-
specify "should invert the order given" do
|
914
|
-
@dataset.reverse_order(:name.desc).sql.should ==
|
915
|
-
'SELECT * FROM test ORDER BY name ASC'
|
916
|
-
end
|
917
|
-
|
918
|
-
specify "should invert the order for ASC expressions" do
|
919
|
-
@dataset.reverse_order(:name.asc).sql.should ==
|
920
|
-
'SELECT * FROM test ORDER BY name DESC'
|
921
|
-
end
|
922
|
-
|
923
|
-
specify "should accept multiple arguments" do
|
924
|
-
@dataset.reverse_order(:name, :price.desc).sql.should ==
|
925
|
-
'SELECT * FROM test ORDER BY name DESC, price ASC'
|
926
|
-
end
|
927
|
-
|
928
|
-
specify "should reverse a previous ordering if no arguments are given" do
|
929
|
-
@dataset.order(:name).reverse_order.sql.should ==
|
930
|
-
'SELECT * FROM test ORDER BY name DESC'
|
931
|
-
@dataset.order(:clumsy.desc, :fool).reverse_order.sql.should ==
|
932
|
-
'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
|
933
|
-
end
|
934
|
-
|
935
|
-
specify "should return an unordered dataset for a dataset with no order" do
|
936
|
-
@dataset.unordered.reverse_order.sql.should ==
|
937
|
-
'SELECT * FROM test'
|
938
|
-
end
|
939
|
-
|
940
|
-
specify "should have #reverse alias" do
|
941
|
-
@dataset.order(:name).reverse.sql.should ==
|
942
|
-
'SELECT * FROM test ORDER BY name DESC'
|
943
|
-
end
|
944
|
-
end
|
945
|
-
|
946
|
-
context "Dataset#limit" do
|
947
|
-
setup do
|
948
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
949
|
-
end
|
950
|
-
|
951
|
-
specify "should include a LIMIT clause in the select statement" do
|
952
|
-
@dataset.limit(10).sql.should ==
|
953
|
-
'SELECT * FROM test LIMIT 10'
|
954
|
-
end
|
955
|
-
|
956
|
-
specify "should accept ranges" do
|
957
|
-
@dataset.limit(3..7).sql.should ==
|
958
|
-
'SELECT * FROM test LIMIT 5 OFFSET 3'
|
959
|
-
|
960
|
-
@dataset.limit(3...7).sql.should ==
|
961
|
-
'SELECT * FROM test LIMIT 4 OFFSET 3'
|
962
|
-
end
|
963
|
-
|
964
|
-
specify "should include an offset if a second argument is given" do
|
965
|
-
@dataset.limit(6, 10).sql.should ==
|
966
|
-
'SELECT * FROM test LIMIT 6 OFFSET 10'
|
967
|
-
end
|
968
|
-
|
969
|
-
specify "should work with fixed sql datasets" do
|
970
|
-
@dataset.opts[:sql] = 'select * from cccc'
|
971
|
-
@dataset.limit(6, 10).sql.should ==
|
972
|
-
'SELECT * FROM (select * from cccc) t1 LIMIT 6 OFFSET 10'
|
973
|
-
end
|
974
|
-
|
975
|
-
specify "should raise an error if an invalid limit or offset is used" do
|
976
|
-
proc{@dataset.limit(-1)}.should raise_error(Sequel::Error)
|
977
|
-
proc{@dataset.limit(0)}.should raise_error(Sequel::Error)
|
978
|
-
proc{@dataset.limit(1)}.should_not raise_error(Sequel::Error)
|
979
|
-
proc{@dataset.limit(1, -1)}.should raise_error(Sequel::Error)
|
980
|
-
proc{@dataset.limit(1, 0)}.should_not raise_error(Sequel::Error)
|
981
|
-
proc{@dataset.limit(1, 1)}.should_not raise_error(Sequel::Error)
|
982
|
-
end
|
983
|
-
end
|
984
|
-
|
985
|
-
context "Dataset#naked" do
|
986
|
-
setup do
|
987
|
-
@d1 = Sequel::Dataset.new(nil, {1 => 2, 3 => 4})
|
988
|
-
@d2 = Sequel::Dataset.new(nil, {1 => 2, 3 => 4}).set_model(Object)
|
989
|
-
end
|
990
|
-
|
991
|
-
specify "should return a clone with :naked option set" do
|
992
|
-
naked = @d1.naked
|
993
|
-
naked.opts[:naked].should be_true
|
994
|
-
end
|
995
|
-
|
996
|
-
specify "should remove any existing reference to a model class" do
|
997
|
-
naked = @d2.naked
|
998
|
-
naked.opts[:models].should be_nil
|
999
|
-
end
|
1000
|
-
end
|
1001
|
-
|
1002
|
-
context "Dataset#qualified_column_name" do
|
1003
|
-
setup do
|
1004
|
-
@dataset = Sequel::Dataset.new(nil).from(:test)
|
1005
|
-
end
|
1006
|
-
|
1007
|
-
specify "should return the literal value if not given a symbol" do
|
1008
|
-
@dataset.literal(@dataset.send(:qualified_column_name, 'ccc__b', :items)).should == "'ccc__b'"
|
1009
|
-
@dataset.literal(@dataset.send(:qualified_column_name, 3, :items)).should == '3'
|
1010
|
-
@dataset.literal(@dataset.send(:qualified_column_name, 'a'.lit, :items)).should == 'a'
|
1011
|
-
end
|
1012
|
-
|
1013
|
-
specify "should qualify the column with the supplied table name if given an unqualified symbol" do
|
1014
|
-
@dataset.literal(@dataset.send(:qualified_column_name, :b1, :items)).should == 'items.b1'
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
specify "should not changed the qualifed column's table if given a qualified symbol" do
|
1018
|
-
@dataset.literal(@dataset.send(:qualified_column_name, :ccc__b, :items)).should == 'ccc.b'
|
1019
|
-
end
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
class DummyDataset < Sequel::Dataset
|
1023
|
-
VALUES = [
|
1024
|
-
{:a => 1, :b => 2},
|
1025
|
-
{:a => 3, :b => 4},
|
1026
|
-
{:a => 5, :b => 6}
|
1027
|
-
]
|
1028
|
-
def fetch_rows(sql, &block)
|
1029
|
-
VALUES.each(&block)
|
1030
|
-
end
|
1031
|
-
end
|
1032
|
-
|
1033
|
-
context "Dataset#map" do
|
1034
|
-
setup do
|
1035
|
-
@d = DummyDataset.new(nil).from(:items)
|
1036
|
-
end
|
1037
|
-
|
1038
|
-
specify "should provide the usual functionality if no argument is given" do
|
1039
|
-
@d.map {|n| n[:a] + n[:b]}.should == [3, 7, 11]
|
1040
|
-
end
|
1041
|
-
|
1042
|
-
specify "should map using #[column name] if column name is given" do
|
1043
|
-
@d.map(:a).should == [1, 3, 5]
|
1044
|
-
end
|
1045
|
-
|
1046
|
-
specify "should return the complete dataset values if nothing is given" do
|
1047
|
-
@d.map.to_a.should == DummyDataset::VALUES
|
1048
|
-
end
|
1049
|
-
end
|
1050
|
-
|
1051
|
-
context "Dataset#to_hash" do
|
1052
|
-
setup do
|
1053
|
-
@d = DummyDataset.new(nil).from(:items)
|
1054
|
-
end
|
1055
|
-
|
1056
|
-
specify "should provide a hash with the first column as key and the second as value" do
|
1057
|
-
@d.to_hash(:a, :b).should == {1 => 2, 3 => 4, 5 => 6}
|
1058
|
-
@d.to_hash(:b, :a).should == {2 => 1, 4 => 3, 6 => 5}
|
1059
|
-
end
|
1060
|
-
|
1061
|
-
specify "should provide a hash with the first column as key and the entire hash as value if the value column is blank or nil" do
|
1062
|
-
@d.to_hash(:a).should == {1 => {:a => 1, :b => 2}, 3 => {:a => 3, :b => 4}, 5 => {:a => 5, :b => 6}}
|
1063
|
-
@d.to_hash(:b).should == {2 => {:a => 1, :b => 2}, 4 => {:a => 3, :b => 4}, 6 => {:a => 5, :b => 6}}
|
1064
|
-
end
|
1065
|
-
end
|
1066
|
-
|
1067
|
-
context "Dataset#uniq" do
|
1068
|
-
setup do
|
1069
|
-
@db = MockDatabase.new
|
1070
|
-
@dataset = @db[:test].select(:name)
|
1071
|
-
end
|
1072
|
-
|
1073
|
-
specify "should include DISTINCT clause in statement" do
|
1074
|
-
@dataset.uniq.sql.should == 'SELECT DISTINCT name FROM test'
|
1075
|
-
end
|
1076
|
-
|
1077
|
-
specify "should be aliased by Dataset#distinct" do
|
1078
|
-
@dataset.distinct.sql.should == 'SELECT DISTINCT name FROM test'
|
1079
|
-
end
|
1080
|
-
|
1081
|
-
specify "should accept an expression list" do
|
1082
|
-
@dataset.uniq(:a, :b).sql.should == 'SELECT DISTINCT ON (a, b) name FROM test'
|
1083
|
-
|
1084
|
-
@dataset.uniq(:stamp.cast_as(:integer), :node_id=>nil).sql.should == 'SELECT DISTINCT ON (cast(stamp AS integer), (node_id IS NULL)) name FROM test'
|
1085
|
-
end
|
1086
|
-
|
1087
|
-
specify "should do a subselect for count" do
|
1088
|
-
@dataset.uniq.count
|
1089
|
-
@db.sqls.should == ['SELECT COUNT(*) FROM (SELECT DISTINCT name FROM test) t1 LIMIT 1']
|
1090
|
-
end
|
1091
|
-
end
|
1092
|
-
|
1093
|
-
context "Dataset#count" do
|
1094
|
-
setup do
|
1095
|
-
@c = Class.new(Sequel::Dataset) do
|
1096
|
-
def self.sql
|
1097
|
-
@@sql
|
1098
|
-
end
|
1099
|
-
|
1100
|
-
def fetch_rows(sql)
|
1101
|
-
@@sql = sql
|
1102
|
-
yield({1 => 1})
|
1103
|
-
end
|
1104
|
-
end
|
1105
|
-
@dataset = @c.new(nil).from(:test)
|
1106
|
-
end
|
1107
|
-
|
1108
|
-
specify "should format SQL properly" do
|
1109
|
-
@dataset.count.should == 1
|
1110
|
-
@c.sql.should == 'SELECT COUNT(*) FROM test LIMIT 1'
|
1111
|
-
end
|
1112
|
-
|
1113
|
-
specify "should be aliased by #size" do
|
1114
|
-
@dataset.size.should == 1
|
1115
|
-
end
|
1116
|
-
|
1117
|
-
specify "should include the where clause if it's there" do
|
1118
|
-
@dataset.filter(:abc < 30).count.should == 1
|
1119
|
-
@c.sql.should == 'SELECT COUNT(*) FROM test WHERE (abc < 30) LIMIT 1'
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
specify "should count properly for datasets with fixed sql" do
|
1123
|
-
@dataset.opts[:sql] = "select abc from xyz"
|
1124
|
-
@dataset.count.should == 1
|
1125
|
-
@c.sql.should == "SELECT COUNT(*) FROM (select abc from xyz) t1 LIMIT 1"
|
1126
|
-
end
|
1127
|
-
|
1128
|
-
specify "should return limit if count is greater than it" do
|
1129
|
-
@dataset.limit(5).count.should == 1
|
1130
|
-
@c.sql.should == "SELECT COUNT(*) FROM (SELECT * FROM test LIMIT 5) t1 LIMIT 1"
|
1131
|
-
end
|
1132
|
-
end
|
1133
|
-
|
1134
|
-
|
1135
|
-
context "Dataset#group_and_count" do
|
1136
|
-
setup do
|
1137
|
-
@c = Class.new(Sequel::Dataset) do
|
1138
|
-
def self.sql
|
1139
|
-
@@sql
|
1140
|
-
end
|
1141
|
-
|
1142
|
-
def fetch_rows(sql)
|
1143
|
-
@@sql = sql
|
1144
|
-
yield({1 => 1})
|
1145
|
-
end
|
1146
|
-
end
|
1147
|
-
@ds = @c.new(nil).from(:test)
|
1148
|
-
end
|
1149
|
-
|
1150
|
-
specify "should format SQL properly" do
|
1151
|
-
@ds.group_and_count(:name).sql.should ==
|
1152
|
-
"SELECT name, count(*) AS count FROM test GROUP BY name ORDER BY count"
|
1153
|
-
end
|
1154
|
-
|
1155
|
-
specify "should accept multiple columns for grouping" do
|
1156
|
-
@ds.group_and_count(:a, :b).sql.should ==
|
1157
|
-
"SELECT a, b, count(*) AS count FROM test GROUP BY a, b ORDER BY count"
|
1158
|
-
end
|
1159
|
-
|
1160
|
-
specify "should work within query block" do
|
1161
|
-
@ds.query{group_and_count(:a, :b)}.sql.should ==
|
1162
|
-
"SELECT a, b, count(*) AS count FROM test GROUP BY a, b ORDER BY count"
|
1163
|
-
end
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
context "Dataset#empty?" do
|
1167
|
-
specify "should return true if records exist in the dataset" do
|
1168
|
-
@db = Sequel::Database.new
|
1169
|
-
@db.meta_def(:execute) {|sql| @sqls ||=[]; @sqls << sql}
|
1170
|
-
@db.meta_def(:sqls) {@sqls ||= []}
|
1171
|
-
|
1172
|
-
$cccc = Class.new(Sequel::Dataset) do
|
1173
|
-
def fetch_rows(sql)
|
1174
|
-
@db.execute(sql)
|
1175
|
-
yield(:x => 'blah')
|
1176
|
-
end
|
1177
|
-
end
|
1178
|
-
|
1179
|
-
@db.meta_def(:dataset) do
|
1180
|
-
$cccc.new(self)
|
1181
|
-
end
|
1182
|
-
|
1183
|
-
@dataset = Sequel::Dataset.new(@db).from(:test)
|
1184
|
-
|
1185
|
-
@dataset.should_not be_empty
|
1186
|
-
@db.sqls.last.should == 'SELECT 1 WHERE (EXISTS (SELECT * FROM test)) LIMIT 1'
|
1187
|
-
|
1188
|
-
@db.meta_def(:dataset) do
|
1189
|
-
ds = $cccc.new(self)
|
1190
|
-
ds.meta_def(:get) {|c| nil}
|
1191
|
-
ds
|
1192
|
-
end
|
1193
|
-
|
1194
|
-
@dataset.should be_empty
|
1195
|
-
end
|
1196
|
-
end
|
1197
|
-
|
1198
|
-
context "Dataset#join_table" do
|
1199
|
-
setup do
|
1200
|
-
@d = MockDataset.new(nil).from(:items)
|
1201
|
-
@d.quote_identifiers = true
|
1202
|
-
end
|
1203
|
-
|
1204
|
-
specify "should format the JOIN clause properly" do
|
1205
|
-
@d.join_table(:left_outer, :categories, :category_id => :id).sql.should ==
|
1206
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1207
|
-
end
|
1208
|
-
|
1209
|
-
specify "should handle multiple conditions on the same join table column" do
|
1210
|
-
@d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
|
1211
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND (("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100)))'
|
1212
|
-
end
|
1213
|
-
|
1214
|
-
specify "should include WHERE clause if applicable" do
|
1215
|
-
@d.filter(:price < 100).join_table(:right_outer, :categories, :category_id => :id).sql.should ==
|
1216
|
-
'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") WHERE ("price" < 100)'
|
1217
|
-
end
|
1218
|
-
|
1219
|
-
specify "should include ORDER BY clause if applicable" do
|
1220
|
-
@d.order(:stamp).join_table(:full_outer, :categories, :category_id => :id).sql.should ==
|
1221
|
-
'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") ORDER BY "stamp"'
|
1222
|
-
end
|
1223
|
-
|
1224
|
-
specify "should support multiple joins" do
|
1225
|
-
@d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.should ==
|
1226
|
-
'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
|
1227
|
-
end
|
1228
|
-
|
1229
|
-
specify "should support left outer joins" do
|
1230
|
-
@d.join_table(:left_outer, :categories, :category_id=>:id).sql.should ==
|
1231
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1232
|
-
|
1233
|
-
@d.left_outer_join(:categories, :category_id=>:id).sql.should ==
|
1234
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1235
|
-
end
|
1236
|
-
|
1237
|
-
specify "should support right outer joins" do
|
1238
|
-
@d.join_table(:right_outer, :categories, :category_id=>:id).sql.should ==
|
1239
|
-
'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1240
|
-
|
1241
|
-
@d.right_outer_join(:categories, :category_id=>:id).sql.should ==
|
1242
|
-
'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1243
|
-
end
|
1244
|
-
|
1245
|
-
specify "should support full outer joins" do
|
1246
|
-
@d.join_table(:full_outer, :categories, :category_id=>:id).sql.should ==
|
1247
|
-
'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1248
|
-
|
1249
|
-
@d.full_outer_join(:categories, :category_id=>:id).sql.should ==
|
1250
|
-
'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1251
|
-
end
|
1252
|
-
|
1253
|
-
specify "should support inner joins" do
|
1254
|
-
@d.join_table(:inner, :categories, :category_id=>:id).sql.should ==
|
1255
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1256
|
-
|
1257
|
-
@d.inner_join(:categories, :category_id=>:id).sql.should ==
|
1258
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1259
|
-
end
|
1260
|
-
|
1261
|
-
specify "should default to a plain join if nil is used for the type" do
|
1262
|
-
@d.join_table(nil, :categories, :category_id=>:id).sql.should ==
|
1263
|
-
'SELECT * FROM "items" JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1264
|
-
end
|
1265
|
-
|
1266
|
-
specify "should use an inner join for Dataset#join" do
|
1267
|
-
@d.join(:categories, :category_id=>:id).sql.should ==
|
1268
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
|
1269
|
-
end
|
1270
|
-
|
1271
|
-
specify "should support aliased tables" do
|
1272
|
-
@d.from('stats').join('players', {:id => :player_id}, 'p').sql.should ==
|
1273
|
-
'SELECT * FROM "stats" INNER JOIN "players" AS "p" ON ("p"."id" = "stats"."player_id")'
|
1274
|
-
|
1275
|
-
ds = MockDataset.new(nil).from(:foo => :f)
|
1276
|
-
ds.quote_identifiers = true
|
1277
|
-
ds.join_table(:inner, :bar, :id => :bar_id).sql.should ==
|
1278
|
-
'SELECT * FROM "foo" "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
1279
|
-
end
|
1280
|
-
|
1281
|
-
specify "should allow for arbitrary conditions in the JOIN clause" do
|
1282
|
-
@d.join_table(:left_outer, :categories, :status => 0).sql.should ==
|
1283
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
1284
|
-
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should ==
|
1285
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
1286
|
-
@d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should ==
|
1287
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
|
1288
|
-
@d.join_table(:left_outer, :categories, :status => [1, 2, 3]).sql.should ==
|
1289
|
-
'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" IN (1, 2, 3))'
|
1290
|
-
end
|
1291
|
-
|
1292
|
-
specify "should raise error for a table without a source" do
|
1293
|
-
proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}. \
|
1294
|
-
should raise_error(Sequel::Error)
|
1295
|
-
end
|
1296
|
-
|
1297
|
-
specify "should support joining datasets" do
|
1298
|
-
ds = Sequel::Dataset.new(nil).from(:categories)
|
1299
|
-
|
1300
|
-
@d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
|
1301
|
-
'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id")'
|
1302
|
-
|
1303
|
-
ds.filter!(:active => true)
|
1304
|
-
|
1305
|
-
@d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
|
1306
|
-
'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active = \'t\')) AS "t1" ON ("t1"."item_id" = "items"."id")'
|
1307
|
-
end
|
1308
|
-
|
1309
|
-
specify "should support joining datasets and aliasing the join" do
|
1310
|
-
ds = Sequel::Dataset.new(nil).from(:categories)
|
1311
|
-
|
1312
|
-
@d.join_table(:left_outer, ds, {:ds__item_id => :id}, :ds).sql.should ==
|
1313
|
-
'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
|
1314
|
-
end
|
1315
|
-
|
1316
|
-
specify "should support joining multiple datasets" do
|
1317
|
-
ds = Sequel::Dataset.new(nil).from(:categories)
|
1318
|
-
ds2 = Sequel::Dataset.new(nil).from(:nodes).select(:name)
|
1319
|
-
ds3 = Sequel::Dataset.new(nil).from(:attributes).filter("name = 'blah'")
|
1320
|
-
|
1321
|
-
@d.join_table(:left_outer, ds, :item_id => :id).join_table(:inner, ds2, :node_id=>:id).join_table(:right_outer, ds3, :attribute_id=>:id).sql.should ==
|
1322
|
-
'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id") ' \
|
1323
|
-
'INNER JOIN (SELECT name FROM nodes) AS "t2" ON ("t2"."node_id" = "t1"."id") ' \
|
1324
|
-
'RIGHT OUTER JOIN (SELECT * FROM attributes WHERE (name = \'blah\')) AS "t3" ON ("t3"."attribute_id" = "t2"."id")'
|
1325
|
-
end
|
1326
|
-
|
1327
|
-
specify "should support joining objects that respond to :table_name" do
|
1328
|
-
ds = Object.new
|
1329
|
-
def ds.table_name; :categories end
|
1330
|
-
|
1331
|
-
@d.join(ds, :item_id => :id).sql.should ==
|
1332
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
|
1333
|
-
end
|
1334
|
-
|
1335
|
-
specify "should support using a SQL String as the join condition" do
|
1336
|
-
@d.join(:categories, %{c.item_id = items.id}, :c).sql.should ==
|
1337
|
-
'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
1338
|
-
end
|
1339
|
-
|
1340
|
-
specify "should support using a boolean column as the join condition" do
|
1341
|
-
@d.join(:categories, :active).sql.should ==
|
1342
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
1343
|
-
end
|
1344
|
-
|
1345
|
-
specify "should support using an expression as the join condition" do
|
1346
|
-
@d.join(:categories, :number > 10).sql.should ==
|
1347
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("number" > 10)'
|
1348
|
-
end
|
1349
|
-
|
1350
|
-
specify "should support natural and cross joins using nil" do
|
1351
|
-
@d.join_table(:natural, :categories).sql.should ==
|
1352
|
-
'SELECT * FROM "items" NATURAL JOIN "categories"'
|
1353
|
-
@d.join_table(:cross, :categories, nil).sql.should ==
|
1354
|
-
'SELECT * FROM "items" CROSS JOIN "categories"'
|
1355
|
-
@d.join_table(:natural, :categories, nil, :c).sql.should ==
|
1356
|
-
'SELECT * FROM "items" NATURAL JOIN "categories" AS "c"'
|
1357
|
-
end
|
1358
|
-
|
1359
|
-
specify "should support joins with a USING clause if an array of symbols is used" do
|
1360
|
-
@d.join(:categories, [:id]).sql.should ==
|
1361
|
-
'SELECT * FROM "items" INNER JOIN "categories" USING ("id")'
|
1362
|
-
@d.join(:categories, [:id1, :id2]).sql.should ==
|
1363
|
-
'SELECT * FROM "items" INNER JOIN "categories" USING ("id1", "id2")'
|
1364
|
-
end
|
1365
|
-
|
1366
|
-
specify "should raise an error if using an array of symbols with a block" do
|
1367
|
-
proc{@d.join(:categories, [:id]){|j,lj,js|}}.should raise_error(Sequel::Error)
|
1368
|
-
end
|
1369
|
-
|
1370
|
-
specify "should support using a block that receieves the join table/alias, last join table/alias, and array of previous joins" do
|
1371
|
-
@d.join(:categories) do |join_alias, last_join_alias, joins|
|
1372
|
-
join_alias.should == :categories
|
1373
|
-
last_join_alias.should == :items
|
1374
|
-
joins.should == []
|
1375
|
-
end
|
1376
|
-
|
1377
|
-
@d.from(:items=>:i).join(:categories, nil, :c) do |join_alias, last_join_alias, joins|
|
1378
|
-
join_alias.should == :c
|
1379
|
-
last_join_alias.should == :i
|
1380
|
-
joins.should == []
|
1381
|
-
end
|
1382
|
-
|
1383
|
-
@d.from(:items___i).join(:categories, nil, :c) do |join_alias, last_join_alias, joins|
|
1384
|
-
join_alias.should == :c
|
1385
|
-
last_join_alias.should == :i
|
1386
|
-
joins.should == []
|
1387
|
-
end
|
1388
|
-
|
1389
|
-
@d.join(:blah).join(:categories, nil, :c) do |join_alias, last_join_alias, joins|
|
1390
|
-
join_alias.should == :c
|
1391
|
-
last_join_alias.should == :blah
|
1392
|
-
joins.should be_a_kind_of(Array)
|
1393
|
-
joins.length.should == 1
|
1394
|
-
joins.first.should be_a_kind_of(Sequel::SQL::JoinClause)
|
1395
|
-
joins.first.join_type.should == :inner
|
1396
|
-
end
|
1397
|
-
|
1398
|
-
@d.join_table(:natural, :blah, nil, :b).join(:categories, nil, :c) do |join_alias, last_join_alias, joins|
|
1399
|
-
join_alias.should == :c
|
1400
|
-
last_join_alias.should == :b
|
1401
|
-
joins.should be_a_kind_of(Array)
|
1402
|
-
joins.length.should == 1
|
1403
|
-
joins.first.should be_a_kind_of(Sequel::SQL::JoinClause)
|
1404
|
-
joins.first.join_type.should == :natural
|
1405
|
-
end
|
1406
|
-
|
1407
|
-
@d.join(:blah).join(:categories).join(:blah2) do |join_alias, last_join_alias, joins|
|
1408
|
-
join_alias.should == :blah2
|
1409
|
-
last_join_alias.should == :categories
|
1410
|
-
joins.should be_a_kind_of(Array)
|
1411
|
-
joins.length.should == 2
|
1412
|
-
joins.first.should be_a_kind_of(Sequel::SQL::JoinClause)
|
1413
|
-
joins.first.table.should == :blah
|
1414
|
-
joins.last.should be_a_kind_of(Sequel::SQL::JoinClause)
|
1415
|
-
joins.last.table.should == :categories
|
1416
|
-
end
|
1417
|
-
end
|
1418
|
-
|
1419
|
-
specify "should use the block result as the only condition if no condition is given" do
|
1420
|
-
@d.join(:categories){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should ==
|
1421
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" = "items"."c")'
|
1422
|
-
@d.join(:categories){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should ==
|
1423
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."b" > "items"."c")'
|
1424
|
-
end
|
1425
|
-
|
1426
|
-
specify "should combine the block conditions and argument conditions if both given" do
|
1427
|
-
@d.join(:categories, :a=>:d){|j,lj,js| {:b.qualify(j)=>:c.qualify(lj)}}.sql.should ==
|
1428
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" = "items"."c"))'
|
1429
|
-
@d.join(:categories, :a=>:d){|j,lj,js| :b.qualify(j) > :c.qualify(lj)}.sql.should ==
|
1430
|
-
'SELECT * FROM "items" INNER JOIN "categories" ON (("categories"."a" = "items"."d") AND ("categories"."b" > "items"."c"))'
|
1431
|
-
end
|
1432
|
-
end
|
1433
|
-
|
1434
|
-
context "Dataset#[]=" do
|
1435
|
-
setup do
|
1436
|
-
c = Class.new(Sequel::Dataset) do
|
1437
|
-
def last_sql
|
1438
|
-
@@last_sql
|
1439
|
-
end
|
1440
|
-
|
1441
|
-
def update(*args)
|
1442
|
-
@@last_sql = update_sql(*args)
|
1443
|
-
end
|
1444
|
-
end
|
1445
|
-
|
1446
|
-
@d = c.new(nil).from(:items)
|
1447
|
-
end
|
1448
|
-
|
1449
|
-
specify "should perform an update on the specified filter" do
|
1450
|
-
@d[:a => 1] = {:x => 3}
|
1451
|
-
@d.last_sql.should == 'UPDATE items SET x = 3 WHERE (a = 1)'
|
1452
|
-
end
|
1453
|
-
end
|
1454
|
-
|
1455
|
-
context "Dataset#set" do
|
1456
|
-
setup do
|
1457
|
-
c = Class.new(Sequel::Dataset) do
|
1458
|
-
def last_sql
|
1459
|
-
@@last_sql
|
1460
|
-
end
|
1461
|
-
|
1462
|
-
def update(*args, &block)
|
1463
|
-
@@last_sql = update_sql(*args, &block)
|
1464
|
-
end
|
1465
|
-
end
|
1466
|
-
|
1467
|
-
@d = c.new(nil).from(:items)
|
1468
|
-
end
|
1469
|
-
|
1470
|
-
specify "should act as alias to #update" do
|
1471
|
-
@d.set({:x => 3})
|
1472
|
-
@d.last_sql.should == 'UPDATE items SET x = 3'
|
1473
|
-
end
|
1474
|
-
end
|
1475
|
-
|
1476
|
-
|
1477
|
-
context "Dataset#insert_multiple" do
|
1478
|
-
setup do
|
1479
|
-
c = Class.new(Sequel::Dataset) do
|
1480
|
-
attr_reader :inserts
|
1481
|
-
def insert(arg)
|
1482
|
-
@inserts ||= []
|
1483
|
-
@inserts << arg
|
1484
|
-
end
|
1485
|
-
end
|
1486
|
-
|
1487
|
-
@d = c.new(nil)
|
1488
|
-
end
|
1489
|
-
|
1490
|
-
specify "should insert all items in the supplied array" do
|
1491
|
-
@d.insert_multiple [:aa, 5, 3, {1 => 2}]
|
1492
|
-
@d.inserts.should == [:aa, 5, 3, {1 => 2}]
|
1493
|
-
end
|
1494
|
-
|
1495
|
-
specify "should pass array items through the supplied block if given" do
|
1496
|
-
a = ["inevitable", "hello", "the ticking clock"]
|
1497
|
-
@d.insert_multiple(a) {|i| i.gsub('l', 'r')}
|
1498
|
-
@d.inserts.should == ["inevitabre", "herro", "the ticking crock"]
|
1499
|
-
end
|
1500
|
-
end
|
1501
|
-
|
1502
|
-
context "Dataset aggregate methods" do
|
1503
|
-
setup do
|
1504
|
-
c = Class.new(Sequel::Dataset) do
|
1505
|
-
def fetch_rows(sql)
|
1506
|
-
yield({1 => sql})
|
1507
|
-
end
|
1508
|
-
end
|
1509
|
-
@d = c.new(nil).from(:test)
|
1510
|
-
end
|
1511
|
-
|
1512
|
-
specify "should include min" do
|
1513
|
-
@d.min(:a).should == 'SELECT min(a) FROM test LIMIT 1'
|
1514
|
-
end
|
1515
|
-
|
1516
|
-
specify "should include max" do
|
1517
|
-
@d.max(:b).should == 'SELECT max(b) FROM test LIMIT 1'
|
1518
|
-
end
|
1519
|
-
|
1520
|
-
specify "should include sum" do
|
1521
|
-
@d.sum(:c).should == 'SELECT sum(c) FROM test LIMIT 1'
|
1522
|
-
end
|
1523
|
-
|
1524
|
-
specify "should include avg" do
|
1525
|
-
@d.avg(:d).should == 'SELECT avg(d) FROM test LIMIT 1'
|
1526
|
-
end
|
1527
|
-
|
1528
|
-
specify "should accept qualified columns" do
|
1529
|
-
@d.avg(:test__bc).should == 'SELECT avg(test.bc) FROM test LIMIT 1'
|
1530
|
-
end
|
1531
|
-
end
|
1532
|
-
|
1533
|
-
context "Dataset#range" do
|
1534
|
-
setup do
|
1535
|
-
c = Class.new(Sequel::Dataset) do
|
1536
|
-
@@sql = nil
|
1537
|
-
|
1538
|
-
def last_sql; @@sql; end
|
1539
|
-
|
1540
|
-
def fetch_rows(sql)
|
1541
|
-
@@sql = sql
|
1542
|
-
yield(:v1 => 1, :v2 => 10)
|
1543
|
-
end
|
1544
|
-
end
|
1545
|
-
@d = c.new(nil).from(:test)
|
1546
|
-
end
|
1547
|
-
|
1548
|
-
specify "should generate a correct SQL statement" do
|
1549
|
-
@d.range(:stamp)
|
1550
|
-
@d.last_sql.should == "SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"
|
1551
|
-
|
1552
|
-
@d.filter(:price > 100).range(:stamp)
|
1553
|
-
@d.last_sql.should == "SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"
|
1554
|
-
end
|
1555
|
-
|
1556
|
-
specify "should return a range object" do
|
1557
|
-
@d.range(:tryme).should == (1..10)
|
1558
|
-
end
|
1559
|
-
end
|
1560
|
-
|
1561
|
-
context "Dataset#interval" do
|
1562
|
-
setup do
|
1563
|
-
c = Class.new(Sequel::Dataset) do
|
1564
|
-
@@sql = nil
|
1565
|
-
|
1566
|
-
def last_sql; @@sql; end
|
1567
|
-
|
1568
|
-
def fetch_rows(sql)
|
1569
|
-
@@sql = sql
|
1570
|
-
yield(:v => 1234)
|
1571
|
-
end
|
1572
|
-
end
|
1573
|
-
@d = c.new(nil).from(:test)
|
1574
|
-
end
|
1575
|
-
|
1576
|
-
specify "should generate a correct SQL statement" do
|
1577
|
-
@d.interval(:stamp)
|
1578
|
-
@d.last_sql.should == "SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"
|
1579
|
-
|
1580
|
-
@d.filter(:price > 100).interval(:stamp)
|
1581
|
-
@d.last_sql.should == "SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"
|
1582
|
-
end
|
1583
|
-
|
1584
|
-
specify "should return an integer" do
|
1585
|
-
@d.interval(:tryme).should == 1234
|
1586
|
-
end
|
1587
|
-
end
|
1588
|
-
|
1589
|
-
context "Dataset #first and #last" do
|
1590
|
-
setup do
|
1591
|
-
@c = Class.new(Sequel::Dataset) do
|
1592
|
-
def each(opts = nil, &block)
|
1593
|
-
s = select_sql(opts)
|
1594
|
-
x = [:a,1,:b,2,s]
|
1595
|
-
i = /LIMIT (\d+)/.match(s)[1].to_i.times{yield x}
|
1596
|
-
end
|
1597
|
-
end
|
1598
|
-
@d = @c.new(nil).from(:test)
|
1599
|
-
end
|
1600
|
-
|
1601
|
-
specify "should return a single record if no argument is given" do
|
1602
|
-
@d.order(:a).first.should == [:a,1,:b,2, 'SELECT * FROM test ORDER BY a LIMIT 1']
|
1603
|
-
@d.order(:a).last.should == [:a,1,:b,2, 'SELECT * FROM test ORDER BY a DESC LIMIT 1']
|
1604
|
-
end
|
1605
|
-
|
1606
|
-
specify "should return the first/last matching record if argument is not an Integer" do
|
1607
|
-
@d.order(:a).first(:z => 26).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1']
|
1608
|
-
@d.order(:a).first('z = ?', 15).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1']
|
1609
|
-
@d.order(:a).last(:z => 26).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1']
|
1610
|
-
@d.order(:a).last('z = ?', 15).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1']
|
1611
|
-
end
|
1612
|
-
|
1613
|
-
specify "should set the limit and return an array of records if the given number is > 1" do
|
1614
|
-
i = rand(10) + 10
|
1615
|
-
r = @d.order(:a).first(i).should == [[:a,1,:b,2, "SELECT * FROM test ORDER BY a LIMIT #{i}"]] * i
|
1616
|
-
i = rand(10) + 10
|
1617
|
-
r = @d.order(:a).last(i).should == [[:a,1,:b,2, "SELECT * FROM test ORDER BY a DESC LIMIT #{i}"]] * i
|
1618
|
-
end
|
1619
|
-
|
1620
|
-
specify "should return the first matching record if a block is given without an argument" do
|
1621
|
-
@d.first{:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) LIMIT 1']
|
1622
|
-
@d.order(:name).last{:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1']
|
1623
|
-
end
|
1624
|
-
|
1625
|
-
specify "should combine block and standard argument filters if argument is not an Integer" do
|
1626
|
-
@d.first(:y=>25){:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1']
|
1627
|
-
@d.order(:name).last('y = ?', 16){:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE ((z > 26) AND (y = 16)) ORDER BY name DESC LIMIT 1']
|
1628
|
-
end
|
1629
|
-
|
1630
|
-
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
1631
|
-
i = rand(10) + 10
|
1632
|
-
r = @d.order(:a).first(i){:z > 26}.should == [[:a,1,:b,2, "SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"]] * i
|
1633
|
-
i = rand(10) + 10
|
1634
|
-
r = @d.order(:a).last(i){:z > 26}.should == [[:a,1,:b,2, "SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"]] * i
|
1635
|
-
end
|
1636
|
-
|
1637
|
-
specify "#last should raise if no order is given" do
|
1638
|
-
proc {@d.last}.should raise_error(Sequel::Error)
|
1639
|
-
proc {@d.last(2)}.should raise_error(Sequel::Error)
|
1640
|
-
proc {@d.order(:a).last}.should_not raise_error
|
1641
|
-
proc {@d.order(:a).last(2)}.should_not raise_error
|
1642
|
-
end
|
1643
|
-
|
1644
|
-
specify "#last should invert the order" do
|
1645
|
-
@d.order(:a).last.pop.should == 'SELECT * FROM test ORDER BY a DESC LIMIT 1'
|
1646
|
-
@d.order(:b.desc).last.pop.should == 'SELECT * FROM test ORDER BY b ASC LIMIT 1'
|
1647
|
-
@d.order(:c, :d).last.pop.should == 'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'
|
1648
|
-
@d.order(:e.desc, :f).last.pop.should == 'SELECT * FROM test ORDER BY e ASC, f DESC LIMIT 1'
|
1649
|
-
end
|
1650
|
-
end
|
1651
|
-
|
1652
|
-
context "Dataset set operations" do
|
1653
|
-
setup do
|
1654
|
-
@a = Sequel::Dataset.new(nil).from(:a).filter(:z => 1)
|
1655
|
-
@b = Sequel::Dataset.new(nil).from(:b).filter(:z => 2)
|
1656
|
-
end
|
1657
|
-
|
1658
|
-
specify "should support UNION and UNION ALL" do
|
1659
|
-
@a.union(@b).sql.should == \
|
1660
|
-
"SELECT * FROM a WHERE (z = 1) UNION SELECT * FROM b WHERE (z = 2)"
|
1661
|
-
@b.union(@a, true).sql.should == \
|
1662
|
-
"SELECT * FROM b WHERE (z = 2) UNION ALL SELECT * FROM a WHERE (z = 1)"
|
1663
|
-
end
|
1664
|
-
|
1665
|
-
specify "should support INTERSECT and INTERSECT ALL" do
|
1666
|
-
@a.intersect(@b).sql.should == \
|
1667
|
-
"SELECT * FROM a WHERE (z = 1) INTERSECT SELECT * FROM b WHERE (z = 2)"
|
1668
|
-
@b.intersect(@a, true).sql.should == \
|
1669
|
-
"SELECT * FROM b WHERE (z = 2) INTERSECT ALL SELECT * FROM a WHERE (z = 1)"
|
1670
|
-
end
|
1671
|
-
|
1672
|
-
specify "should support EXCEPT and EXCEPT ALL" do
|
1673
|
-
@a.except(@b).sql.should == \
|
1674
|
-
"SELECT * FROM a WHERE (z = 1) EXCEPT SELECT * FROM b WHERE (z = 2)"
|
1675
|
-
@b.except(@a, true).sql.should == \
|
1676
|
-
"SELECT * FROM b WHERE (z = 2) EXCEPT ALL SELECT * FROM a WHERE (z = 1)"
|
1677
|
-
end
|
1678
|
-
end
|
1679
|
-
|
1680
|
-
context "Dataset#[]" do
|
1681
|
-
setup do
|
1682
|
-
@c = Class.new(Sequel::Dataset) do
|
1683
|
-
@@last_dataset = nil
|
1684
|
-
|
1685
|
-
def self.last_dataset
|
1686
|
-
@@last_dataset
|
1687
|
-
end
|
1688
|
-
|
1689
|
-
def single_record(opts = nil)
|
1690
|
-
@@last_dataset = opts ? clone(opts) : self
|
1691
|
-
{1 => 2, 3 => 4}
|
1692
|
-
end
|
1693
|
-
end
|
1694
|
-
@d = @c.new(nil).from(:test)
|
1695
|
-
end
|
1696
|
-
|
1697
|
-
specify "should return a single record filtered according to the given conditions" do
|
1698
|
-
@d[:name => 'didi'].should == {1 => 2, 3 => 4}
|
1699
|
-
@c.last_dataset.literal(@c.last_dataset.opts[:where]).should == "(name = 'didi')"
|
1700
|
-
|
1701
|
-
@d[:id => 5..45].should == {1 => 2, 3 => 4}
|
1702
|
-
@c.last_dataset.literal(@c.last_dataset.opts[:where]).should == "((id >= 5) AND (id <= 45))"
|
1703
|
-
end
|
1704
|
-
end
|
1705
|
-
|
1706
|
-
context "Dataset#single_record" do
|
1707
|
-
setup do
|
1708
|
-
@c = Class.new(Sequel::Dataset) do
|
1709
|
-
def fetch_rows(sql)
|
1710
|
-
yield sql
|
1711
|
-
end
|
1712
|
-
end
|
1713
|
-
@cc = Class.new(@c) do
|
1714
|
-
def fetch_rows(sql); end
|
1715
|
-
end
|
1716
|
-
|
1717
|
-
@d = @c.new(nil).from(:test)
|
1718
|
-
@e = @cc.new(nil).from(:test)
|
1719
|
-
end
|
1720
|
-
|
1721
|
-
specify "should call each with a limit of 1 and return the record" do
|
1722
|
-
@d.single_record.should == 'SELECT * FROM test LIMIT 1'
|
1723
|
-
end
|
1724
|
-
|
1725
|
-
specify "should pass opts to each" do
|
1726
|
-
@d.single_record(:order => [:name]).should == 'SELECT * FROM test ORDER BY name LIMIT 1'
|
1727
|
-
end
|
1728
|
-
|
1729
|
-
specify "should override the limit if passed as an option" do
|
1730
|
-
@d.single_record(:limit => 3).should == 'SELECT * FROM test LIMIT 1'
|
1731
|
-
end
|
1732
|
-
|
1733
|
-
specify "should return nil if no record is present" do
|
1734
|
-
@e.single_record.should be_nil
|
1735
|
-
end
|
1736
|
-
end
|
1737
|
-
|
1738
|
-
context "Dataset#single_value" do
|
1739
|
-
setup do
|
1740
|
-
@c = Class.new(Sequel::Dataset) do
|
1741
|
-
def fetch_rows(sql)
|
1742
|
-
yield({1 => sql})
|
1743
|
-
end
|
1744
|
-
end
|
1745
|
-
@cc = Class.new(@c) do
|
1746
|
-
def fetch_rows(sql); end
|
1747
|
-
end
|
1748
|
-
|
1749
|
-
@d = @c.new(nil).from(:test)
|
1750
|
-
@e = @cc.new(nil).from(:test)
|
1751
|
-
end
|
1752
|
-
|
1753
|
-
specify "should call each and return the first value of the first record" do
|
1754
|
-
@d.single_value.should == 'SELECT * FROM test LIMIT 1'
|
1755
|
-
end
|
1756
|
-
|
1757
|
-
specify "should pass opts to each" do
|
1758
|
-
@d.single_value(:from => [:blah]).should == 'SELECT * FROM blah LIMIT 1'
|
1759
|
-
end
|
1760
|
-
|
1761
|
-
specify "should return nil if no records" do
|
1762
|
-
@e.single_value.should be_nil
|
1763
|
-
end
|
1764
|
-
end
|
1765
|
-
|
1766
|
-
context "Dataset#get" do
|
1767
|
-
setup do
|
1768
|
-
@c = Class.new(Sequel::Dataset) do
|
1769
|
-
attr_reader :last_sql
|
1770
|
-
|
1771
|
-
def fetch_rows(sql)
|
1772
|
-
@last_sql = sql
|
1773
|
-
yield(:name => sql)
|
1774
|
-
end
|
1775
|
-
end
|
1776
|
-
|
1777
|
-
@d = @c.new(nil).from(:test)
|
1778
|
-
end
|
1779
|
-
|
1780
|
-
specify "should select the specified column and fetch its value" do
|
1781
|
-
@d.get(:name).should == "SELECT name FROM test LIMIT 1"
|
1782
|
-
@d.get(:abc).should == "SELECT abc FROM test LIMIT 1" # the first available value is returned always
|
1783
|
-
end
|
1784
|
-
|
1785
|
-
specify "should work with filters" do
|
1786
|
-
@d.filter(:id => 1).get(:name).should == "SELECT name FROM test WHERE (id = 1) LIMIT 1"
|
1787
|
-
end
|
1788
|
-
|
1789
|
-
specify "should work with aliased fields" do
|
1790
|
-
@d.get(:x__b.as(:name)).should == "SELECT x.b AS name FROM test LIMIT 1"
|
1791
|
-
end
|
1792
|
-
end
|
1793
|
-
|
1794
|
-
context "Dataset#set_row_proc" do
|
1795
|
-
setup do
|
1796
|
-
@c = Class.new(Sequel::Dataset) do
|
1797
|
-
def fetch_rows(sql, &block)
|
1798
|
-
# yield a hash with kind as the 1 bit of a number
|
1799
|
-
(1..10).each {|i| block.call({:kind => i[0]})}
|
1800
|
-
end
|
1801
|
-
end
|
1802
|
-
@dataset = @c.new(nil).from(:items)
|
1803
|
-
end
|
1804
|
-
|
1805
|
-
specify "should cause dataset to pass all rows through the filter" do
|
1806
|
-
@dataset.row_proc = proc{|h| h[:der] = h[:kind] + 2; h}
|
1807
|
-
|
1808
|
-
rows = @dataset.all
|
1809
|
-
rows.size.should == 10
|
1810
|
-
|
1811
|
-
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
1812
|
-
end
|
1813
|
-
|
1814
|
-
specify "should be copied over when dataset is cloned" do
|
1815
|
-
@dataset.row_proc = proc{|h| h[:der] = h[:kind] + 2; h}
|
1816
|
-
|
1817
|
-
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
1818
|
-
end
|
1819
|
-
end
|
1820
|
-
|
1821
|
-
context "Dataset#set_model" do
|
1822
|
-
setup do
|
1823
|
-
@c = Class.new(Sequel::Dataset) do
|
1824
|
-
def fetch_rows(sql, &block)
|
1825
|
-
# yield a hash with kind as the 1 bit of a number
|
1826
|
-
(1..10).each {|i| block.call({:kind => i[0]})}
|
1827
|
-
end
|
1828
|
-
end
|
1829
|
-
@dataset = @c.new(nil).from(:items)
|
1830
|
-
@m = Class.new do
|
1831
|
-
attr_accessor :c, :args
|
1832
|
-
def initialize(c, *args); @c = c; @args = args; end
|
1833
|
-
def ==(o); (@c == o.c) && (@args = o.args); end
|
1834
|
-
end
|
1835
|
-
end
|
1836
|
-
|
1837
|
-
specify "should clear the models hash and restore the stock #each if nil is specified" do
|
1838
|
-
@dataset.set_model(@m)
|
1839
|
-
@dataset.set_model(nil)
|
1840
|
-
@dataset.first.should == {:kind => 1}
|
1841
|
-
@dataset.model_classes.should be_nil
|
1842
|
-
end
|
1843
|
-
|
1844
|
-
specify "should clear the models hash and restore the stock #each if nothing is specified" do
|
1845
|
-
@dataset.set_model(@m)
|
1846
|
-
@dataset.set_model(nil)
|
1847
|
-
@dataset.first.should == {:kind => 1}
|
1848
|
-
@dataset.model_classes.should be_nil
|
1849
|
-
end
|
1850
|
-
|
1851
|
-
specify "should alter #each to provide model instances" do
|
1852
|
-
@dataset.first.should == {:kind => 1}
|
1853
|
-
@dataset.set_model(@m)
|
1854
|
-
@dataset.first.should == @m.new({:kind => 1})
|
1855
|
-
end
|
1856
|
-
|
1857
|
-
specify "should set opts[:naked] to nil" do
|
1858
|
-
@dataset.opts[:naked] = true
|
1859
|
-
@dataset.set_model(@m)
|
1860
|
-
@dataset.opts[:naked].should be_nil
|
1861
|
-
end
|
1862
|
-
|
1863
|
-
specify "should send additional arguments to the models' initialize method" do
|
1864
|
-
@dataset.set_model(@m, 7, 6, 5)
|
1865
|
-
@dataset.first.should == @m.new({:kind => 1}, 7, 6, 5)
|
1866
|
-
end
|
1867
|
-
|
1868
|
-
specify "should provide support for polymorphic model instantiation" do
|
1869
|
-
@m1 = Class.new(@m)
|
1870
|
-
@m2 = Class.new(@m)
|
1871
|
-
@dataset.set_model(:kind, 0 => @m1, 1 => @m2)
|
1872
|
-
@dataset.opts[:polymorphic_key].should == :kind
|
1873
|
-
all = @dataset.all
|
1874
|
-
all[0].class.should == @m2
|
1875
|
-
all[1].class.should == @m1
|
1876
|
-
all[2].class.should == @m2
|
1877
|
-
all[3].class.should == @m1
|
1878
|
-
#...
|
1879
|
-
|
1880
|
-
# denude model
|
1881
|
-
@dataset.set_model(nil)
|
1882
|
-
@dataset.first.should == {:kind => 1}
|
1883
|
-
end
|
1884
|
-
|
1885
|
-
specify "should send additional arguments for polymorphic models as well" do
|
1886
|
-
@m1 = Class.new(@m)
|
1887
|
-
@m2 = Class.new(@m)
|
1888
|
-
@dataset.set_model(:kind, {0 => @m1, 1 => @m2}, :hey => :wow)
|
1889
|
-
all = @dataset.all
|
1890
|
-
all[0].class.should == @m2; all[0].args.should == [{:hey => :wow}]
|
1891
|
-
all[1].class.should == @m1; all[1].args.should == [{:hey => :wow}]
|
1892
|
-
all[2].class.should == @m2; all[2].args.should == [{:hey => :wow}]
|
1893
|
-
all[3].class.should == @m1; all[3].args.should == [{:hey => :wow}]
|
1894
|
-
end
|
1895
|
-
|
1896
|
-
specify "should raise for invalid parameters" do
|
1897
|
-
proc {@dataset.set_model('kind')}.should raise_error(ArgumentError)
|
1898
|
-
proc {@dataset.set_model(0)}.should raise_error(ArgumentError)
|
1899
|
-
proc {@dataset.set_model(:kind)}.should raise_error(ArgumentError) # no hash given
|
1900
|
-
end
|
1901
|
-
end
|
1902
|
-
|
1903
|
-
context "Dataset#model_classes" do
|
1904
|
-
setup do
|
1905
|
-
@c = Class.new(Sequel::Dataset) do
|
1906
|
-
# # We don't need that for now
|
1907
|
-
# def fetch_rows(sql, &block)
|
1908
|
-
# (1..10).each(&block)
|
1909
|
-
# end
|
1910
|
-
end
|
1911
|
-
@dataset = @c.new(nil).from(:items)
|
1912
|
-
@m = Class.new do
|
1913
|
-
attr_accessor :c
|
1914
|
-
def initialize(c); @c = c; end
|
1915
|
-
def ==(o); @c == o.c; end
|
1916
|
-
end
|
1917
|
-
end
|
1918
|
-
|
1919
|
-
specify "should return nil for a naked dataset" do
|
1920
|
-
@dataset.model_classes.should == nil
|
1921
|
-
end
|
1922
|
-
|
1923
|
-
specify "should return a {nil => model_class} hash for a model dataset" do
|
1924
|
-
@dataset.set_model(@m)
|
1925
|
-
@dataset.model_classes.should == {nil => @m}
|
1926
|
-
end
|
1927
|
-
|
1928
|
-
specify "should return the polymorphic hash for a polymorphic model dataset" do
|
1929
|
-
@m1 = Class.new(@m)
|
1930
|
-
@m2 = Class.new(@m)
|
1931
|
-
@dataset.set_model(:key, 0 => @m1, 1 => @m2)
|
1932
|
-
@dataset.model_classes.should == {0 => @m1, 1 => @m2}
|
1933
|
-
end
|
1934
|
-
end
|
1935
|
-
|
1936
|
-
context "Dataset#polymorphic_key" do
|
1937
|
-
setup do
|
1938
|
-
@c = Class.new(Sequel::Dataset) do
|
1939
|
-
# # We don't need this for now
|
1940
|
-
# def fetch_rows(sql, &block)
|
1941
|
-
# (1..10).each(&block)
|
1942
|
-
# end
|
1943
|
-
end
|
1944
|
-
@dataset = @c.new(nil).from(:items)
|
1945
|
-
@m = Class.new do
|
1946
|
-
attr_accessor :c
|
1947
|
-
def initialize(c); @c = c; end
|
1948
|
-
def ==(o); @c == o.c; end
|
1949
|
-
end
|
1950
|
-
end
|
1951
|
-
|
1952
|
-
specify "should return nil for a naked dataset" do
|
1953
|
-
@dataset.polymorphic_key.should be_nil
|
1954
|
-
end
|
1955
|
-
|
1956
|
-
specify "should return the polymorphic key" do
|
1957
|
-
@dataset.set_model(:id, nil => @m)
|
1958
|
-
@dataset.polymorphic_key.should == :id
|
1959
|
-
end
|
1960
|
-
end
|
1961
|
-
|
1962
|
-
context "A model dataset" do
|
1963
|
-
setup do
|
1964
|
-
@c = Class.new(Sequel::Dataset) do
|
1965
|
-
def fetch_rows(sql, &block)
|
1966
|
-
(1..10).each(&block)
|
1967
|
-
end
|
1968
|
-
end
|
1969
|
-
@dataset = @c.new(nil).from(:items)
|
1970
|
-
@m = Class.new do
|
1971
|
-
attr_accessor :c
|
1972
|
-
def initialize(c); @c = c; end
|
1973
|
-
def ==(o); @c == o.c; end
|
1974
|
-
end
|
1975
|
-
@dataset.set_model(@m)
|
1976
|
-
end
|
1977
|
-
|
1978
|
-
specify "should supply naked records if the naked option is specified" do
|
1979
|
-
@dataset.each {|r| r.class.should == @m}
|
1980
|
-
@dataset.each(:naked => true) {|r| r.class.should == Fixnum}
|
1981
|
-
end
|
1982
|
-
end
|
1983
|
-
|
1984
|
-
context "A polymorphic model dataset" do
|
1985
|
-
setup do
|
1986
|
-
@c = Class.new(Sequel::Dataset) do
|
1987
|
-
def fetch_rows(sql, &block)
|
1988
|
-
(1..10).each {|i| block.call(:bit => i[0])}
|
1989
|
-
end
|
1990
|
-
end
|
1991
|
-
@dataset = @c.new(nil).from(:items)
|
1992
|
-
@m = Class.new do
|
1993
|
-
attr_accessor :c
|
1994
|
-
def initialize(c); @c = c; end
|
1995
|
-
def ==(o); @c == o.c; end
|
1996
|
-
end
|
1997
|
-
end
|
1998
|
-
|
1999
|
-
specify "should use a nil key in the polymorphic hash to specify the default model class" do
|
2000
|
-
@m2 = Class.new(@m)
|
2001
|
-
@dataset.set_model(:bit, nil => @m, 1 => @m2)
|
2002
|
-
all = @dataset.all
|
2003
|
-
all[0].class.should == @m2
|
2004
|
-
all[1].class.should == @m
|
2005
|
-
all[2].class.should == @m2
|
2006
|
-
all[3].class.should == @m
|
2007
|
-
#...
|
2008
|
-
end
|
2009
|
-
|
2010
|
-
specify "should raise Sequel::Error if no suitable class is found in the polymorphic hash" do
|
2011
|
-
@m2 = Class.new(@m)
|
2012
|
-
@dataset.set_model(:bit, 1 => @m2)
|
2013
|
-
proc {@dataset.all}.should raise_error(Sequel::Error)
|
2014
|
-
end
|
2015
|
-
|
2016
|
-
specify "should supply naked records if the naked option is specified" do
|
2017
|
-
@dataset.set_model(:bit, nil => @m)
|
2018
|
-
@dataset.each(:naked => true) {|r| r.class.should == Hash}
|
2019
|
-
end
|
2020
|
-
end
|
2021
|
-
|
2022
|
-
context "A dataset with associated model class(es)" do
|
2023
|
-
setup do
|
2024
|
-
@c = Class.new(Sequel::Dataset) do
|
2025
|
-
def fetch_rows(sql, &block)
|
2026
|
-
block.call({:x => 1, :y => 2})
|
2027
|
-
end
|
2028
|
-
end
|
2029
|
-
@dataset = @c.new(nil).from(:items)
|
2030
|
-
@m1 = Class.new do
|
2031
|
-
attr_accessor :v
|
2032
|
-
def initialize(v); @v = v; end
|
2033
|
-
end
|
2034
|
-
@m2 = Class.new do
|
2035
|
-
attr_accessor :v, :vv
|
2036
|
-
def initialize(v = nil); @v = v; end
|
2037
|
-
def self.load(v); o = new(nil); o.vv = v; o; end
|
2038
|
-
end
|
2039
|
-
@m3 = Class.new(@m2)
|
2040
|
-
end
|
2041
|
-
|
2042
|
-
specify "should instantiate an instance by passing the record hash as argument" do
|
2043
|
-
@dataset.set_model(@m1)
|
2044
|
-
o = @dataset.first
|
2045
|
-
o.class.should == @m1
|
2046
|
-
o.v.should == {:x => 1, :y => 2}
|
2047
|
-
end
|
2048
|
-
|
2049
|
-
specify "should use the .load constructor if available" do
|
2050
|
-
@dataset.set_model(@m2)
|
2051
|
-
o = @dataset.first
|
2052
|
-
o.class.should == @m2
|
2053
|
-
o.v.should == nil
|
2054
|
-
o.vv.should == {:x => 1, :y => 2}
|
2055
|
-
end
|
2056
|
-
|
2057
|
-
specify "should use the .load constructor also for polymorphic datasets" do
|
2058
|
-
@dataset.set_model(:y, 1 => @m2, 2 => @m3)
|
2059
|
-
o = @dataset.first
|
2060
|
-
o.class.should == @m3
|
2061
|
-
o.v.should == nil
|
2062
|
-
o.vv.should == {:x => 1, :y => 2}
|
2063
|
-
end
|
2064
|
-
end
|
2065
|
-
|
2066
|
-
context "Dataset#<<" do
|
2067
|
-
setup do
|
2068
|
-
@d = Sequel::Dataset.new(nil)
|
2069
|
-
@d.meta_def(:insert) do |*args|
|
2070
|
-
1234567890
|
2071
|
-
end
|
2072
|
-
end
|
2073
|
-
|
2074
|
-
specify "should call #insert" do
|
2075
|
-
(@d << {:name => 1}).should == 1234567890
|
2076
|
-
end
|
2077
|
-
end
|
2078
|
-
|
2079
|
-
context "A paginated dataset" do
|
2080
|
-
setup do
|
2081
|
-
@d = Sequel::Dataset.new(nil)
|
2082
|
-
@d.meta_def(:count) {153}
|
2083
|
-
|
2084
|
-
@paginated = @d.paginate(1, 20)
|
2085
|
-
end
|
2086
|
-
|
2087
|
-
specify "should raise an error if the dataset already has a limit" do
|
2088
|
-
proc{@d.limit(10).paginate(1,10)}.should raise_error(Sequel::Error)
|
2089
|
-
proc{@paginated.paginate(2,20)}.should raise_error(Sequel::Error)
|
2090
|
-
end
|
2091
|
-
|
2092
|
-
specify "should set the limit and offset options correctly" do
|
2093
|
-
@paginated.opts[:limit].should == 20
|
2094
|
-
@paginated.opts[:offset].should == 0
|
2095
|
-
end
|
2096
|
-
|
2097
|
-
specify "should set the page count correctly" do
|
2098
|
-
@paginated.page_count.should == 8
|
2099
|
-
@d.paginate(1, 50).page_count.should == 4
|
2100
|
-
end
|
2101
|
-
|
2102
|
-
specify "should set the current page number correctly" do
|
2103
|
-
@paginated.current_page.should == 1
|
2104
|
-
@d.paginate(3, 50).current_page.should == 3
|
2105
|
-
end
|
2106
|
-
|
2107
|
-
specify "should return the next page number or nil if we're on the last" do
|
2108
|
-
@paginated.next_page.should == 2
|
2109
|
-
@d.paginate(4, 50).next_page.should be_nil
|
2110
|
-
end
|
2111
|
-
|
2112
|
-
specify "should return the previous page number or nil if we're on the last" do
|
2113
|
-
@paginated.prev_page.should be_nil
|
2114
|
-
@d.paginate(4, 50).prev_page.should == 3
|
2115
|
-
end
|
2116
|
-
|
2117
|
-
specify "should return the page range" do
|
2118
|
-
@paginated.page_range.should == (1..8)
|
2119
|
-
@d.paginate(4, 50).page_range.should == (1..4)
|
2120
|
-
end
|
2121
|
-
|
2122
|
-
specify "should return the record range for the current page" do
|
2123
|
-
@paginated.current_page_record_range.should == (1..20)
|
2124
|
-
@d.paginate(4, 50).current_page_record_range.should == (151..153)
|
2125
|
-
@d.paginate(5, 50).current_page_record_range.should == (0..0)
|
2126
|
-
end
|
2127
|
-
|
2128
|
-
specify "should return the record count for the current page" do
|
2129
|
-
@paginated.current_page_record_count.should == 20
|
2130
|
-
@d.paginate(3, 50).current_page_record_count.should == 50
|
2131
|
-
@d.paginate(4, 50).current_page_record_count.should == 3
|
2132
|
-
@d.paginate(5, 50).current_page_record_count.should == 0
|
2133
|
-
end
|
2134
|
-
|
2135
|
-
specify "should know if current page is last page" do
|
2136
|
-
@paginated.last_page?.should be_false
|
2137
|
-
@d.paginate(2, 20).last_page?.should be_false
|
2138
|
-
@d.paginate(5, 30).last_page?.should be_false
|
2139
|
-
@d.paginate(6, 30).last_page?.should be_true
|
2140
|
-
end
|
2141
|
-
|
2142
|
-
specify "should know if current page is first page" do
|
2143
|
-
@paginated.first_page?.should be_true
|
2144
|
-
@d.paginate(1, 20).first_page?.should be_true
|
2145
|
-
@d.paginate(2, 20).first_page?.should be_false
|
2146
|
-
end
|
2147
|
-
|
2148
|
-
specify "should work with fixed sql" do
|
2149
|
-
ds = @d.clone(:sql => 'select * from blah')
|
2150
|
-
ds.meta_def(:count) {150}
|
2151
|
-
ds.paginate(2, 50).sql.should == 'SELECT * FROM (select * from blah) t1 LIMIT 50 OFFSET 50'
|
2152
|
-
end
|
2153
|
-
end
|
2154
|
-
|
2155
|
-
context "Dataset#each_page" do
|
2156
|
-
setup do
|
2157
|
-
@d = Sequel::Dataset.new(nil).from(:items)
|
2158
|
-
@d.meta_def(:count) {153}
|
2159
|
-
end
|
2160
|
-
|
2161
|
-
specify "should raise an error if the dataset already has a limit" do
|
2162
|
-
proc{@d.limit(10).each_page(10){}}.should raise_error(Sequel::Error)
|
2163
|
-
end
|
2164
|
-
|
2165
|
-
specify "should iterate over each page in the resultset as a paginated dataset" do
|
2166
|
-
a = []
|
2167
|
-
@d.each_page(50) {|p| a << p}
|
2168
|
-
a.map {|p| p.sql}.should == [
|
2169
|
-
'SELECT * FROM items LIMIT 50 OFFSET 0',
|
2170
|
-
'SELECT * FROM items LIMIT 50 OFFSET 50',
|
2171
|
-
'SELECT * FROM items LIMIT 50 OFFSET 100',
|
2172
|
-
'SELECT * FROM items LIMIT 50 OFFSET 150',
|
2173
|
-
]
|
2174
|
-
end
|
2175
|
-
end
|
2176
|
-
|
2177
|
-
context "Dataset#columns" do
|
2178
|
-
setup do
|
2179
|
-
@dataset = DummyDataset.new(nil).from(:items)
|
2180
|
-
@dataset.meta_def(:columns=) {|c| @columns = c}
|
2181
|
-
i = 'a'
|
2182
|
-
@dataset.meta_def(:each) {|o| @columns = select_sql(o||@opts) + i; i = i.next}
|
2183
|
-
end
|
2184
|
-
|
2185
|
-
specify "should return the value of @columns if @columns is not nil" do
|
2186
|
-
@dataset.columns = [:a, :b, :c]
|
2187
|
-
@dataset.columns.should == [:a, :b, :c]
|
2188
|
-
end
|
2189
|
-
|
2190
|
-
specify "should attempt to get a single record and return @columns if @columns is nil" do
|
2191
|
-
@dataset.columns = nil
|
2192
|
-
@dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
|
2193
|
-
@dataset.opts[:from] = [:nana]
|
2194
|
-
@dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
|
2195
|
-
end
|
2196
|
-
|
2197
|
-
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
2198
|
-
@dataset.filter!(:b=>100).order!(:b).distinct!(:b)
|
2199
|
-
@dataset.columns = nil
|
2200
|
-
@dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
|
2201
|
-
end
|
2202
|
-
end
|
2203
|
-
|
2204
|
-
context "Dataset#columns!" do
|
2205
|
-
setup do
|
2206
|
-
@dataset = DummyDataset.new(nil).from(:items)
|
2207
|
-
i = 'a'
|
2208
|
-
@dataset.meta_def(:each) {|o| @columns = select_sql(o||@opts) + i; i = i.next}
|
2209
|
-
end
|
2210
|
-
|
2211
|
-
specify "should always attempt to get a record and return @columns" do
|
2212
|
-
@dataset.columns!.should == 'SELECT * FROM items LIMIT 1a'
|
2213
|
-
@dataset.columns!.should == 'SELECT * FROM items LIMIT 1b'
|
2214
|
-
@dataset.opts[:from] = [:nana]
|
2215
|
-
@dataset.columns!.should == 'SELECT * FROM nana LIMIT 1c'
|
2216
|
-
end
|
2217
|
-
end
|
2218
|
-
|
2219
|
-
require 'stringio'
|
2220
|
-
|
2221
|
-
context "Dataset#print" do
|
2222
|
-
setup do
|
2223
|
-
@output = StringIO.new
|
2224
|
-
@orig_stdout = $stdout
|
2225
|
-
$stdout = @output
|
2226
|
-
@dataset = DummyDataset.new(nil).from(:items)
|
2227
|
-
end
|
2228
|
-
|
2229
|
-
teardown do
|
2230
|
-
$stdout = @orig_stdout
|
2231
|
-
end
|
2232
|
-
|
2233
|
-
specify "should print out a table with the values" do
|
2234
|
-
@dataset.print(:a, :b)
|
2235
|
-
@output.rewind
|
2236
|
-
@output.read.should == \
|
2237
|
-
"+-+-+\n|a|b|\n+-+-+\n|1|2|\n|3|4|\n|5|6|\n+-+-+\n"
|
2238
|
-
end
|
2239
|
-
|
2240
|
-
specify "should default to the dataset's columns" do
|
2241
|
-
@dataset.meta_def(:columns) {[:a, :b]}
|
2242
|
-
@dataset.print
|
2243
|
-
@output.rewind
|
2244
|
-
@output.read.should == \
|
2245
|
-
"+-+-+\n|a|b|\n+-+-+\n|1|2|\n|3|4|\n|5|6|\n+-+-+\n"
|
2246
|
-
end
|
2247
|
-
end
|
2248
|
-
|
2249
|
-
context "Dataset#multi_insert" do
|
2250
|
-
setup do
|
2251
|
-
@dbc = Class.new do
|
2252
|
-
attr_reader :sqls
|
2253
|
-
|
2254
|
-
def execute(sql)
|
2255
|
-
@sqls ||= []
|
2256
|
-
@sqls << sql
|
2257
|
-
end
|
2258
|
-
|
2259
|
-
def transaction
|
2260
|
-
@sqls ||= []
|
2261
|
-
@sqls << 'BEGIN'
|
2262
|
-
yield
|
2263
|
-
@sqls << 'COMMIT'
|
2264
|
-
end
|
2265
|
-
end
|
2266
|
-
@db = @dbc.new
|
2267
|
-
|
2268
|
-
@ds = Sequel::Dataset.new(@db).from(:items)
|
2269
|
-
|
2270
|
-
@list = [{:name => 'abc'}, {:name => 'def'}, {:name => 'ghi'}]
|
2271
|
-
end
|
2272
|
-
|
2273
|
-
specify "should join all inserts into a single SQL string" do
|
2274
|
-
@ds.multi_insert(@list)
|
2275
|
-
@db.sqls.should == [
|
2276
|
-
'BEGIN',
|
2277
|
-
"INSERT INTO items (name) VALUES ('abc')",
|
2278
|
-
"INSERT INTO items (name) VALUES ('def')",
|
2279
|
-
"INSERT INTO items (name) VALUES ('ghi')",
|
2280
|
-
'COMMIT'
|
2281
|
-
]
|
2282
|
-
end
|
2283
|
-
|
2284
|
-
specify "should accept the :commit_every option for committing every x records" do
|
2285
|
-
@ds.multi_insert(@list, :commit_every => 2)
|
2286
|
-
@db.sqls.should == [
|
2287
|
-
'BEGIN',
|
2288
|
-
"INSERT INTO items (name) VALUES ('abc')",
|
2289
|
-
"INSERT INTO items (name) VALUES ('def')",
|
2290
|
-
'COMMIT',
|
2291
|
-
'BEGIN',
|
2292
|
-
"INSERT INTO items (name) VALUES ('ghi')",
|
2293
|
-
'COMMIT'
|
2294
|
-
]
|
2295
|
-
end
|
2296
|
-
|
2297
|
-
specify "should accept the :slice option for committing every x records" do
|
2298
|
-
@ds.multi_insert(@list, :slice => 2)
|
2299
|
-
@db.sqls.should == [
|
2300
|
-
'BEGIN',
|
2301
|
-
"INSERT INTO items (name) VALUES ('abc')",
|
2302
|
-
"INSERT INTO items (name) VALUES ('def')",
|
2303
|
-
'COMMIT',
|
2304
|
-
'BEGIN',
|
2305
|
-
"INSERT INTO items (name) VALUES ('ghi')",
|
2306
|
-
'COMMIT'
|
2307
|
-
]
|
2308
|
-
end
|
2309
|
-
|
2310
|
-
specify "should accept a columns array and a values array" do
|
2311
|
-
@ds.multi_insert([:x, :y], [[1, 2], [3, 4]])
|
2312
|
-
@db.sqls.should == [
|
2313
|
-
'BEGIN',
|
2314
|
-
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2315
|
-
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2316
|
-
'COMMIT'
|
2317
|
-
]
|
2318
|
-
end
|
2319
|
-
|
2320
|
-
specify "should accept a columns array and a dataset" do
|
2321
|
-
@ds2 = Sequel::Dataset.new(@db).from(:cats).filter(:purr => true).select(:a, :b)
|
2322
|
-
|
2323
|
-
@ds.multi_insert([:x, :y], @ds2)
|
2324
|
-
@db.sqls.should == [
|
2325
|
-
'BEGIN',
|
2326
|
-
"INSERT INTO items (x, y) VALUES (SELECT a, b FROM cats WHERE (purr = 't'))",
|
2327
|
-
'COMMIT'
|
2328
|
-
]
|
2329
|
-
end
|
2330
|
-
|
2331
|
-
specify "should accept a columns array and a values array with slice option" do
|
2332
|
-
@ds.multi_insert([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
2333
|
-
@db.sqls.should == [
|
2334
|
-
'BEGIN',
|
2335
|
-
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2336
|
-
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2337
|
-
'COMMIT',
|
2338
|
-
'BEGIN',
|
2339
|
-
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2340
|
-
'COMMIT'
|
2341
|
-
]
|
2342
|
-
end
|
2343
|
-
|
2344
|
-
specify "should be aliased by #import" do
|
2345
|
-
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
2346
|
-
@db.sqls.should == [
|
2347
|
-
'BEGIN',
|
2348
|
-
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2349
|
-
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2350
|
-
'COMMIT',
|
2351
|
-
'BEGIN',
|
2352
|
-
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2353
|
-
'COMMIT'
|
2354
|
-
]
|
2355
|
-
end
|
2356
|
-
|
2357
|
-
specify "should not do anything if no columns or values are given" do
|
2358
|
-
@ds.multi_insert
|
2359
|
-
@db.sqls.should be_nil
|
2360
|
-
|
2361
|
-
@ds.multi_insert([])
|
2362
|
-
@db.sqls.should be_nil
|
2363
|
-
|
2364
|
-
@ds.multi_insert([], [])
|
2365
|
-
@db.sqls.should be_nil
|
2366
|
-
|
2367
|
-
@ds.multi_insert([{}, {}])
|
2368
|
-
@db.sqls.should be_nil
|
2369
|
-
|
2370
|
-
@ds.multi_insert([:a, :b], [])
|
2371
|
-
@db.sqls.should be_nil
|
2372
|
-
|
2373
|
-
@ds.multi_insert([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
2374
|
-
@db.sqls.should == [
|
2375
|
-
'BEGIN',
|
2376
|
-
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2377
|
-
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2378
|
-
'COMMIT',
|
2379
|
-
'BEGIN',
|
2380
|
-
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2381
|
-
'COMMIT'
|
2382
|
-
]
|
2383
|
-
end
|
2384
|
-
|
2385
|
-
end
|
2386
|
-
|
2387
|
-
context "Dataset#query" do
|
2388
|
-
setup do
|
2389
|
-
@d = Sequel::Dataset.new(nil)
|
2390
|
-
end
|
2391
|
-
|
2392
|
-
specify "should support #from" do
|
2393
|
-
q = @d.query {from :xxx}
|
2394
|
-
q.class.should == @d.class
|
2395
|
-
q.sql.should == "SELECT * FROM xxx"
|
2396
|
-
end
|
2397
|
-
|
2398
|
-
specify "should support #select" do
|
2399
|
-
q = @d.query do
|
2400
|
-
select :a, :b___mongo
|
2401
|
-
from :yyy
|
2402
|
-
end
|
2403
|
-
q.class.should == @d.class
|
2404
|
-
q.sql.should == "SELECT a, b AS mongo FROM yyy"
|
2405
|
-
end
|
2406
|
-
|
2407
|
-
specify "should support #where" do
|
2408
|
-
q = @d.query do
|
2409
|
-
from :zzz
|
2410
|
-
where(:x + 2 > :y + 3)
|
2411
|
-
end
|
2412
|
-
q.class.should == @d.class
|
2413
|
-
q.sql.should == "SELECT * FROM zzz WHERE ((x + 2) > (y + 3))"
|
2414
|
-
|
2415
|
-
q = @d.from(:zzz).query do
|
2416
|
-
where((:x > 1) & (:y > 2))
|
2417
|
-
end
|
2418
|
-
q.class.should == @d.class
|
2419
|
-
q.sql.should == "SELECT * FROM zzz WHERE ((x > 1) AND (y > 2))"
|
2420
|
-
|
2421
|
-
q = @d.from(:zzz).query do
|
2422
|
-
where :x => 33
|
2423
|
-
end
|
2424
|
-
q.class.should == @d.class
|
2425
|
-
q.sql.should == "SELECT * FROM zzz WHERE (x = 33)"
|
2426
|
-
end
|
2427
|
-
|
2428
|
-
specify "should support #group_by and #having" do
|
2429
|
-
q = @d.query do
|
2430
|
-
from :abc
|
2431
|
-
group_by :id
|
2432
|
-
having(:x >= 2)
|
2433
|
-
end
|
2434
|
-
q.class.should == @d.class
|
2435
|
-
q.sql.should == "SELECT * FROM abc GROUP BY id HAVING (x >= 2)"
|
2436
|
-
end
|
2437
|
-
|
2438
|
-
specify "should support #order, #order_by" do
|
2439
|
-
q = @d.query do
|
2440
|
-
from :xyz
|
2441
|
-
order_by :stamp
|
2442
|
-
end
|
2443
|
-
q.class.should == @d.class
|
2444
|
-
q.sql.should == "SELECT * FROM xyz ORDER BY stamp"
|
2445
|
-
end
|
2446
|
-
|
2447
|
-
specify "should raise on non-chainable method calls" do
|
2448
|
-
proc {@d.query {first_source}}.should raise_error(Sequel::Error)
|
2449
|
-
end
|
2450
|
-
|
2451
|
-
specify "should raise on each, insert, update, delete" do
|
2452
|
-
proc {@d.query {each}}.should raise_error(Sequel::Error)
|
2453
|
-
proc {@d.query {insert(:x => 1)}}.should raise_error(Sequel::Error)
|
2454
|
-
proc {@d.query {update(:x => 1)}}.should raise_error(Sequel::Error)
|
2455
|
-
proc {@d.query {delete}}.should raise_error(Sequel::Error)
|
2456
|
-
end
|
2457
|
-
end
|
2458
|
-
|
2459
|
-
context "Dataset" do
|
2460
|
-
setup do
|
2461
|
-
@d = Sequel::Dataset.new(nil).from(:x)
|
2462
|
-
end
|
2463
|
-
|
2464
|
-
specify "should support self-changing select!" do
|
2465
|
-
@d.select!(:y)
|
2466
|
-
@d.sql.should == "SELECT y FROM x"
|
2467
|
-
end
|
2468
|
-
|
2469
|
-
specify "should support self-changing from!" do
|
2470
|
-
@d.from!(:y)
|
2471
|
-
@d.sql.should == "SELECT * FROM y"
|
2472
|
-
end
|
2473
|
-
|
2474
|
-
specify "should support self-changing order!" do
|
2475
|
-
@d.order!(:y)
|
2476
|
-
@d.sql.should == "SELECT * FROM x ORDER BY y"
|
2477
|
-
end
|
2478
|
-
|
2479
|
-
specify "should support self-changing filter!" do
|
2480
|
-
@d.filter!(:y => 1)
|
2481
|
-
@d.sql.should == "SELECT * FROM x WHERE (y = 1)"
|
2482
|
-
end
|
2483
|
-
|
2484
|
-
specify "should support self-changing filter! with block" do
|
2485
|
-
@d.filter!{:y < 2}
|
2486
|
-
@d.sql.should == "SELECT * FROM x WHERE (y < 2)"
|
2487
|
-
end
|
2488
|
-
|
2489
|
-
specify "should raise for ! methods that don't return a dataset" do
|
2490
|
-
proc {@d.opts!}.should raise_error(NameError)
|
2491
|
-
end
|
2492
|
-
|
2493
|
-
specify "should raise for missing methods" do
|
2494
|
-
proc {@d.xuyz}.should raise_error(NameError)
|
2495
|
-
proc {@d.xyz!}.should raise_error(NameError)
|
2496
|
-
proc {@d.xyz?}.should raise_error(NameError)
|
2497
|
-
end
|
2498
|
-
|
2499
|
-
specify "should support chaining of bang methods" do
|
2500
|
-
@d.order!(:y)
|
2501
|
-
@d.filter!(:y => 1)
|
2502
|
-
@d.sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
2503
|
-
end
|
2504
|
-
end
|
2505
|
-
|
2506
|
-
context "Dataset#transform" do
|
2507
|
-
setup do
|
2508
|
-
@c = Class.new(Sequel::Dataset) do
|
2509
|
-
attr_accessor :raw
|
2510
|
-
attr_accessor :sql
|
2511
|
-
|
2512
|
-
def fetch_rows(sql, &block)
|
2513
|
-
block[@raw]
|
2514
|
-
end
|
2515
|
-
|
2516
|
-
def insert(v)
|
2517
|
-
@sql = insert_sql(v)
|
2518
|
-
end
|
2519
|
-
|
2520
|
-
def update(v)
|
2521
|
-
@sql = update_sql(v)
|
2522
|
-
end
|
2523
|
-
end
|
2524
|
-
|
2525
|
-
@ds = @c.new(nil).from(:items)
|
2526
|
-
@ds.transform(:x => [
|
2527
|
-
proc {|v| Marshal.load(v)},
|
2528
|
-
proc {|v| Marshal.dump(v)}
|
2529
|
-
])
|
2530
|
-
end
|
2531
|
-
|
2532
|
-
specify "should change the dataset to transform values loaded from the database" do
|
2533
|
-
@ds.raw = {:x => Marshal.dump([1, 2, 3]), :y => 'hello'}
|
2534
|
-
@ds.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
2535
|
-
@ds.raw = {:x => Marshal.dump([1, 2, 3]), :y => 'hello'}
|
2536
|
-
@ds.all.should == [{:x => [1, 2, 3], :y => 'hello'}]
|
2537
|
-
end
|
2538
|
-
|
2539
|
-
specify "should change the dataset to transform values saved to the database" do
|
2540
|
-
@ds.insert(:x => :toast)
|
2541
|
-
@ds.sql.should == "INSERT INTO items (x) VALUES ('#{Marshal.dump(:toast)}')"
|
2542
|
-
|
2543
|
-
@ds.insert(:y => 'butter')
|
2544
|
-
@ds.sql.should == "INSERT INTO items (y) VALUES ('butter')"
|
2545
|
-
|
2546
|
-
@ds.update(:x => ['dream'])
|
2547
|
-
@ds.sql.should == "UPDATE items SET x = '#{Marshal.dump(['dream'])}'"
|
2548
|
-
end
|
2549
|
-
|
2550
|
-
specify "should be transferred to cloned datasets" do
|
2551
|
-
@ds2 = @ds.filter(:a => 1)
|
2552
|
-
|
2553
|
-
@ds2.raw = {:x => Marshal.dump([1, 2, 3]), :y => 'hello'}
|
2554
|
-
@ds2.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
2555
|
-
|
2556
|
-
@ds2.insert(:x => :toast)
|
2557
|
-
@ds2.sql.should == "INSERT INTO items (x) VALUES ('#{Marshal.dump(:toast)}')"
|
2558
|
-
end
|
2559
|
-
|
2560
|
-
specify "should work correctly together with set_row_proc" do
|
2561
|
-
@ds.row_proc = proc{|r| r[:z] = r[:x] * 2; r}
|
2562
|
-
@ds.raw = {:x => Marshal.dump("wow"), :y => 'hello'}
|
2563
|
-
@ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
|
2564
|
-
|
2565
|
-
f = nil
|
2566
|
-
@ds.raw = {:x => Marshal.dump("wow"), :y => 'hello'}
|
2567
|
-
@ds.each(:naked => true) {|r| f = r}
|
2568
|
-
f.should == {:x => "wow", :y => 'hello'}
|
2569
|
-
end
|
2570
|
-
|
2571
|
-
specify "should leave the supplied values intact" do
|
2572
|
-
h = {:x => :toast}
|
2573
|
-
@ds.insert(h)
|
2574
|
-
h.should == {:x => :toast}
|
2575
|
-
end
|
2576
|
-
end
|
2577
|
-
|
2578
|
-
context "Dataset#transform" do
|
2579
|
-
setup do
|
2580
|
-
@c = Class.new(Sequel::Dataset) do
|
2581
|
-
attr_accessor :raw
|
2582
|
-
attr_accessor :sql
|
2583
|
-
|
2584
|
-
def fetch_rows(sql, &block)
|
2585
|
-
block[@raw]
|
2586
|
-
end
|
2587
|
-
|
2588
|
-
def insert(v)
|
2589
|
-
@sql = insert_sql(v)
|
2590
|
-
end
|
2591
|
-
|
2592
|
-
def update(v)
|
2593
|
-
@sql = update_sql(v)
|
2594
|
-
end
|
2595
|
-
end
|
2596
|
-
|
2597
|
-
@ds = @c.new(nil).from(:items)
|
2598
|
-
end
|
2599
|
-
|
2600
|
-
specify "should raise Sequel::Error for invalid transformations" do
|
2601
|
-
proc {@ds.transform(:x => 'mau')}.should raise_error(Sequel::Error::InvalidTransform)
|
2602
|
-
proc {@ds.transform(:x => :mau)}.should raise_error(Sequel::Error::InvalidTransform)
|
2603
|
-
proc {@ds.transform(:x => [])}.should raise_error(Sequel::Error::InvalidTransform)
|
2604
|
-
proc {@ds.transform(:x => ['mau'])}.should raise_error(Sequel::Error::InvalidTransform)
|
2605
|
-
proc {@ds.transform(:x => [proc {|v|}, proc {|v|}])}.should_not raise_error(Sequel::Error::InvalidTransform)
|
2606
|
-
end
|
2607
|
-
|
2608
|
-
specify "should support stock YAML transformation" do
|
2609
|
-
@ds.transform(:x => :yaml)
|
2610
|
-
|
2611
|
-
@ds.raw = {:x => [1, 2, 3].to_yaml, :y => 'hello'}
|
2612
|
-
@ds.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
2613
|
-
|
2614
|
-
@ds.insert(:x => :toast)
|
2615
|
-
@ds.sql.should == "INSERT INTO items (x) VALUES ('#{:toast.to_yaml}')"
|
2616
|
-
@ds.insert(:y => 'butter')
|
2617
|
-
@ds.sql.should == "INSERT INTO items (y) VALUES ('butter')"
|
2618
|
-
@ds.update(:x => ['dream'])
|
2619
|
-
@ds.sql.should == "UPDATE items SET x = '#{['dream'].to_yaml}'"
|
2620
|
-
|
2621
|
-
@ds2 = @ds.filter(:a => 1)
|
2622
|
-
@ds2.raw = {:x => [1, 2, 3].to_yaml, :y => 'hello'}
|
2623
|
-
@ds2.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
2624
|
-
@ds2.insert(:x => :toast)
|
2625
|
-
@ds2.sql.should == "INSERT INTO items (x) VALUES ('#{:toast.to_yaml}')"
|
2626
|
-
|
2627
|
-
@ds.row_proc = proc{|r| r[:z] = r[:x] * 2; r}
|
2628
|
-
@ds.raw = {:x => "wow".to_yaml, :y => 'hello'}
|
2629
|
-
@ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
|
2630
|
-
f = nil
|
2631
|
-
@ds.raw = {:x => "wow".to_yaml, :y => 'hello'}
|
2632
|
-
@ds.each(:naked => true) {|r| f = r}
|
2633
|
-
f.should == {:x => "wow", :y => 'hello'}
|
2634
|
-
end
|
2635
|
-
|
2636
|
-
specify "should support stock Marshal transformation with Base64 encoding" do
|
2637
|
-
@ds.transform(:x => :marshal)
|
2638
|
-
|
2639
|
-
@ds.raw = {:x => [Marshal.dump([1, 2, 3])].pack('m'), :y => 'hello'}
|
2640
|
-
@ds.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
2641
|
-
|
2642
|
-
@ds.insert(:x => :toast)
|
2643
|
-
@ds.sql.should == "INSERT INTO items (x) VALUES ('#{[Marshal.dump(:toast)].pack('m')}')"
|
2644
|
-
@ds.insert(:y => 'butter')
|
2645
|
-
@ds.sql.should == "INSERT INTO items (y) VALUES ('butter')"
|
2646
|
-
@ds.update(:x => ['dream'])
|
2647
|
-
@ds.sql.should == "UPDATE items SET x = '#{[Marshal.dump(['dream'])].pack('m')}'"
|
2648
|
-
|
2649
|
-
@ds2 = @ds.filter(:a => 1)
|
2650
|
-
@ds2.raw = {:x => [Marshal.dump([1, 2, 3])].pack('m'), :y => 'hello'}
|
2651
|
-
@ds2.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
2652
|
-
@ds2.insert(:x => :toast)
|
2653
|
-
@ds2.sql.should == "INSERT INTO items (x) VALUES ('#{[Marshal.dump(:toast)].pack('m')}')"
|
2654
|
-
|
2655
|
-
@ds.row_proc = proc{|r| r[:z] = r[:x] * 2; r}
|
2656
|
-
@ds.raw = {:x => [Marshal.dump("wow")].pack('m'), :y => 'hello'}
|
2657
|
-
@ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
|
2658
|
-
f = nil
|
2659
|
-
@ds.raw = {:x => [Marshal.dump("wow")].pack('m'), :y => 'hello'}
|
2660
|
-
@ds.each(:naked => true) {|r| f = r}
|
2661
|
-
f.should == {:x => "wow", :y => 'hello'}
|
2662
|
-
end
|
2663
|
-
|
2664
|
-
specify "should support loading of Marshalled values without Base64 encoding" do
|
2665
|
-
@ds.transform(:x => :marshal)
|
2666
|
-
|
2667
|
-
@ds.raw = {:x => Marshal.dump([1,2,3]), :y => nil}
|
2668
|
-
@ds.first.should == {:x => [1,2,3], :y => nil}
|
2669
|
-
end
|
2670
|
-
|
2671
|
-
specify "should return self" do
|
2672
|
-
@ds.transform(:x => :marshal).should be(@ds)
|
2673
|
-
end
|
2674
|
-
end
|
2675
|
-
|
2676
|
-
context "A dataset with a transform" do
|
2677
|
-
setup do
|
2678
|
-
@ds = Sequel::Dataset.new(nil).from(:items)
|
2679
|
-
@ds.transform(:x => :marshal)
|
2680
|
-
end
|
2681
|
-
|
2682
|
-
specify "should automatically transform hash filters" do
|
2683
|
-
@ds.filter(:y => 2).sql.should == 'SELECT * FROM items WHERE (y = 2)'
|
2684
|
-
|
2685
|
-
@ds.filter(:x => 2).sql.should == "SELECT * FROM items WHERE (x = '#{[Marshal.dump(2)].pack('m')}')"
|
2686
|
-
end
|
2687
|
-
end
|
2688
|
-
|
2689
|
-
context "Dataset#to_csv" do
|
2690
|
-
setup do
|
2691
|
-
@c = Class.new(Sequel::Dataset) do
|
2692
|
-
attr_accessor :data
|
2693
|
-
attr_accessor :columns
|
2694
|
-
|
2695
|
-
def fetch_rows(sql, &block)
|
2696
|
-
@data.each(&block)
|
2697
|
-
end
|
2698
|
-
|
2699
|
-
# naked should return self here because to_csv wants a naked result set.
|
2700
|
-
def naked
|
2701
|
-
self
|
2702
|
-
end
|
2703
|
-
end
|
2704
|
-
|
2705
|
-
@ds = @c.new(nil).from(:items)
|
2706
|
-
@ds.columns = [:a, :b, :c]
|
2707
|
-
@ds.data = [ {:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}, {:a=>7, :b=>8, :c=>9} ]
|
2708
|
-
end
|
2709
|
-
|
2710
|
-
specify "should format a CSV representation of the records" do
|
2711
|
-
@ds.to_csv.should ==
|
2712
|
-
"a, b, c\r\n1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
2713
|
-
end
|
2714
|
-
|
2715
|
-
specify "should exclude column titles if so specified" do
|
2716
|
-
@ds.to_csv(false).should ==
|
2717
|
-
"1, 2, 3\r\n4, 5, 6\r\n7, 8, 9\r\n"
|
2718
|
-
end
|
2719
|
-
end
|
2720
|
-
|
2721
|
-
context "Dataset#create_view" do
|
2722
|
-
setup do
|
2723
|
-
@dbc = Class.new(Sequel::Database) do
|
2724
|
-
attr_reader :sqls
|
2725
|
-
|
2726
|
-
def execute(sql)
|
2727
|
-
@sqls ||= []
|
2728
|
-
@sqls << sql
|
2729
|
-
end
|
2730
|
-
end
|
2731
|
-
@db = @dbc.new
|
2732
|
-
|
2733
|
-
@ds = @db[:items].order(:abc).filter(:category => 'ruby')
|
2734
|
-
end
|
2735
|
-
|
2736
|
-
specify "should create a view with the dataset's sql" do
|
2737
|
-
@ds.create_view(:xyz)
|
2738
|
-
@db.sqls.should == ["CREATE VIEW xyz AS #{@ds.sql}"]
|
2739
|
-
end
|
2740
|
-
end
|
2741
|
-
|
2742
|
-
context "Dataset#create_or_replace_view" do
|
2743
|
-
setup do
|
2744
|
-
@dbc = Class.new(Sequel::Database) do
|
2745
|
-
attr_reader :sqls
|
2746
|
-
|
2747
|
-
def execute(sql)
|
2748
|
-
@sqls ||= []
|
2749
|
-
@sqls << sql
|
2750
|
-
end
|
2751
|
-
end
|
2752
|
-
@db = @dbc.new
|
2753
|
-
|
2754
|
-
@ds = @db[:items].order(:abc).filter(:category => 'ruby')
|
2755
|
-
end
|
2756
|
-
|
2757
|
-
specify "should create a view with the dataset's sql" do
|
2758
|
-
@ds.create_or_replace_view(:xyz)
|
2759
|
-
@db.sqls.should == ["CREATE OR REPLACE VIEW xyz AS #{@ds.sql}"]
|
2760
|
-
end
|
2761
|
-
end
|
2762
|
-
|
2763
|
-
context "Dataset#update_sql" do
|
2764
|
-
setup do
|
2765
|
-
@ds = Sequel::Dataset.new(nil).from(:items)
|
2766
|
-
end
|
2767
|
-
|
2768
|
-
specify "should accept strings" do
|
2769
|
-
@ds.update_sql("a = b").should == "UPDATE items SET a = b"
|
2770
|
-
end
|
2771
|
-
|
2772
|
-
specify "should accept hash with string keys" do
|
2773
|
-
@ds.update_sql('c' => 'd').should == "UPDATE items SET c = 'd'"
|
2774
|
-
end
|
2775
|
-
|
2776
|
-
specify "should accept array subscript references" do
|
2777
|
-
@ds.update_sql((:day|1) => 'd').should == "UPDATE items SET day[1] = 'd'"
|
2778
|
-
end
|
2779
|
-
end
|
2780
|
-
|
2781
|
-
context "Dataset#insert_sql" do
|
2782
|
-
setup do
|
2783
|
-
@ds = Sequel::Dataset.new(nil).from(:items)
|
2784
|
-
end
|
2785
|
-
|
2786
|
-
specify "should accept hash with symbol keys" do
|
2787
|
-
@ds.insert_sql(:c => 'd').should == "INSERT INTO items (c) VALUES ('d')"
|
2788
|
-
end
|
2789
|
-
|
2790
|
-
specify "should accept hash with string keys" do
|
2791
|
-
@ds.insert_sql('c' => 'd').should == "INSERT INTO items (c) VALUES ('d')"
|
2792
|
-
end
|
2793
|
-
|
2794
|
-
specify "should accept array subscript references" do
|
2795
|
-
@ds.insert_sql((:day|1) => 'd').should == "INSERT INTO items (day[1]) VALUES ('d')"
|
2796
|
-
end
|
2797
|
-
end
|
2798
|
-
|
2799
|
-
class DummyMummyDataset < Sequel::Dataset
|
2800
|
-
def first
|
2801
|
-
raise if @opts[:from] == [:a]
|
2802
|
-
true
|
2803
|
-
end
|
2804
|
-
end
|
2805
|
-
|
2806
|
-
class DummyMummyDatabase < Sequel::Database
|
2807
|
-
attr_reader :sqls
|
2808
|
-
|
2809
|
-
def execute(sql)
|
2810
|
-
@sqls ||= []
|
2811
|
-
@sqls << sql
|
2812
|
-
end
|
2813
|
-
|
2814
|
-
def transaction; yield; end
|
2815
|
-
|
2816
|
-
def dataset
|
2817
|
-
DummyMummyDataset.new(self)
|
2818
|
-
end
|
2819
|
-
end
|
2820
|
-
|
2821
|
-
context "Dataset#table_exists?" do
|
2822
|
-
setup do
|
2823
|
-
@db = DummyMummyDatabase.new
|
2824
|
-
@db.stub!(:tables).and_return([:a, :b])
|
2825
|
-
@db2 = DummyMummyDatabase.new
|
2826
|
-
end
|
2827
|
-
|
2828
|
-
specify "should use Database#tables if available" do
|
2829
|
-
@db[:a].table_exists?.should be_true
|
2830
|
-
@db[:b].table_exists?.should be_true
|
2831
|
-
@db[:c].table_exists?.should be_false
|
2832
|
-
end
|
2833
|
-
|
2834
|
-
specify "should otherwise try to select the first record from the table's dataset" do
|
2835
|
-
@db2[:a].table_exists?.should be_false
|
2836
|
-
@db2[:b].table_exists?.should be_true
|
2837
|
-
end
|
2838
|
-
|
2839
|
-
specify "should raise Sequel::Error if dataset references more than one table" do
|
2840
|
-
proc {@db.from(:a, :b).table_exists?}.should raise_error(Sequel::Error)
|
2841
|
-
end
|
2842
|
-
|
2843
|
-
specify "should raise Sequel::Error if dataset is from a subquery" do
|
2844
|
-
proc {@db.from(@db[:a]).table_exists?}.should raise_error(Sequel::Error)
|
2845
|
-
end
|
2846
|
-
|
2847
|
-
specify "should raise Sequel::Error if dataset has fixed sql" do
|
2848
|
-
proc {@db['select * from blah'].table_exists?}.should raise_error(Sequel::Error)
|
2849
|
-
end
|
2850
|
-
end
|
2851
|
-
|
2852
|
-
context "Dataset#inspect" do
|
2853
|
-
setup do
|
2854
|
-
@ds = Sequel::Dataset.new(nil).from(:blah)
|
2855
|
-
end
|
2856
|
-
|
2857
|
-
specify "should include the class name and the corresponding SQL statement" do
|
2858
|
-
@ds.inspect.should == '#<%s: %s>' % [@ds.class.to_s, @ds.sql.inspect]
|
2859
|
-
end
|
2860
|
-
end
|
2861
|
-
|
2862
|
-
context "Dataset#all" do
|
2863
|
-
setup do
|
2864
|
-
@c = Class.new(Sequel::Dataset) do
|
2865
|
-
def fetch_rows(sql, &block)
|
2866
|
-
block.call({:x => 1, :y => 2})
|
2867
|
-
block.call({:x => 3, :y => 4})
|
2868
|
-
block.call(sql)
|
2869
|
-
end
|
2870
|
-
end
|
2871
|
-
@dataset = @c.new(nil).from(:items)
|
2872
|
-
end
|
2873
|
-
|
2874
|
-
specify "should return an array with all records" do
|
2875
|
-
@dataset.all.should == [
|
2876
|
-
{:x => 1, :y => 2},
|
2877
|
-
{:x => 3, :y => 4},
|
2878
|
-
"SELECT * FROM items"
|
2879
|
-
]
|
2880
|
-
end
|
2881
|
-
|
2882
|
-
specify "should accept options and pass them to #each" do
|
2883
|
-
@dataset.all(:limit => 33).should == [
|
2884
|
-
{:x => 1, :y => 2},
|
2885
|
-
{:x => 3, :y => 4},
|
2886
|
-
"SELECT * FROM items LIMIT 33"
|
2887
|
-
]
|
2888
|
-
end
|
2889
|
-
|
2890
|
-
specify "should iterate over the array if a block is given" do
|
2891
|
-
a = []
|
2892
|
-
|
2893
|
-
@dataset.all do |r|
|
2894
|
-
a << (r.is_a?(Hash) ? r[:x] : r)
|
2895
|
-
end
|
2896
|
-
|
2897
|
-
a.should == [1, 3, "SELECT * FROM items"]
|
2898
|
-
end
|
2899
|
-
end
|
2900
|
-
|
2901
|
-
context "Dataset#grep" do
|
2902
|
-
setup do
|
2903
|
-
@ds = Sequel::Dataset.new(nil).from(:posts)
|
2904
|
-
end
|
2905
|
-
|
2906
|
-
specify "should format a SQL filter correctly" do
|
2907
|
-
@ds.grep(:title, 'ruby').sql.should ==
|
2908
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
2909
|
-
end
|
2910
|
-
|
2911
|
-
specify "should support multiple columns" do
|
2912
|
-
@ds.grep([:title, :body], 'ruby').sql.should ==
|
2913
|
-
"SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
2914
|
-
end
|
2915
|
-
|
2916
|
-
specify "should support multiple search terms" do
|
2917
|
-
@ds.grep(:title, ['abc', 'def']).sql.should ==
|
2918
|
-
"SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')))"
|
2919
|
-
end
|
2920
|
-
|
2921
|
-
specify "should support multiple columns and search terms" do
|
2922
|
-
@ds.grep([:title, :body], ['abc', 'def']).sql.should ==
|
2923
|
-
"SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')) OR ((body LIKE 'abc') OR (body LIKE 'def')))"
|
2924
|
-
end
|
2925
|
-
|
2926
|
-
specify "should support regexps though the database may not support it" do
|
2927
|
-
@ds.grep(:title, /ruby/).sql.should ==
|
2928
|
-
"SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
2929
|
-
|
2930
|
-
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
|
2931
|
-
"SELECT * FROM posts WHERE (((title ~ '^ruby') OR (title LIKE 'ruby')))"
|
2932
|
-
end
|
2933
|
-
end
|