sequel_core 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +39 -1
- data/Rakefile +1 -1
- data/doc/dataset_filtering.rdoc +5 -87
- data/lib/sequel_core.rb +20 -13
- data/lib/sequel_core/adapters/mysql.rb +12 -11
- data/lib/sequel_core/adapters/odbc_mssql.rb +3 -3
- data/lib/sequel_core/adapters/oracle.rb +2 -2
- data/lib/sequel_core/adapters/postgres.rb +46 -26
- data/lib/sequel_core/adapters/sqlite.rb +12 -0
- data/lib/sequel_core/core_sql.rb +7 -0
- data/lib/sequel_core/database.rb +12 -14
- data/lib/sequel_core/dataset.rb +6 -3
- data/lib/sequel_core/dataset/sql.rb +28 -25
- data/lib/sequel_core/object_graph.rb +23 -21
- data/lib/sequel_core/schema/sql.rb +5 -1
- data/lib/sequel_core/sql.rb +76 -5
- data/spec/adapters/mysql_spec.rb +33 -9
- data/spec/adapters/postgres_spec.rb +35 -3
- data/spec/adapters/sqlite_spec.rb +14 -2
- data/spec/core_sql_spec.rb +38 -3
- data/spec/database_spec.rb +19 -1
- data/spec/dataset_spec.rb +60 -66
- data/spec/{blockless_filters_spec.rb → expression_filters_spec.rb} +2 -10
- data/spec/object_graph_spec.rb +5 -0
- data/spec/schema_spec.rb +6 -6
- data/spec/spec_config.rb.example +2 -1
- data/spec/spec_helper.rb +0 -6
- metadata +3 -6
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +0 -310
- data/lib/sequel_core/dataset/sequelizer.rb +0 -50
- data/spec/sequelizer_spec.rb +0 -504
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '../spec_helper.rb')
|
2
2
|
|
3
|
+
unless defined?(MYSQL_USER)
|
4
|
+
MYSQL_USER = 'root'
|
5
|
+
end
|
3
6
|
unless defined?(MYSQL_DB)
|
4
|
-
MYSQL_URL = (ENV['SEQUEL_MY_SPEC_DB']||
|
7
|
+
MYSQL_URL = (ENV['SEQUEL_MY_SPEC_DB']||"mysql://#{MYSQL_USER}@localhost/sandbox") unless defined? MYSQL_URL
|
5
8
|
MYSQL_DB = Sequel.connect(MYSQL_URL)
|
6
9
|
end
|
7
10
|
unless defined?(MYSQL_SOCKET_FILE)
|
@@ -36,6 +39,9 @@ context "A MySQL database" do
|
|
36
39
|
setup do
|
37
40
|
@db = MYSQL_DB
|
38
41
|
end
|
42
|
+
teardown do
|
43
|
+
Sequel.convert_tinyint_to_bool = true
|
44
|
+
end
|
39
45
|
|
40
46
|
specify "should provide disconnect functionality" do
|
41
47
|
@db.tables
|
@@ -66,6 +72,9 @@ context "A MySQL database" do
|
|
66
72
|
|
67
73
|
specify "should correctly parse the schema" do
|
68
74
|
@db.schema(:booltest, :reload=>true).should == [[:value, {:type=>:boolean, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"tinyint", :numeric_precision=>3}]]
|
75
|
+
|
76
|
+
Sequel.convert_tinyint_to_bool = false
|
77
|
+
@db.schema(:booltest, :reload=>true).should == [[:value, {:type=>:integer, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"tinyint", :numeric_precision=>3}]]
|
69
78
|
end
|
70
79
|
|
71
80
|
specify "should get the schema all database tables if no table name is used" do
|
@@ -248,6 +257,9 @@ context "MySQL datasets" do
|
|
248
257
|
setup do
|
249
258
|
@d = MYSQL_DB[:orders]
|
250
259
|
end
|
260
|
+
teardown do
|
261
|
+
Sequel.convert_tinyint_to_bool = true
|
262
|
+
end
|
251
263
|
|
252
264
|
specify "should correctly quote column references" do
|
253
265
|
@d.quote_identifiers = true
|
@@ -255,22 +267,34 @@ context "MySQL datasets" do
|
|
255
267
|
ack_stamp = Time.now - 15 * 60 # 15 minutes ago
|
256
268
|
@d.query do
|
257
269
|
select :market, :minute[:from_unixtime[:ack]].as(:minute)
|
258
|
-
where
|
259
|
-
:ack > ack_stamp
|
260
|
-
:market == market
|
261
|
-
end
|
270
|
+
where {(:ack > ack_stamp) & {:market => market}}
|
262
271
|
group_by :minute[:from_unixtime[:ack]]
|
263
272
|
end.sql.should == \
|
264
273
|
"SELECT `market`, minute(from_unixtime(`ack`)) AS `minute` FROM `orders` WHERE ((`ack` > #{@d.literal(ack_stamp)}) AND (`market` = 'ICE')) GROUP BY minute(from_unixtime(`ack`))"
|
265
274
|
end
|
266
275
|
|
267
|
-
specify "should accept and return tinyints as bools" do
|
276
|
+
specify "should accept and return tinyints as bools or integers when configured to do so" do
|
268
277
|
MYSQL_DB[:booltest].delete
|
269
278
|
MYSQL_DB[:booltest] << {:value=>true}
|
270
279
|
MYSQL_DB[:booltest].all.should == [{:value=>true}]
|
271
280
|
MYSQL_DB[:booltest].delete
|
272
281
|
MYSQL_DB[:booltest] << {:value=>false}
|
273
282
|
MYSQL_DB[:booltest].all.should == [{:value=>false}]
|
283
|
+
|
284
|
+
Sequel.convert_tinyint_to_bool = false
|
285
|
+
MYSQL_DB[:booltest].delete
|
286
|
+
MYSQL_DB[:booltest] << {:value=>true}
|
287
|
+
MYSQL_DB[:booltest].all.should == [{:value=>1}]
|
288
|
+
MYSQL_DB[:booltest].delete
|
289
|
+
MYSQL_DB[:booltest] << {:value=>false}
|
290
|
+
MYSQL_DB[:booltest].all.should == [{:value=>0}]
|
291
|
+
|
292
|
+
MYSQL_DB[:booltest].delete
|
293
|
+
MYSQL_DB[:booltest] << {:value=>1}
|
294
|
+
MYSQL_DB[:booltest].all.should == [{:value=>1}]
|
295
|
+
MYSQL_DB[:booltest].delete
|
296
|
+
MYSQL_DB[:booltest] << {:value=>0}
|
297
|
+
MYSQL_DB[:booltest].all.should == [{:value=>0}]
|
274
298
|
end
|
275
299
|
end
|
276
300
|
|
@@ -466,17 +490,17 @@ end
|
|
466
490
|
if %w'localhost 127.0.0.1 ::1'.include? MYSQL_URI.host
|
467
491
|
context "A MySQL database" do
|
468
492
|
specify "should accept a socket option" do
|
469
|
-
db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user =>
|
493
|
+
db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => MYSQL_USER, :socket => MYSQL_SOCKET_FILE)
|
470
494
|
proc {db.test_connection}.should_not raise_error
|
471
495
|
end
|
472
496
|
|
473
497
|
specify "should accept a socket option without host option" do
|
474
|
-
db = Sequel.mysql(MYSQL_DB_NAME, :user =>
|
498
|
+
db = Sequel.mysql(MYSQL_DB_NAME, :user => MYSQL_USER, :socket => MYSQL_SOCKET_FILE)
|
475
499
|
proc {db.test_connection}.should_not raise_error
|
476
500
|
end
|
477
501
|
|
478
502
|
specify "should fail to connect with invalid socket" do
|
479
|
-
db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user =>
|
503
|
+
db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => MYSQL_USER, :socket => 'blah')
|
480
504
|
proc {db.test_connection}.should raise_error
|
481
505
|
end
|
482
506
|
end
|
@@ -17,6 +17,10 @@ POSTGRES_DB.create_table! :test3 do
|
|
17
17
|
integer :value
|
18
18
|
timestamp :time
|
19
19
|
end
|
20
|
+
POSTGRES_DB.create_table! :test4 do
|
21
|
+
varchar :name, :size => 20
|
22
|
+
bytea :value
|
23
|
+
end
|
20
24
|
|
21
25
|
context "A PostgreSQL database" do
|
22
26
|
setup do
|
@@ -43,6 +47,10 @@ context "A PostgreSQL database" do
|
|
43
47
|
[:value, {:type=>:integer, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"integer", :numeric_precision=>32}],
|
44
48
|
[:time, {:type=>:datetime, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"timestamp without time zone", :numeric_precision=>nil}]
|
45
49
|
]
|
50
|
+
@db.schema(:test4, :reload=>true).should == [
|
51
|
+
[:name, {:type=>:string, :allow_null=>true, :max_chars=>20, :default=>nil, :db_type=>"character varying", :numeric_precision=>nil}],
|
52
|
+
[:value, {:type=>:blob, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"bytea", :numeric_precision=>nil}]
|
53
|
+
]
|
46
54
|
end
|
47
55
|
|
48
56
|
specify "should get the schema all database tables if no table name is used" do
|
@@ -172,6 +180,12 @@ context "A PostgreSQL dataset" do
|
|
172
180
|
@d.count.should == 1
|
173
181
|
end
|
174
182
|
|
183
|
+
specify "should have #transaction yield the connection" do
|
184
|
+
POSTGRES_DB.transaction do |conn|
|
185
|
+
conn.should be_a_kind_of(Sequel::Postgres::Adapter)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
175
189
|
specify "should correctly rollback transactions" do
|
176
190
|
proc do
|
177
191
|
POSTGRES_DB.transaction do
|
@@ -237,9 +251,27 @@ context "A PostgreSQL dataset" do
|
|
237
251
|
@d.filter(:name => /^bc/).count.should == 1
|
238
252
|
end
|
239
253
|
|
240
|
-
specify "should
|
241
|
-
|
242
|
-
|
254
|
+
specify "should correctly escape strings" do
|
255
|
+
POSTGRES_DB['SELECT ? AS a', "\\dingo"].get(:a) == "\\dingo"
|
256
|
+
end
|
257
|
+
|
258
|
+
specify "should properly escape binary data" do
|
259
|
+
POSTGRES_DB['SELECT ? AS a', "\1\2\3".to_blob].get(:a) == "\1\2\3"
|
260
|
+
end
|
261
|
+
|
262
|
+
specify "should retrieve binary data as Blob object" do
|
263
|
+
d = POSTGRES_DB[:test4]
|
264
|
+
d << {:name => '123', :value => "\1\2\3".to_blob}
|
265
|
+
retrieved_binary_value = d[:name => '123'][:value]
|
266
|
+
retrieved_binary_value.should be_a_kind_of(::Sequel::SQL::Blob)
|
267
|
+
retrieved_binary_value.should == "\1\2\3"
|
268
|
+
retrieved_binary_value = d[:value => "\1\2\3".to_blob][:value]
|
269
|
+
retrieved_binary_value.should be_a_kind_of(::Sequel::SQL::Blob)
|
270
|
+
retrieved_binary_value.should == "\1\2\3"
|
271
|
+
end
|
272
|
+
|
273
|
+
specify "should properly receive binary data" do
|
274
|
+
POSTGRES_DB['SELECT ?::bytea AS a', "a"].get(:a) == "a"
|
243
275
|
end
|
244
276
|
end
|
245
277
|
|
@@ -387,8 +387,11 @@ context "A SQLite database" do
|
|
387
387
|
@db[:test2].first.should == {:name => 'mmm', :value => 111, :xyz=>'000'}
|
388
388
|
end
|
389
389
|
|
390
|
-
specify "should
|
391
|
-
|
390
|
+
specify "should support drop_column operations" do
|
391
|
+
@db.drop_column :test2, :value
|
392
|
+
@db[:test2].columns.should == [:name]
|
393
|
+
@db[:test2] << {:name => 'mmm'}
|
394
|
+
@db[:test2].first.should == {:name => 'mmm'}
|
392
395
|
end
|
393
396
|
|
394
397
|
specify "should not support rename_column operations" do
|
@@ -398,4 +401,13 @@ context "A SQLite database" do
|
|
398
401
|
specify "should not support set_column_type operations" do
|
399
402
|
proc {@db.set_column_type :test2, :value, :integer}.should raise_error(Sequel::Error)
|
400
403
|
end
|
404
|
+
|
405
|
+
specify "should support add_index" do
|
406
|
+
@db.add_index :test2, :value, :unique => true
|
407
|
+
@db.add_index :test2, [:name, :value]
|
408
|
+
end
|
409
|
+
|
410
|
+
specify "should not support drop_index" do
|
411
|
+
proc {@db.drop_index :test2, :value}.should raise_error(Sequel::Error)
|
412
|
+
end
|
401
413
|
end
|
data/spec/core_sql_spec.rb
CHANGED
@@ -111,6 +111,17 @@ context "String#lit" do
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
+
context "String#to_blob" do
|
115
|
+
specify "should return a Blob object" do
|
116
|
+
'xyz'.to_blob.should be_a_kind_of(::Sequel::SQL::Blob)
|
117
|
+
'xyz'.to_blob.should == 'xyz'
|
118
|
+
end
|
119
|
+
|
120
|
+
specify "should retain binary data" do
|
121
|
+
"\1\2\3\4".to_blob.should == "\1\2\3\4"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
114
125
|
context "String#split_sql" do
|
115
126
|
specify "should split a string containing multiple statements" do
|
116
127
|
"DROP TABLE a; DROP TABLE c".split_sql.should == \
|
@@ -212,6 +223,13 @@ context "Column references" do
|
|
212
223
|
end
|
213
224
|
end
|
214
225
|
|
226
|
+
context "Blob" do
|
227
|
+
specify "#to_blob should return self" do
|
228
|
+
blob = "x".to_blob
|
229
|
+
blob.to_blob.object_id.should == blob.object_id
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
215
233
|
context "Symbol#*" do
|
216
234
|
setup do
|
217
235
|
@ds = Sequel::Dataset.new(nil)
|
@@ -228,9 +246,26 @@ context "Symbol#*" do
|
|
228
246
|
end
|
229
247
|
end
|
230
248
|
|
231
|
-
context "Symbol
|
232
|
-
|
233
|
-
|
249
|
+
context "Symbol" do
|
250
|
+
before do
|
251
|
+
@ds = Sequel::Dataset.new(nil)
|
252
|
+
@ds.quote_identifiers = true
|
253
|
+
end
|
254
|
+
|
255
|
+
specify "#identifier should format an identifier" do
|
256
|
+
@ds.literal(:xyz__abc.identifier).should == '"XYZ__ABC"'
|
257
|
+
end
|
258
|
+
|
259
|
+
specify "#qualify should format a qualified column" do
|
260
|
+
@ds.literal(:xyz.qualify(:abc)).should == '"ABC"."XYZ"'
|
261
|
+
end
|
262
|
+
|
263
|
+
specify "should be able to qualify an identifier" do
|
264
|
+
@ds.literal(:xyz.identifier.qualify(:xyz__abc)).should == '"XYZ__ABC"."XYZ"'
|
265
|
+
end
|
266
|
+
|
267
|
+
specify "should be able to specify a schema.table.column" do
|
268
|
+
@ds.literal(:column.qualify(:table__name.qualify(:schema))).should == '"SCHEMA"."TABLE__NAME"."COLUMN"'
|
234
269
|
end
|
235
270
|
end
|
236
271
|
|
data/spec/database_spec.rb
CHANGED
@@ -35,6 +35,15 @@ context "A new Database" do
|
|
35
35
|
d.synchronize {|c| cc = c}
|
36
36
|
cc.should == 1234
|
37
37
|
end
|
38
|
+
|
39
|
+
specify "should respect the :quote_identifiers and :single_threaded options" do
|
40
|
+
db = Sequel::Database.new(:quote_identifiers=>false, :single_threaded=>true)
|
41
|
+
db.quote_identifiers?.should == false
|
42
|
+
db.pool.should be_a_kind_of(Sequel::SingleThreadedPool)
|
43
|
+
db = Sequel::Database.new(:quote_identifiers=>true, :single_threaded=>false)
|
44
|
+
db.quote_identifiers?.should == true
|
45
|
+
db.pool.should be_a_kind_of(Sequel::ConnectionPool)
|
46
|
+
end
|
38
47
|
end
|
39
48
|
|
40
49
|
context "Database#connect" do
|
@@ -97,7 +106,7 @@ context "Database#dataset" do
|
|
97
106
|
e.sql.should == 'SELECT * FROM miu'
|
98
107
|
end
|
99
108
|
|
100
|
-
|
109
|
+
specify "should provide a filtered #from dataset if a block is given" do
|
101
110
|
d = @db.from(:mau) {:x > 100}
|
102
111
|
d.should be_a_kind_of(Sequel::Dataset)
|
103
112
|
d.sql.should == 'SELECT * FROM mau WHERE (x > 100)'
|
@@ -587,6 +596,15 @@ context "A Database adapter with a scheme" do
|
|
587
596
|
c.should be_a_kind_of(CCC)
|
588
597
|
c.opts.should == {:adapter => :ccc, :database => 'mydb'}
|
589
598
|
end
|
599
|
+
|
600
|
+
specify "should be accessible through Sequel.connect with URL parameters" do
|
601
|
+
c = Sequel.connect 'ccc://localhost/db?host=/tmp&user=test'
|
602
|
+
c.should be_a_kind_of(CCC)
|
603
|
+
c.opts[:host].should == '/tmp'
|
604
|
+
c.opts[:database].should == 'db'
|
605
|
+
c.opts[:user].should == 'test'
|
606
|
+
end
|
607
|
+
|
590
608
|
end
|
591
609
|
|
592
610
|
context "An unknown database scheme" do
|
data/spec/dataset_spec.rb
CHANGED
@@ -164,11 +164,6 @@ context "A simple dataset" do
|
|
164
164
|
"UPDATE test SET name = 'abc'"
|
165
165
|
end
|
166
166
|
|
167
|
-
pt_specify "should format an update statement with block" do
|
168
|
-
@dataset.update_sql {:x << :y}.should ==
|
169
|
-
"UPDATE test SET x = y"
|
170
|
-
end
|
171
|
-
|
172
167
|
specify "should be able to return rows for arbitrary SQL" do
|
173
168
|
@dataset.select_sql(:sql => 'xxx yyy zzz').should ==
|
174
169
|
"xxx yyy zzz"
|
@@ -271,7 +266,7 @@ context "Dataset#where" do
|
|
271
266
|
"SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
|
272
267
|
end
|
273
268
|
|
274
|
-
|
269
|
+
specify "should be composable using AND operator (for scoping) with block" do
|
275
270
|
@d3.where{:e < 5}.select_sql.should ==
|
276
271
|
"SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
|
277
272
|
end
|
@@ -294,28 +289,11 @@ context "Dataset#where" do
|
|
294
289
|
'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id < 7))'
|
295
290
|
end
|
296
291
|
|
297
|
-
pt_specify "should accept ranges with a block" do
|
298
|
-
@dataset.filter {:id == (4..7)}.sql.should ==
|
299
|
-
'SELECT * FROM test WHERE (id >= 4 AND id <= 7)'
|
300
|
-
@dataset.filter {:id.in?(4..7)}.sql.should ==
|
301
|
-
'SELECT * FROM test WHERE (id >= 4 AND id <= 7)'
|
302
|
-
|
303
|
-
@dataset.filter {:table__id == (4..7)}.sql.should ==
|
304
|
-
'SELECT * FROM test WHERE (table.id >= 4 AND table.id <= 7)'
|
305
|
-
@dataset.filter {:table__id.in?(4..7)}.sql.should ==
|
306
|
-
'SELECT * FROM test WHERE (table.id >= 4 AND table.id <= 7)'
|
307
|
-
end
|
308
|
-
|
309
292
|
specify "should accept nil" do
|
310
293
|
@dataset.filter(:owner_id => nil).sql.should ==
|
311
294
|
'SELECT * FROM test WHERE (owner_id IS NULL)'
|
312
295
|
end
|
313
296
|
|
314
|
-
pt_specify "should accept nil with a block" do
|
315
|
-
@dataset.filter{:owner_id.nil?}.sql.should ==
|
316
|
-
'SELECT * FROM test WHERE (owner_id IS NULL)'
|
317
|
-
end
|
318
|
-
|
319
297
|
specify "should accept a subquery" do
|
320
298
|
@dataset.filter('gdp > ?', @d1.select(:avg[:gdp])).sql.should ==
|
321
299
|
"SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
@@ -330,36 +308,24 @@ context "Dataset#where" do
|
|
330
308
|
'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
|
331
309
|
end
|
332
310
|
|
333
|
-
|
311
|
+
specify "should accept proc expressions" do
|
334
312
|
d = @d1.select(:avg[:gdp])
|
335
313
|
@dataset.filter {:gdp > d}.sql.should ==
|
336
314
|
"SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
337
315
|
|
338
|
-
@dataset.filter {:id.in(4..7)}.sql.should ==
|
339
|
-
'SELECT * FROM test WHERE (id >= 4 AND id <= 7)'
|
340
|
-
|
341
|
-
@dataset.filter {:c == 3}.sql.should ==
|
342
|
-
'SELECT * FROM test WHERE (c = 3)'
|
343
|
-
|
344
|
-
@dataset.filter {:id == :items__id}.sql.should ==
|
345
|
-
'SELECT * FROM test WHERE (id = items.id)'
|
346
|
-
|
347
316
|
@dataset.filter {:a < 1}.sql.should ==
|
348
317
|
'SELECT * FROM test WHERE (a < 1)'
|
349
318
|
|
350
|
-
@dataset.filter {:a
|
351
|
-
'SELECT * FROM test WHERE (NOT (a = 1))'
|
352
|
-
|
353
|
-
@dataset.filter {:a >= 1 && :b <= 2}.sql.should ==
|
319
|
+
@dataset.filter {(:a >= 1) & (:b <= 2)}.sql.should ==
|
354
320
|
'SELECT * FROM test WHERE ((a >= 1) AND (b <= 2))'
|
355
321
|
|
356
322
|
@dataset.filter {:c.like 'ABC%'}.sql.should ==
|
357
323
|
"SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
358
324
|
|
359
|
-
@dataset.filter {:c.like
|
325
|
+
@dataset.filter {:c.like 'ABC%'}.sql.should ==
|
360
326
|
"SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
361
327
|
|
362
|
-
@dataset.filter {:c.like
|
328
|
+
@dataset.filter {:c.like 'ABC%', '%XYZ'}.sql.should ==
|
363
329
|
"SELECT * FROM test WHERE ((c LIKE 'ABC%') OR (c LIKE '%XYZ'))"
|
364
330
|
end
|
365
331
|
|
@@ -375,10 +341,18 @@ context "Dataset#where" do
|
|
375
341
|
"SELECT * FROM test WHERE 'f'"
|
376
342
|
end
|
377
343
|
|
378
|
-
|
344
|
+
specify "should allow the use of blocks and arguments simultaneously" do
|
379
345
|
@dataset.filter(:zz < 3){:yy > 3}.sql.should ==
|
380
346
|
'SELECT * FROM test WHERE ((zz < 3) AND (yy > 3))'
|
381
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
|
382
356
|
end
|
383
357
|
|
384
358
|
context "Dataset#or" do
|
@@ -403,7 +377,7 @@ context "Dataset#or" do
|
|
403
377
|
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
404
378
|
end
|
405
379
|
|
406
|
-
|
380
|
+
specify "should accept blocks passed to filter" do
|
407
381
|
@d1.or{:yy > 3}.sql.should ==
|
408
382
|
'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
409
383
|
end
|
@@ -416,7 +390,7 @@ context "Dataset#or" do
|
|
416
390
|
'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
|
417
391
|
end
|
418
392
|
|
419
|
-
|
393
|
+
specify "should allow the use of blocks and arguments simultaneously" do
|
420
394
|
@d1.or(:zz < 3){:yy > 3}.sql.should ==
|
421
395
|
'SELECT * FROM test WHERE ((x = 1) OR ((zz < 3) AND (yy > 3)))'
|
422
396
|
end
|
@@ -448,7 +422,7 @@ context "Dataset#and" do
|
|
448
422
|
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
449
423
|
end
|
450
424
|
|
451
|
-
|
425
|
+
specify "should accept blocks passed to filter" do
|
452
426
|
@d1.and {:yy > 3}.sql.should ==
|
453
427
|
'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
454
428
|
end
|
@@ -493,14 +467,14 @@ context "Dataset#exclude" do
|
|
493
467
|
"SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
494
468
|
end
|
495
469
|
|
496
|
-
|
497
|
-
@dataset.exclude{:id
|
498
|
-
'SELECT * FROM test WHERE
|
470
|
+
specify "should support proc expressions" do
|
471
|
+
@dataset.exclude{:id < 6}.sql.should ==
|
472
|
+
'SELECT * FROM test WHERE (id >= 6)'
|
499
473
|
end
|
500
474
|
|
501
|
-
|
502
|
-
@dataset.exclude(:id => (7..11)){:id
|
503
|
-
'SELECT * FROM test WHERE (((id < 7) OR (id > 11)) OR
|
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))'
|
504
478
|
end
|
505
479
|
end
|
506
480
|
|
@@ -540,7 +514,7 @@ context "Dataset#having" do
|
|
540
514
|
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
541
515
|
end
|
542
516
|
|
543
|
-
|
517
|
+
specify "should support proc expressions" do
|
544
518
|
@grouped.having {:sum[:population] > 10}.sql.should ==
|
545
519
|
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
546
520
|
end
|
@@ -592,6 +566,18 @@ context "Dataset#group_by" do
|
|
592
566
|
specify "should specify the grouping in generated select statement" do
|
593
567
|
@dataset.select_sql.should ==
|
594
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)"
|
595
581
|
end
|
596
582
|
end
|
597
583
|
|
@@ -829,11 +815,16 @@ context "Dataset#order" do
|
|
829
815
|
'SELECT * FROM test ORDER BY stamp'
|
830
816
|
end
|
831
817
|
|
832
|
-
specify "should accept a string" do
|
818
|
+
specify "should accept a literal string" do
|
833
819
|
@dataset.order('dada ASC'.lit).sql.should ==
|
834
820
|
'SELECT * FROM test ORDER BY dada ASC'
|
835
821
|
end
|
836
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
|
+
|
837
828
|
specify "should accept a nil to remove ordering" do
|
838
829
|
@dataset.order(:bah).order(nil).sql.should ==
|
839
830
|
'SELECT * FROM test'
|
@@ -1090,7 +1081,7 @@ context "Dataset#uniq" do
|
|
1090
1081
|
specify "should accept an expression list" do
|
1091
1082
|
@dataset.uniq(:a, :b).sql.should == 'SELECT DISTINCT ON (a, b) name FROM test'
|
1092
1083
|
|
1093
|
-
@dataset.uniq(:stamp.cast_as(:integer), :node_id).sql.should == 'SELECT DISTINCT ON (cast(stamp AS integer), node_id) name FROM test'
|
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'
|
1094
1085
|
end
|
1095
1086
|
|
1096
1087
|
specify "should do a subselect for count" do
|
@@ -1133,6 +1124,11 @@ context "Dataset#count" do
|
|
1133
1124
|
@dataset.count.should == 1
|
1134
1125
|
@c.sql.should == "SELECT COUNT(*) FROM (select abc from xyz) t1 LIMIT 1"
|
1135
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
|
1136
1132
|
end
|
1137
1133
|
|
1138
1134
|
|
@@ -1475,14 +1471,6 @@ context "Dataset#set" do
|
|
1475
1471
|
@d.set({:x => 3})
|
1476
1472
|
@d.last_sql.should == 'UPDATE items SET x = 3'
|
1477
1473
|
end
|
1478
|
-
|
1479
|
-
pt_specify "should accept a block" do
|
1480
|
-
@d.set{:x << :x + 1}
|
1481
|
-
@d.last_sql.should == 'UPDATE items SET x = (x + 1)'
|
1482
|
-
|
1483
|
-
@d.set{(:x|1) << (:x|2) + 1}
|
1484
|
-
@d.last_sql.should == 'UPDATE items SET x[1] = (x[2] + 1)'
|
1485
|
-
end
|
1486
1474
|
end
|
1487
1475
|
|
1488
1476
|
|
@@ -1629,17 +1617,17 @@ context "Dataset #first and #last" do
|
|
1629
1617
|
r = @d.order(:a).last(i).should == [[:a,1,:b,2, "SELECT * FROM test ORDER BY a DESC LIMIT #{i}"]] * i
|
1630
1618
|
end
|
1631
1619
|
|
1632
|
-
|
1620
|
+
specify "should return the first matching record if a block is given without an argument" do
|
1633
1621
|
@d.first{:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) LIMIT 1']
|
1634
1622
|
@d.order(:name).last{:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1']
|
1635
1623
|
end
|
1636
1624
|
|
1637
|
-
|
1625
|
+
specify "should combine block and standard argument filters if argument is not an Integer" do
|
1638
1626
|
@d.first(:y=>25){:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1']
|
1639
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']
|
1640
1628
|
end
|
1641
1629
|
|
1642
|
-
|
1630
|
+
specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
1643
1631
|
i = rand(10) + 10
|
1644
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
|
1645
1633
|
i = rand(10) + 10
|
@@ -2205,6 +2193,12 @@ context "Dataset#columns" do
|
|
2205
2193
|
@dataset.opts[:from] = [:nana]
|
2206
2194
|
@dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
|
2207
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
|
2208
2202
|
end
|
2209
2203
|
|
2210
2204
|
context "Dataset#columns!" do
|
@@ -2487,9 +2481,9 @@ context "Dataset" do
|
|
2487
2481
|
@d.sql.should == "SELECT * FROM x WHERE (y = 1)"
|
2488
2482
|
end
|
2489
2483
|
|
2490
|
-
|
2491
|
-
@d.filter!{:y
|
2492
|
-
@d.sql.should == "SELECT * FROM x WHERE (y
|
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)"
|
2493
2487
|
end
|
2494
2488
|
|
2495
2489
|
specify "should raise for ! methods that don't return a dataset" do
|