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.
@@ -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']||'mysql://root@localhost/sandbox') unless defined? MYSQL_URL
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 do
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 => 'root', :socket => MYSQL_SOCKET_FILE)
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 => 'root', :socket => MYSQL_SOCKET_FILE)
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 => 'root', :socket => 'blah')
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 consider strings containing backslashes to be escaped string literals" do
241
- @d.literal("\\dingo").should == "'\\\\dingo'" # literally, E'\\dingo'
242
- @d.literal("dingo").should == "'dingo'"
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 not support drop_column operations" do
391
- proc {@db.drop_column :test2, :value}.should raise_error(Sequel::Error)
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
@@ -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#qualify" do
232
- specify "should format a qualified column" do
233
- :xyz.qualify(:abc).to_s(Sequel::Dataset.new(nil)).should == 'abc.xyz'
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
 
@@ -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
- pt_specify "should provide a filtered #from dataset if a block is given" do
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
- pt_specify "should be composable using AND operator (for scoping) with block" do
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
- pt_specify "should accept proc expressions" do
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 != 1}.sql.should ==
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? 'ABC%'}.sql.should ==
325
+ @dataset.filter {:c.like 'ABC%'}.sql.should ==
360
326
  "SELECT * FROM test WHERE (c LIKE 'ABC%')"
361
327
 
362
- @dataset.filter {:c.like? ['ABC%', '%XYZ']}.sql.should ==
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
- pt_specify "should allow the use of blocks and arguments simultaneously" do
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
- pt_specify "should accept blocks passed to filter" do
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
- pt_specify "should allow the use of blocks and arguments simultaneously" do
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
- pt_specify "should accept blocks passed to filter" do
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
- pt_specify "should support proc expressions" do
497
- @dataset.exclude{:id == (6...12)}.sql.should ==
498
- 'SELECT * FROM test WHERE NOT (id >= 6 AND id < 12)'
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
- pt_specify "should allow the use of blocks and arguments simultaneously" do
502
- @dataset.exclude(:id => (7..11)){:id == (6...12)}.sql.should ==
503
- 'SELECT * FROM test WHERE (((id < 7) OR (id > 11)) OR NOT (id >= 6 AND id < 12))'
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
- pt_specify "should support proc expressions" do
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
- pt_specify "should return the first matching record if a block is given without an argument" do
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
- pt_specify "should combine block and standard argument filters if argument is not an Integer" do
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
- pt_specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
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
- pt_specify "should support self-changing filter! with block" do
2491
- @d.filter!{:y == 2}
2492
- @d.sql.should == "SELECT * FROM x WHERE (y = 2)"
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