sequel_core 2.1.0 → 2.2.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.
@@ -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