sequel_core 1.5.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGELOG +116 -0
  2. data/COPYING +19 -19
  3. data/README +83 -32
  4. data/Rakefile +9 -20
  5. data/bin/sequel +43 -112
  6. data/doc/cheat_sheet.rdoc +225 -0
  7. data/doc/dataset_filtering.rdoc +257 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
  9. data/lib/sequel_core/adapters/ado.rb +3 -1
  10. data/lib/sequel_core/adapters/db2.rb +4 -2
  11. data/lib/sequel_core/adapters/dbi.rb +127 -113
  12. data/lib/sequel_core/adapters/informix.rb +4 -2
  13. data/lib/sequel_core/adapters/jdbc.rb +5 -3
  14. data/lib/sequel_core/adapters/mysql.rb +112 -46
  15. data/lib/sequel_core/adapters/odbc.rb +5 -7
  16. data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
  17. data/lib/sequel_core/adapters/openbase.rb +3 -1
  18. data/lib/sequel_core/adapters/oracle.rb +11 -9
  19. data/lib/sequel_core/adapters/postgres.rb +261 -262
  20. data/lib/sequel_core/adapters/sqlite.rb +72 -22
  21. data/lib/sequel_core/connection_pool.rb +140 -73
  22. data/lib/sequel_core/core_ext.rb +201 -66
  23. data/lib/sequel_core/core_sql.rb +123 -153
  24. data/lib/sequel_core/database/schema.rb +156 -0
  25. data/lib/sequel_core/database.rb +321 -338
  26. data/lib/sequel_core/dataset/callback.rb +11 -12
  27. data/lib/sequel_core/dataset/convenience.rb +213 -240
  28. data/lib/sequel_core/dataset/pagination.rb +58 -43
  29. data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
  30. data/lib/sequel_core/dataset/query.rb +41 -0
  31. data/lib/sequel_core/dataset/schema.rb +15 -0
  32. data/lib/sequel_core/dataset/sequelizer.rb +41 -373
  33. data/lib/sequel_core/dataset/sql.rb +741 -632
  34. data/lib/sequel_core/dataset.rb +183 -168
  35. data/lib/sequel_core/deprecated.rb +1 -169
  36. data/lib/sequel_core/exceptions.rb +24 -19
  37. data/lib/sequel_core/migration.rb +44 -52
  38. data/lib/sequel_core/object_graph.rb +43 -42
  39. data/lib/sequel_core/pretty_table.rb +71 -76
  40. data/lib/sequel_core/schema/generator.rb +163 -105
  41. data/lib/sequel_core/schema/sql.rb +250 -93
  42. data/lib/sequel_core/schema.rb +2 -8
  43. data/lib/sequel_core/sql.rb +394 -0
  44. data/lib/sequel_core/worker.rb +37 -27
  45. data/lib/sequel_core.rb +99 -45
  46. data/spec/adapters/informix_spec.rb +0 -1
  47. data/spec/adapters/mysql_spec.rb +177 -124
  48. data/spec/adapters/oracle_spec.rb +0 -1
  49. data/spec/adapters/postgres_spec.rb +98 -58
  50. data/spec/adapters/sqlite_spec.rb +45 -4
  51. data/spec/blockless_filters_spec.rb +269 -0
  52. data/spec/connection_pool_spec.rb +21 -18
  53. data/spec/core_ext_spec.rb +169 -19
  54. data/spec/core_sql_spec.rb +56 -49
  55. data/spec/database_spec.rb +78 -17
  56. data/spec/dataset_spec.rb +300 -428
  57. data/spec/migration_spec.rb +1 -1
  58. data/spec/object_graph_spec.rb +5 -11
  59. data/spec/rcov.opts +1 -1
  60. data/spec/schema_generator_spec.rb +16 -4
  61. data/spec/schema_spec.rb +89 -10
  62. data/spec/sequelizer_spec.rb +56 -56
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_config.rb +7 -0
  65. data/spec/spec_config.rb.example +5 -5
  66. data/spec/spec_helper.rb +6 -0
  67. data/spec/worker_spec.rb +1 -1
  68. metadata +78 -63
data/spec/dataset_spec.rb CHANGED
@@ -66,7 +66,7 @@ context "Dataset#clone" do
66
66
  specify "should deep-copy the dataset opts" do
67
67
  @clone = @dataset.clone
68
68
 
69
- @clone.opts.should_not eql(@dataset.opts)
69
+ @clone.opts.should_not equal(@dataset.opts)
70
70
  @dataset.filter!(:a => 'b')
71
71
  @clone.opts[:filter].should be_nil
72
72
  end
@@ -162,7 +162,9 @@ context "A simple dataset" do
162
162
  specify "should format an update statement" do
163
163
  @dataset.update_sql(:name => 'abc').should ==
164
164
  "UPDATE test SET name = 'abc'"
165
+ end
165
166
 
167
+ pt_specify "should format an update statement with block" do
166
168
  @dataset.update_sql {:x << :y}.should ==
167
169
  "UPDATE test SET x = y"
168
170
  end
@@ -195,23 +197,23 @@ context "Dataset#where" do
195
197
  setup do
196
198
  @dataset = Sequel::Dataset.new(nil).from(:test)
197
199
  @d1 = @dataset.where(:region => 'Asia')
198
- @d2 = @dataset.where('(region = ?)', 'Asia')
199
- @d3 = @dataset.where("(a = 1)")
200
+ @d2 = @dataset.where('region = ?', 'Asia')
201
+ @d3 = @dataset.where("a = 1")
200
202
  end
201
203
 
202
204
  specify "should work with hashes" do
203
205
  @dataset.where(:name => 'xyz', :price => 342).select_sql.
204
- should match(/WHERE \(name = 'xyz'\) AND \(price = 342\)|WHERE \(price = 342\) AND \(name = 'xyz'\)/)
206
+ should match(/WHERE \(\(name = 'xyz'\) AND \(price = 342\)\)|WHERE \(\(price = 342\) AND \(name = 'xyz'\)\)/)
205
207
  end
206
208
 
207
209
  specify "should work with arrays (ala ActiveRecord)" do
208
- @dataset.where('price < ? AND id in (?)', 100, [1, 2, 3]).select_sql.should ==
209
- "SELECT * FROM test WHERE price < 100 AND id in (1, 2, 3)"
210
+ @dataset.where('price < ? AND id in ?', 100, [1, 2, 3]).select_sql.should ==
211
+ "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
210
212
  end
211
213
 
212
214
  specify "should work with strings (custom SQL expressions)" do
213
215
  @dataset.where('(a = 1 AND b = 2)').select_sql.should ==
214
- "SELECT * FROM test WHERE (a = 1 AND b = 2)"
216
+ "SELECT * FROM test WHERE ((a = 1 AND b = 2))"
215
217
  end
216
218
 
217
219
  specify "should affect select, delete and update statements" do
@@ -232,45 +234,46 @@ context "Dataset#where" do
232
234
  specify "should be composable using AND operator (for scoping)" do
233
235
  # hashes are merged, no problem
234
236
  @d1.where(:size => 'big').select_sql.should ==
235
- "SELECT * FROM test WHERE (region = 'Asia') AND (size = 'big')"
237
+ "SELECT * FROM test WHERE ((region = 'Asia') AND (size = 'big'))"
236
238
 
237
239
  # hash and string
238
240
  @d1.where('population > 1000').select_sql.should ==
239
- "SELECT * FROM test WHERE (region = 'Asia') AND (population > 1000)"
241
+ "SELECT * FROM test WHERE ((region = 'Asia') AND (population > 1000))"
240
242
  @d1.where('(a > 1) OR (b < 2)').select_sql.should ==
241
- "SELECT * FROM test WHERE (region = 'Asia') AND ((a > 1) OR (b < 2))"
243
+ "SELECT * FROM test WHERE ((region = 'Asia') AND ((a > 1) OR (b < 2)))"
242
244
 
243
245
  # hash and array
244
- @d1.where('(GDP > ?)', 1000).select_sql.should ==
245
- "SELECT * FROM test WHERE (region = 'Asia') AND (GDP > 1000)"
246
+ @d1.where('GDP > ?', 1000).select_sql.should ==
247
+ "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
246
248
 
247
249
  # array and array
248
- @d2.where('(GDP > ?)', 1000).select_sql.should ==
249
- "SELECT * FROM test WHERE (region = 'Asia') AND (GDP > 1000)"
250
+ @d2.where('GDP > ?', 1000).select_sql.should ==
251
+ "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
250
252
 
251
253
  # array and hash
252
254
  @d2.where(:name => ['Japan', 'China']).select_sql.should ==
253
- "SELECT * FROM test WHERE (region = 'Asia') AND (name IN ('Japan', 'China'))"
255
+ "SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
254
256
 
255
257
  # array and string
256
258
  @d2.where('GDP > ?').select_sql.should ==
257
- "SELECT * FROM test WHERE (region = 'Asia') AND (GDP > ?)"
259
+ "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
258
260
 
259
261
  # string and string
260
262
  @d3.where('b = 2').select_sql.should ==
261
- "SELECT * FROM test WHERE (a = 1) AND (b = 2)"
263
+ "SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
262
264
 
263
265
  # string and hash
264
266
  @d3.where(:c => 3).select_sql.should ==
265
- "SELECT * FROM test WHERE (a = 1) AND (c = 3)"
267
+ "SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
266
268
 
267
269
  # string and array
268
- @d3.where('(d = ?)', 4).select_sql.should ==
269
- "SELECT * FROM test WHERE (a = 1) AND (d = 4)"
270
+ @d3.where('d = ?', 4).select_sql.should ==
271
+ "SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
272
+ end
270
273
 
271
- # string and proc expr
272
- @d3.where {:e < 5}.select_sql.should ==
273
- "SELECT * FROM test WHERE (a = 1) AND (e < 5)"
274
+ pt_specify "should be composable using AND operator (for scoping) with block" do
275
+ @d3.where{:e < 5}.select_sql.should ==
276
+ "SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
274
277
  end
275
278
 
276
279
  specify "should raise if the dataset is grouped" do
@@ -281,21 +284,22 @@ context "Dataset#where" do
281
284
 
282
285
  specify "should accept ranges" do
283
286
  @dataset.filter(:id => 4..7).sql.should ==
284
- 'SELECT * FROM test WHERE (id >= 4 AND id <= 7)'
287
+ 'SELECT * FROM test WHERE ((id >= 4) AND (id <= 7))'
285
288
  @dataset.filter(:id => 4...7).sql.should ==
286
- 'SELECT * FROM test WHERE (id >= 4 AND id < 7)'
289
+ 'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
287
290
 
291
+ @dataset.filter(:table__id => 4..7).sql.should ==
292
+ 'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id <= 7))'
293
+ @dataset.filter(:table__id => 4...7).sql.should ==
294
+ 'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id < 7))'
295
+ end
296
+
297
+ pt_specify "should accept ranges with a block" do
288
298
  @dataset.filter {:id == (4..7)}.sql.should ==
289
299
  'SELECT * FROM test WHERE (id >= 4 AND id <= 7)'
290
-
291
300
  @dataset.filter {:id.in?(4..7)}.sql.should ==
292
301
  'SELECT * FROM test WHERE (id >= 4 AND id <= 7)'
293
302
 
294
- @dataset.filter(:table__id => 4..7).sql.should ==
295
- 'SELECT * FROM test WHERE (table.id >= 4 AND table.id <= 7)'
296
- @dataset.filter(:table__id => 4...7).sql.should ==
297
- 'SELECT * FROM test WHERE (table.id >= 4 AND table.id < 7)'
298
-
299
303
  @dataset.filter {:table__id == (4..7)}.sql.should ==
300
304
  'SELECT * FROM test WHERE (table.id >= 4 AND table.id <= 7)'
301
305
  @dataset.filter {:table__id.in?(4..7)}.sql.should ==
@@ -305,7 +309,9 @@ context "Dataset#where" do
305
309
  specify "should accept nil" do
306
310
  @dataset.filter(:owner_id => nil).sql.should ==
307
311
  'SELECT * FROM test WHERE (owner_id IS NULL)'
312
+ end
308
313
 
314
+ pt_specify "should accept nil with a block" do
309
315
  @dataset.filter{:owner_id.nil?}.sql.should ==
310
316
  'SELECT * FROM test WHERE (owner_id IS NULL)'
311
317
  end
@@ -313,19 +319,19 @@ context "Dataset#where" do
313
319
  specify "should accept a subquery" do
314
320
  # select all countries that have GDP greater than the average for Asia
315
321
  @dataset.filter('gdp > ?', @d1.select(:avg[:gdp])).sql.should ==
316
- "SELECT * FROM test WHERE gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia'))"
322
+ "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
317
323
 
318
324
  @dataset.filter(:id => @d1.select(:id)).sql.should ==
319
325
  "SELECT * FROM test WHERE (id IN (SELECT id FROM test WHERE (region = 'Asia')))"
320
326
  end
321
327
 
322
328
  specify "should accept a subquery for an EXISTS clause" do
323
- a = @dataset.filter {:price < 100}
329
+ a = @dataset.filter(:price < 100)
324
330
  @dataset.filter(a.exists).sql.should ==
325
- 'SELECT * FROM test WHERE EXISTS (SELECT * FROM test WHERE (price < 100))'
331
+ 'SELECT * FROM test WHERE (EXISTS (SELECT * FROM test WHERE (price < 100)))'
326
332
  end
327
333
 
328
- specify "should accept proc expressions" do
334
+ pt_specify "should accept proc expressions" do
329
335
  d = @d1.select(:avg[:gdp])
330
336
  @dataset.filter {:gdp > d}.sql.should ==
331
337
  "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
@@ -384,24 +390,27 @@ context "Dataset#or" do
384
390
 
385
391
  specify "should add an alternative expression to the where clause" do
386
392
  @d1.or(:y => 2).sql.should ==
387
- 'SELECT * FROM test WHERE (x = 1) OR (y = 2)'
393
+ 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
388
394
  end
389
395
 
390
396
  specify "should accept all forms of filters" do
391
- # probably not exhaustive, but good enough
392
- @d1.or('(y > ?)', 2).sql.should ==
393
- 'SELECT * FROM test WHERE (x = 1) OR (y > 2)'
394
-
395
- (@d1.or {:yy > 3}).sql.should ==
396
- 'SELECT * FROM test WHERE (x = 1) OR (yy > 3)'
397
+ @d1.or('y > ?', 2).sql.should ==
398
+ 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
399
+ @d1.or(:yy > 3).sql.should ==
400
+ 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
401
+ end
402
+
403
+ pt_specify "should accept blocks passed to filter" do
404
+ @d1.or{:yy > 3}.sql.should ==
405
+ 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
397
406
  end
398
407
 
399
408
  specify "should correctly add parens to give predictable results" do
400
409
  @d1.filter(:y => 2).or(:z => 3).sql.should ==
401
- 'SELECT * FROM test WHERE ((x = 1) AND (y = 2)) OR (z = 3)'
410
+ 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
402
411
 
403
412
  @d1.or(:y => 2).filter(:z => 3).sql.should ==
404
- 'SELECT * FROM test WHERE ((x = 1) OR (y = 2)) AND (z = 3)'
413
+ 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
405
414
  end
406
415
  end
407
416
 
@@ -420,24 +429,28 @@ context "Dataset#and" do
420
429
 
421
430
  specify "should add an alternative expression to the where clause" do
422
431
  @d1.and(:y => 2).sql.should ==
423
- 'SELECT * FROM test WHERE (x = 1) AND (y = 2)'
432
+ 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
424
433
  end
425
434
 
426
435
  specify "should accept all forms of filters" do
427
436
  # probably not exhaustive, but good enough
428
- @d1.and('(y > ?)', 2).sql.should ==
429
- 'SELECT * FROM test WHERE (x = 1) AND (y > 2)'
437
+ @d1.and('y > ?', 2).sql.should ==
438
+ 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
439
+ @d1.and(:yy > 3).sql.should ==
440
+ 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
441
+ end
430
442
 
431
- (@d1.and {:yy > 3}).sql.should ==
432
- 'SELECT * FROM test WHERE (x = 1) AND (yy > 3)'
443
+ pt_specify "should accept blocks passed to filter" do
444
+ @d1.and {:yy > 3}.sql.should ==
445
+ 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
433
446
  end
434
447
 
435
448
  specify "should correctly add parens to give predictable results" do
436
449
  @d1.or(:y => 2).and(:z => 3).sql.should ==
437
- 'SELECT * FROM test WHERE ((x = 1) OR (y = 2)) AND (z = 3)'
450
+ 'SELECT * FROM test WHERE (((x = 1) OR (y = 2)) AND (z = 3))'
438
451
 
439
452
  @d1.and(:y => 2).or(:z => 3).sql.should ==
440
- 'SELECT * FROM test WHERE ((x = 1) AND (y = 2)) OR (z = 3)'
453
+ 'SELECT * FROM test WHERE (((x = 1) AND (y = 2)) OR (z = 3))'
441
454
  end
442
455
  end
443
456
 
@@ -448,33 +461,51 @@ context "Dataset#exclude" do
448
461
 
449
462
  specify "should correctly include the NOT operator when one condition is given" do
450
463
  @dataset.exclude(:region=>'Asia').select_sql.should ==
451
- "SELECT * FROM test WHERE (NOT (region = 'Asia'))"
464
+ "SELECT * FROM test WHERE (region != 'Asia')"
452
465
  end
453
466
 
454
467
  specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
455
468
  @dataset.exclude(:region => 'Asia', :name => 'Japan').select_sql.
456
- should match(Regexp.union(/WHERE \(NOT \(\(region = 'Asia'\) AND \(name = 'Japan'\)\)\)/,
457
- /WHERE \(NOT \(\(name = 'Japan'\) AND \(region = 'Asia'\)\)\)/))
469
+ should match(Regexp.union(/WHERE \(\(region != 'Asia'\) AND \(name != 'Japan'\)\)/,
470
+ /WHERE \(\(name != 'Japan'\) AND \(region != 'Asia'\)\)/))
458
471
  end
459
472
 
460
473
  specify "should parenthesize a single string condition correctly" do
461
474
  @dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should ==
462
- "SELECT * FROM test WHERE (NOT (region = 'Asia' AND name = 'Japan'))"
475
+ "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
463
476
  end
464
477
 
465
478
  specify "should parenthesize an array condition correctly" do
466
479
  @dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should ==
467
- "SELECT * FROM test WHERE (NOT (region = 'Asia' AND name = 'Japan'))"
480
+ "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
468
481
  end
469
482
 
470
483
  specify "should correctly parenthesize when it is used twice" do
471
484
  @dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should ==
472
- "SELECT * FROM test WHERE (NOT (region = 'Asia')) AND (NOT (name = 'Japan'))"
485
+ "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
473
486
  end
474
487
 
475
- specify "should support proc expressions" do
488
+ pt_specify "should support proc expressions" do
476
489
  @dataset.exclude {:id == (6...12)}.sql.should ==
477
- 'SELECT * FROM test WHERE (NOT ((id >= 6 AND id < 12)))'
490
+ 'SELECT * FROM test WHERE NOT (id >= 6 AND id < 12)'
491
+ end
492
+ end
493
+
494
+ context "Dataset#invert" do
495
+ setup do
496
+ @d = Sequel::Dataset.new(nil).from(:test)
497
+ end
498
+
499
+ specify "should raise error if the dataset is not filtered" do
500
+ proc{@d.invert}.should raise_error(Sequel::Error)
501
+ end
502
+
503
+ specify "should invert current filter if dataset is filtered" do
504
+ @d.filter(:x).invert.sql.should == 'SELECT * FROM test WHERE NOT x'
505
+ end
506
+
507
+ specify "should invert both having and where if both are preset" do
508
+ @d.filter(:x).group(:x).having(:x).invert.sql.should == 'SELECT * FROM test WHERE NOT x GROUP BY x HAVING NOT x'
478
509
  end
479
510
  end
480
511
 
@@ -493,17 +524,17 @@ context "Dataset#having" do
493
524
 
494
525
  specify "should affect select statements" do
495
526
  @d1.select_sql.should ==
496
- "SELECT #{@columns} FROM test GROUP BY region HAVING sum(population) > 10"
527
+ "SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
497
528
  end
498
529
 
499
- specify "should support proc expressions" do
530
+ pt_specify "should support proc expressions" do
500
531
  @grouped.having {:sum[:population] > 10}.sql.should ==
501
532
  "SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
502
533
  end
503
534
 
504
535
  specify "should work with and on the having clause" do
505
- @grouped.having{ :a > 1 }.and{ :b < 2 }.sql.should ==
506
- "SELECT #{@columns} FROM test GROUP BY region HAVING (a > 1) AND (b < 2)"
536
+ @grouped.having( :a > 1 ).and( :b < 2 ).sql.should ==
537
+ "SELECT #{@columns} FROM test GROUP BY region HAVING ((a > 1) AND (b < 2))"
507
538
  end
508
539
  end
509
540
 
@@ -528,7 +559,7 @@ context "a grouped dataset" do
528
559
  specify "should format the right statement for counting (as a subquery)" do
529
560
  db = MockDatabase.new
530
561
  db[:test].select(:name).group(:name).count
531
- db.sqls.should == ["SELECT COUNT(*) FROM (SELECT name FROM test GROUP BY name) t1"]
562
+ db.sqls.should == ["SELECT COUNT(*) FROM (SELECT name FROM test GROUP BY name) t1 LIMIT 1"]
532
563
  end
533
564
  end
534
565
 
@@ -551,6 +582,14 @@ context "Dataset#group_by" do
551
582
  end
552
583
  end
553
584
 
585
+ context "Dataset#as" do
586
+ specify "should set up an alias" do
587
+ dataset = Sequel::Dataset.new(nil).from(:test)
588
+ dataset.select(dataset.limit(1).select(:name).as(:n)).sql.should == \
589
+ 'SELECT (SELECT name FROM test LIMIT 1) AS n FROM test'
590
+ end
591
+ end
592
+
554
593
  context "Dataset#literal" do
555
594
  setup do
556
595
  @dataset = Sequel::Dataset.new(nil).from(:test)
@@ -576,9 +615,9 @@ context "Dataset#literal" do
576
615
  end
577
616
 
578
617
  specify "should literalize an array properly" do
579
- @dataset.literal([]).should == "NULL"
580
- @dataset.literal([1, 'abc', 3]).should == "1, 'abc', 3"
581
- @dataset.literal([1, "a'b''c", 3]).should == "1, 'a''b''''c', 3"
618
+ @dataset.literal([]).should == "(NULL)"
619
+ @dataset.literal([1, 'abc', 3]).should == "(1, 'abc', 3)"
620
+ @dataset.literal([1, "a'b''c", 3]).should == "(1, 'a''b''''c', 3)"
582
621
  end
583
622
 
584
623
  specify "should literalize symbols as column references" do
@@ -658,9 +697,9 @@ context "Dataset#from" do
658
697
  "SELECT * FROM (SELECT * FROM a GROUP BY b) c"
659
698
  end
660
699
 
661
- specify "should use the relevant table name if given a simple dataset" do
700
+ specify "should always use a subquery if given a dataset" do
662
701
  @dataset.from(@dataset.from(:a)).select_sql.should ==
663
- "SELECT * FROM a"
702
+ "SELECT * FROM (SELECT * FROM a) t1"
664
703
  end
665
704
 
666
705
  specify "should raise if no source is given" do
@@ -671,8 +710,8 @@ context "Dataset#from" do
671
710
  @dataset.from(:abc[:def]).select_sql.should ==
672
711
  "SELECT * FROM abc(def)"
673
712
 
674
- @dataset.from(:a|:i).select_sql.should ==
675
- "SELECT * FROM a[i]"
713
+ @dataset.from(:a[:i]).select_sql.should ==
714
+ "SELECT * FROM a(i)"
676
715
 
677
716
  @dataset.from(:generate_series[1, 2].as(:a[:i])).select_sql.should ==
678
717
  "SELECT * FROM generate_series(1, 2) AS a(i)"
@@ -794,6 +833,17 @@ context "Dataset#order" do
794
833
  end
795
834
  end
796
835
 
836
+ context "Dataset#unfiltered" do
837
+ setup do
838
+ @dataset = Sequel::Dataset.new(nil).from(:test)
839
+ end
840
+
841
+ specify "should remove filtering from the dataset" do
842
+ @dataset.filter(:score=>1).unfiltered.sql.should ==
843
+ 'SELECT * FROM test'
844
+ end
845
+ end
846
+
797
847
  context "Dataset#unordered" do
798
848
  setup do
799
849
  @dataset = Sequel::Dataset.new(nil).from(:test)
@@ -923,6 +973,15 @@ context "Dataset#limit" do
923
973
  @dataset.limit(6, 10).sql.should ==
924
974
  'SELECT * FROM (select * from cccc) t1 LIMIT 6 OFFSET 10'
925
975
  end
976
+
977
+ specify "should raise an error if an invalid limit or offset is used" do
978
+ proc{@dataset.limit(-1)}.should raise_error(Sequel::Error)
979
+ proc{@dataset.limit(0)}.should raise_error(Sequel::Error)
980
+ proc{@dataset.limit(1)}.should_not raise_error(Sequel::Error)
981
+ proc{@dataset.limit(1, -1)}.should raise_error(Sequel::Error)
982
+ proc{@dataset.limit(1, 0)}.should_not raise_error(Sequel::Error)
983
+ proc{@dataset.limit(1, 1)}.should_not raise_error(Sequel::Error)
984
+ end
926
985
  end
927
986
 
928
987
  context "Dataset#naked" do
@@ -947,14 +1006,18 @@ context "Dataset#qualified_column_name" do
947
1006
  @dataset = Sequel::Dataset.new(nil).from(:test)
948
1007
  end
949
1008
 
950
- specify "should return the same if already qualified" do
951
- @dataset.send(:qualified_column_name, 'test.a'.lit, :items).should == 'test.a'
952
- @dataset.send(:qualified_column_name, :ccc__b, :items).should == :ccc__b
1009
+ specify "should return the literal value if not given a symbol" do
1010
+ @dataset.literal(@dataset.send(:qualified_column_name, 'ccc__b', :items)).should == "'ccc__b'"
1011
+ @dataset.literal(@dataset.send(:qualified_column_name, 3, :items)).should == '3'
1012
+ @dataset.literal(@dataset.send(:qualified_column_name, 'a'.lit, :items)).should == 'a'
953
1013
  end
954
1014
 
955
- specify "should qualify the column with the supplied table name" do
956
- @dataset.send(:qualified_column_name, 'a'.lit, :items).to_s(@dataset).should == 'items.a'
957
- @dataset.send(:qualified_column_name, :b1, :items).to_s(@dataset).should == 'items.b1'
1015
+ specify "should qualify the column with the supplied table name if given an unqualified symbol" do
1016
+ @dataset.literal(@dataset.send(:qualified_column_name, :b1, :items)).should == 'items.b1'
1017
+ end
1018
+
1019
+ specify "should not changed the qualifed column's table if given a qualified symbol" do
1020
+ @dataset.literal(@dataset.send(:qualified_column_name, :ccc__b, :items)).should == 'ccc.b'
958
1021
  end
959
1022
  end
960
1023
 
@@ -983,7 +1046,7 @@ context "Dataset#map" do
983
1046
  end
984
1047
 
985
1048
  specify "should return the complete dataset values if nothing is given" do
986
- @d.map.should == DummyDataset::VALUES
1049
+ @d.map.to_a.should == DummyDataset::VALUES
987
1050
  end
988
1051
  end
989
1052
 
@@ -1035,7 +1098,7 @@ context "Dataset#count" do
1035
1098
 
1036
1099
  specify "should format SQL properly" do
1037
1100
  @dataset.count.should == 1
1038
- @c.sql.should == 'SELECT COUNT(*) FROM test'
1101
+ @c.sql.should == 'SELECT COUNT(*) FROM test LIMIT 1'
1039
1102
  end
1040
1103
 
1041
1104
  specify "should be aliased by #size" do
@@ -1043,14 +1106,14 @@ context "Dataset#count" do
1043
1106
  end
1044
1107
 
1045
1108
  specify "should include the where clause if it's there" do
1046
- @dataset.filter {:abc < 30}.count.should == 1
1047
- @c.sql.should == 'SELECT COUNT(*) FROM test WHERE (abc < 30)'
1109
+ @dataset.filter(:abc < 30).count.should == 1
1110
+ @c.sql.should == 'SELECT COUNT(*) FROM test WHERE (abc < 30) LIMIT 1'
1048
1111
  end
1049
1112
 
1050
1113
  specify "should count properly for datasets with fixed sql" do
1051
1114
  @dataset.opts[:sql] = "select abc from xyz"
1052
1115
  @dataset.count.should == 1
1053
- @c.sql.should == "SELECT COUNT(*) FROM (select abc from xyz) t1"
1116
+ @c.sql.should == "SELECT COUNT(*) FROM (select abc from xyz) t1 LIMIT 1"
1054
1117
  end
1055
1118
  end
1056
1119
 
@@ -1106,7 +1169,7 @@ context "Dataset#empty?" do
1106
1169
  @dataset = Sequel::Dataset.new(@db).from(:test)
1107
1170
 
1108
1171
  @dataset.should_not be_empty
1109
- @db.sqls.last.should == 'SELECT 1 WHERE EXISTS (SELECT * FROM test)'
1172
+ @db.sqls.last.should == 'SELECT 1 WHERE (EXISTS (SELECT * FROM test)) LIMIT 1'
1110
1173
 
1111
1174
  @db.meta_def(:dataset) do
1112
1175
  ds = $cccc.new(self)
@@ -1121,26 +1184,32 @@ end
1121
1184
  context "Dataset#join_table" do
1122
1185
  setup do
1123
1186
  @d = Sequel::Dataset.new(nil).from(:items)
1187
+ @d.quote_identifiers = true
1124
1188
  end
1125
1189
 
1126
1190
  specify "should format the JOIN clause properly" do
1127
1191
  @d.join_table(:left_outer, :categories, :category_id => :id).sql.should ==
1128
- 'SELECT * FROM items LEFT OUTER JOIN categories ON (categories.category_id = items.id)'
1192
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1193
+ end
1194
+
1195
+ specify "should handle multiple conditions on the same join table column" do
1196
+ @d.join_table(:left_outer, :categories, [[:category_id, :id], [:category_id, 0..100]]).sql.should ==
1197
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON (("categories"."category_id" = "items"."id") AND (("categories"."category_id" >= 0) AND ("categories"."category_id" <= 100)))'
1129
1198
  end
1130
1199
 
1131
1200
  specify "should include WHERE clause if applicable" do
1132
- @d.filter {:price < 100}.join_table(:right_outer, :categories, :category_id => :id).sql.should ==
1133
- 'SELECT * FROM items RIGHT OUTER JOIN categories ON (categories.category_id = items.id) WHERE (price < 100)'
1201
+ @d.filter(:price < 100).join_table(:right_outer, :categories, :category_id => :id).sql.should ==
1202
+ 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") WHERE ("price" < 100)'
1134
1203
  end
1135
1204
 
1136
1205
  specify "should include ORDER BY clause if applicable" do
1137
1206
  @d.order(:stamp).join_table(:full_outer, :categories, :category_id => :id).sql.should ==
1138
- 'SELECT * FROM items FULL OUTER JOIN categories ON (categories.category_id = items.id) ORDER BY stamp'
1207
+ 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id") ORDER BY "stamp"'
1139
1208
  end
1140
1209
 
1141
1210
  specify "should support multiple joins" do
1142
1211
  @d.join_table(:inner, :b, :items_id).join_table(:left_outer, :c, :b_id => :b__id).sql.should ==
1143
- 'SELECT * FROM items INNER JOIN b ON (b.items_id = items.id) LEFT OUTER JOIN c ON (c.b_id = b.id)'
1212
+ 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
1144
1213
  end
1145
1214
 
1146
1215
  specify "should use id as implicit relation primary key if omitted" do
@@ -1149,47 +1218,47 @@ context "Dataset#join_table" do
1149
1218
 
1150
1219
  # when doing multiple joins, id should be qualified using the last joined table
1151
1220
  @d.join_table(:right_outer, :b, :items_id).join_table(:full_outer, :c, :b_id).sql.should ==
1152
- 'SELECT * FROM items RIGHT OUTER JOIN b ON (b.items_id = items.id) FULL OUTER JOIN c ON (c.b_id = b.id)'
1221
+ 'SELECT * FROM "items" RIGHT OUTER JOIN "b" ON ("b"."items_id" = "items"."id") FULL OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
1153
1222
  end
1154
1223
 
1155
1224
  specify "should support left outer joins" do
1156
1225
  @d.join_table(:left_outer, :categories, :category_id).sql.should ==
1157
- 'SELECT * FROM items LEFT OUTER JOIN categories ON (categories.category_id = items.id)'
1226
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1158
1227
 
1159
1228
  @d.left_outer_join(:categories, :category_id).sql.should ==
1160
- 'SELECT * FROM items LEFT OUTER JOIN categories ON (categories.category_id = items.id)'
1229
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1161
1230
  end
1162
1231
 
1163
1232
  specify "should support right outer joins" do
1164
1233
  @d.join_table(:right_outer, :categories, :category_id).sql.should ==
1165
- 'SELECT * FROM items RIGHT OUTER JOIN categories ON (categories.category_id = items.id)'
1234
+ 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1166
1235
 
1167
1236
  @d.right_outer_join(:categories, :category_id).sql.should ==
1168
- 'SELECT * FROM items RIGHT OUTER JOIN categories ON (categories.category_id = items.id)'
1237
+ 'SELECT * FROM "items" RIGHT OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1169
1238
  end
1170
1239
 
1171
1240
  specify "should support full outer joins" do
1172
1241
  @d.join_table(:full_outer, :categories, :category_id).sql.should ==
1173
- 'SELECT * FROM items FULL OUTER JOIN categories ON (categories.category_id = items.id)'
1242
+ 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1174
1243
 
1175
1244
  @d.full_outer_join(:categories, :category_id).sql.should ==
1176
- 'SELECT * FROM items FULL OUTER JOIN categories ON (categories.category_id = items.id)'
1245
+ 'SELECT * FROM "items" FULL OUTER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1177
1246
  end
1178
1247
 
1179
1248
  specify "should support inner joins" do
1180
1249
  @d.join_table(:inner, :categories, :category_id).sql.should ==
1181
- 'SELECT * FROM items INNER JOIN categories ON (categories.category_id = items.id)'
1250
+ 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1182
1251
 
1183
1252
  @d.inner_join(:categories, :category_id).sql.should ==
1184
- 'SELECT * FROM items INNER JOIN categories ON (categories.category_id = items.id)'
1253
+ 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1185
1254
  end
1186
1255
 
1187
1256
  specify "should default to an inner join" do
1188
1257
  @d.join_table(nil, :categories, :category_id).sql.should ==
1189
- 'SELECT * FROM items INNER JOIN categories ON (categories.category_id = items.id)'
1258
+ 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1190
1259
 
1191
1260
  @d.join(:categories, :category_id).sql.should ==
1192
- 'SELECT * FROM items INNER JOIN categories ON (categories.category_id = items.id)'
1261
+ 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."category_id" = "items"."id")'
1193
1262
  end
1194
1263
 
1195
1264
  specify "should raise if an invalid join type is specified" do
@@ -1197,27 +1266,28 @@ context "Dataset#join_table" do
1197
1266
  end
1198
1267
 
1199
1268
  specify "should support aliased tables" do
1200
- @d.from('stats s').join('players p', :id => :player_id).sql.should ==
1201
- 'SELECT * FROM stats s INNER JOIN players p ON (p.id = s.player_id)'
1269
+ @d.from('stats').join('players', {:id => :player_id}, 'p').sql.should ==
1270
+ 'SELECT * FROM "stats" INNER JOIN "players" "p" ON ("p"."id" = "stats"."player_id")'
1202
1271
 
1203
- ds = Sequel::Dataset.new(nil).from(:foo => :f). \
1204
- join_table(:inner, :bar, :id => :bar_id).sql.should ==
1205
- 'SELECT * FROM foo f INNER JOIN bar ON (bar.id = f.bar_id)'
1272
+ ds = Sequel::Dataset.new(nil).from(:foo => :f)
1273
+ ds.quote_identifiers = true
1274
+ ds.join_table(:inner, :bar, :id => :bar_id).sql.should ==
1275
+ 'SELECT * FROM "foo" "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
1206
1276
  end
1207
1277
 
1208
1278
  specify "should allow for arbitrary conditions in the JOIN clause" do
1209
1279
  @d.join_table(:left_outer, :categories, :status => 0).sql.should ==
1210
- 'SELECT * FROM items LEFT OUTER JOIN categories ON (categories.status = 0)'
1280
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
1211
1281
  @d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should ==
1212
- "SELECT * FROM items LEFT OUTER JOIN categories ON (categories.categorizable_type = 'Post')"
1282
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
1213
1283
  @d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should ==
1214
- "SELECT * FROM items LEFT OUTER JOIN categories ON (categories.timestamp = CURRENT_TIMESTAMP)"
1284
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."timestamp" = CURRENT_TIMESTAMP)'
1215
1285
  @d.join_table(:left_outer, :categories, :status => [1, 2, 3]).sql.should ==
1216
- "SELECT * FROM items LEFT OUTER JOIN categories ON (categories.status IN (1, 2, 3))"
1286
+ 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" IN (1, 2, 3))'
1217
1287
  end
1218
1288
 
1219
1289
  specify "should raise error for a table without a source" do
1220
- proc {Sequel::Dataset.new(nil).join('players p', :id => :player_id)}. \
1290
+ proc {Sequel::Dataset.new(nil).join('players', :id => :player_id)}. \
1221
1291
  should raise_error(Sequel::Error)
1222
1292
  end
1223
1293
 
@@ -1225,12 +1295,12 @@ context "Dataset#join_table" do
1225
1295
  ds = Sequel::Dataset.new(nil).from(:categories)
1226
1296
 
1227
1297
  @d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
1228
- 'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories) t1 ON (t1.item_id = items.id)'
1298
+ 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) "t1" ON ("t1"."item_id" = "items"."id")'
1229
1299
 
1230
1300
  ds.filter!(:active => true)
1231
1301
 
1232
1302
  @d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
1233
- 'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories WHERE (active = \'t\')) t1 ON (t1.item_id = items.id)'
1303
+ 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active = \'t\')) "t1" ON ("t1"."item_id" = "items"."id")'
1234
1304
  end
1235
1305
 
1236
1306
  specify "should support joining multiple datasets" do
@@ -1239,9 +1309,9 @@ context "Dataset#join_table" do
1239
1309
  ds3 = Sequel::Dataset.new(nil).from(:attributes).filter("name = 'blah'")
1240
1310
 
1241
1311
  @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 ==
1242
- 'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories) t1 ON (t1.item_id = items.id) ' \
1243
- 'INNER JOIN (SELECT name FROM nodes) t2 ON (t2.node_id = t1.id) ' \
1244
- "RIGHT OUTER JOIN (SELECT * FROM attributes WHERE name = 'blah') t3 ON (t3.attribute_id = t2.id)"
1312
+ 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) "t1" ON ("t1"."item_id" = "items"."id") ' \
1313
+ 'INNER JOIN (SELECT name FROM nodes) "t2" ON ("t2"."node_id" = "t1"."id") ' \
1314
+ 'RIGHT OUTER JOIN (SELECT * FROM attributes WHERE (name = \'blah\')) "t3" ON ("t3"."attribute_id" = "t2"."id")'
1245
1315
  end
1246
1316
 
1247
1317
  specify "should support joining objects that respond to :table_name" do
@@ -1249,7 +1319,7 @@ context "Dataset#join_table" do
1249
1319
  def ds.table_name; :categories end
1250
1320
 
1251
1321
  @d.join(ds, :item_id => :id).sql.should ==
1252
- 'SELECT * FROM items INNER JOIN categories ON (categories.item_id = items.id)'
1322
+ 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."item_id" = "items"."id")'
1253
1323
  end
1254
1324
  end
1255
1325
 
@@ -1292,11 +1362,13 @@ context "Dataset#set" do
1292
1362
  specify "should act as alias to #update" do
1293
1363
  @d.set({:x => 3})
1294
1364
  @d.last_sql.should == 'UPDATE items SET x = 3'
1365
+ end
1295
1366
 
1296
- @d.set {:x << :x + 1}
1367
+ pt_specify "should accept a block" do
1368
+ @d.set{:x << :x + 1}
1297
1369
  @d.last_sql.should == 'UPDATE items SET x = (x + 1)'
1298
1370
 
1299
- @d.set {(:x|1) << (:x|2) + 1}
1371
+ @d.set{(:x|1) << (:x|2) + 1}
1300
1372
  @d.last_sql.should == 'UPDATE items SET x[1] = (x[2] + 1)'
1301
1373
  end
1302
1374
  end
@@ -1338,23 +1410,23 @@ context "Dataset aggregate methods" do
1338
1410
  end
1339
1411
 
1340
1412
  specify "should include min" do
1341
- @d.min(:a).should == 'SELECT min(a) AS v FROM test'
1413
+ @d.min(:a).should == 'SELECT min(a) FROM test LIMIT 1'
1342
1414
  end
1343
1415
 
1344
1416
  specify "should include max" do
1345
- @d.max(:b).should == 'SELECT max(b) AS v FROM test'
1417
+ @d.max(:b).should == 'SELECT max(b) FROM test LIMIT 1'
1346
1418
  end
1347
1419
 
1348
1420
  specify "should include sum" do
1349
- @d.sum(:c).should == 'SELECT sum(c) AS v FROM test'
1421
+ @d.sum(:c).should == 'SELECT sum(c) FROM test LIMIT 1'
1350
1422
  end
1351
1423
 
1352
1424
  specify "should include avg" do
1353
- @d.avg(:d).should == 'SELECT avg(d) AS v FROM test'
1425
+ @d.avg(:d).should == 'SELECT avg(d) FROM test LIMIT 1'
1354
1426
  end
1355
1427
 
1356
1428
  specify "should accept qualified columns" do
1357
- @d.avg(:test__bc).should == 'SELECT avg(test.bc) AS v FROM test'
1429
+ @d.avg(:test__bc).should == 'SELECT avg(test.bc) FROM test LIMIT 1'
1358
1430
  end
1359
1431
  end
1360
1432
 
@@ -1377,17 +1449,16 @@ context "Dataset#range" do
1377
1449
  @d.range(:stamp)
1378
1450
  @d.last_sql.should == "SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"
1379
1451
 
1380
- @d.filter {:price > 100}.range(:stamp)
1452
+ @d.filter(:price > 100).range(:stamp)
1381
1453
  @d.last_sql.should == "SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"
1382
1454
  end
1383
1455
 
1384
1456
  specify "should return a range object" do
1385
1457
  @d.range(:tryme).should == (1..10)
1386
- @d.last_sql.should == "SELECT min(tryme) AS v1, max(tryme) AS v2 FROM test LIMIT 1"
1387
1458
  end
1388
1459
  end
1389
1460
 
1390
- context "Dataset#range" do
1461
+ context "Dataset#interval" do
1391
1462
  setup do
1392
1463
  c = Class.new(Sequel::Dataset) do
1393
1464
  @@sql = nil
@@ -1404,147 +1475,77 @@ context "Dataset#range" do
1404
1475
 
1405
1476
  specify "should generate a correct SQL statement" do
1406
1477
  @d.interval(:stamp)
1407
- @d.last_sql.should == "SELECT (max(stamp) - min(stamp)) AS v FROM test LIMIT 1"
1478
+ @d.last_sql.should == "SELECT (max(stamp) - min(stamp)) FROM test LIMIT 1"
1408
1479
 
1409
- @d.filter {:price > 100}.interval(:stamp)
1410
- @d.last_sql.should == "SELECT (max(stamp) - min(stamp)) AS v FROM test WHERE (price > 100) LIMIT 1"
1480
+ @d.filter(:price > 100).interval(:stamp)
1481
+ @d.last_sql.should == "SELECT (max(stamp) - min(stamp)) FROM test WHERE (price > 100) LIMIT 1"
1411
1482
  end
1412
1483
 
1413
- specify "should return a range object" do
1484
+ specify "should return an integer" do
1414
1485
  @d.interval(:tryme).should == 1234
1415
- @d.last_sql.should == "SELECT (max(tryme) - min(tryme)) AS v FROM test LIMIT 1"
1416
1486
  end
1417
1487
  end
1418
1488
 
1419
- context "Dataset#first" do
1489
+ context "Dataset #first and #last" do
1420
1490
  setup do
1421
1491
  @c = Class.new(Sequel::Dataset) do
1422
- @@last_dataset = nil
1423
- @@last_opts = nil
1424
-
1425
- def self.last_dataset
1426
- @@last_dataset
1427
- end
1428
-
1429
- def self.last_opts
1430
- @@last_opts
1431
- end
1432
-
1433
- def single_record(opts = nil)
1434
- @@last_opts = @opts.merge(opts || {})
1435
- {:a => 1, :b => 2}
1436
- end
1437
-
1438
- def all
1439
- @@last_dataset = self
1440
- [{:a => 1, :b => 2}] * @opts[:limit]
1492
+ def each(opts = nil, &block)
1493
+ s = select_sql(opts)
1494
+ x = [:a,1,:b,2,s]
1495
+ i = /LIMIT (\d+)/.match(s)[1].to_i.times{yield x}
1441
1496
  end
1442
1497
  end
1443
1498
  @d = @c.new(nil).from(:test)
1444
1499
  end
1445
1500
 
1446
- specify "should return the first matching record if a hash is specified" do
1447
- @d.first(:z => 26).should == {:a => 1, :b => 2}
1448
- @c.last_opts[:where].should == ('(z = 26)')
1501
+ specify "should return a single record if no argument is given" do
1502
+ @d.order(:a).first.should == [:a,1,:b,2, 'SELECT * FROM test ORDER BY a LIMIT 1']
1503
+ @d.order(:a).last.should == [:a,1,:b,2, 'SELECT * FROM test ORDER BY a DESC LIMIT 1']
1504
+ end
1449
1505
 
1450
- @d.first('z = ?', 15)
1451
- @c.last_opts[:where].should == ('z = 15')
1506
+ specify "should return the first/last matching record if argument is not an Integer" do
1507
+ @d.order(:a).first(:z => 26).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1']
1508
+ @d.order(:a).first('z = ?', 15).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1']
1509
+ @d.order(:a).last(:z => 26).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1']
1510
+ @d.order(:a).last('z = ?', 15).should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1']
1452
1511
  end
1453
1512
 
1454
- specify "should return the first matching record if a block is given" do
1455
- @d.first {:z > 26}.should == {:a => 1, :b => 2}
1456
- @c.last_opts[:where].should == ('(z > 26)')
1513
+ specify "should set the limit and return an array of records if the given number is > 1" do
1514
+ i = rand(10) + 10
1515
+ r = @d.order(:a).first(i).should == [[:a,1,:b,2, "SELECT * FROM test ORDER BY a LIMIT #{i}"]] * i
1516
+ i = rand(10) + 10
1517
+ r = @d.order(:a).last(i).should == [[:a,1,:b,2, "SELECT * FROM test ORDER BY a DESC LIMIT #{i}"]] * i
1457
1518
  end
1458
1519
 
1459
- specify "should return a single record if no argument is given" do
1460
- @d.first.should == {:a => 1, :b => 2}
1520
+ pt_specify "should return the first matching record if a block is given without an argument" do
1521
+ @d.first{:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) LIMIT 1']
1522
+ @d.order(:name).last{:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1']
1461
1523
  end
1462
1524
 
1463
- specify "should set the limit according to the given number" do
1464
- @d.first
1465
- @c.last_opts[:limit].should == 1
1466
-
1467
- i = rand(10) + 10
1468
- @d.first(i)
1469
- @c.last_dataset.opts[:limit].should == i
1525
+ pt_specify "should combine block and standard argument filters if argument is not an Integer" do
1526
+ @d.first(:y=>25){:z > 26}.should == [:a,1,:b,2, 'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1']
1527
+ @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']
1470
1528
  end
1471
1529
 
1472
- specify "should return an array with the records if argument is greater than 1" do
1530
+ pt_specify "should filter and return an array of records if an Integer argument is provided and a block is given" do
1473
1531
  i = rand(10) + 10
1474
- r = @d.first(i)
1475
- r.should be_a_kind_of(Array)
1476
- r.size.should == i
1477
- r.each {|row| row.should == {:a => 1, :b => 2}}
1478
- end
1479
- end
1480
-
1481
- context "Dataset#last" do
1482
- setup do
1483
- @c = Class.new(Sequel::Dataset) do
1484
- @@last_dataset = nil
1485
-
1486
- def self.last_dataset
1487
- @@last_dataset
1488
- end
1489
-
1490
- def single_record(opts = nil)
1491
- @@last_dataset = clone(opts) if opts
1492
- {:a => 1, :b => 2}
1493
- end
1494
-
1495
- def all
1496
- @@last_dataset = self
1497
- [{:a => 1, :b => 2}] * @opts[:limit]
1498
- end
1499
- end
1500
- @d = @c.new(nil).from(:test)
1532
+ 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
1533
+ i = rand(10) + 10
1534
+ 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
1501
1535
  end
1502
1536
 
1503
- specify "should raise if no order is given" do
1537
+ specify "#last should raise if no order is given" do
1504
1538
  proc {@d.last}.should raise_error(Sequel::Error)
1505
1539
  proc {@d.last(2)}.should raise_error(Sequel::Error)
1506
1540
  proc {@d.order(:a).last}.should_not raise_error
1507
1541
  proc {@d.order(:a).last(2)}.should_not raise_error
1508
1542
  end
1509
1543
 
1510
- specify "should invert the order" do
1511
- @d.order(:a).last
1512
- @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:a.desc])
1513
-
1514
- @d.order(:b.desc).last
1515
- @d.literal(@c.last_dataset.opts[:order]).should == @d.literal(:b)
1516
-
1517
- @d.order(:c, :d).last
1518
- @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:c.desc, :d.desc])
1519
-
1520
- @d.order(:e.desc, :f).last
1521
- @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:e, :f.desc])
1522
- end
1523
-
1524
- specify "should return the first matching record if a hash is specified" do
1525
- @d.order(:a).last(:z => 26).should == {:a => 1, :b => 2}
1526
- @c.last_dataset.opts[:where].should == ('(z = 26)')
1527
-
1528
- @d.order(:a).last('z = ?', 15)
1529
- @c.last_dataset.opts[:where].should == ('z = 15')
1530
- end
1531
-
1532
- specify "should return a single record if no argument is given" do
1533
- @d.order(:a).last.should == {:a => 1, :b => 2}
1534
- end
1535
-
1536
- specify "should set the limit according to the given number" do
1537
- i = rand(10) + 10
1538
- r = @d.order(:a).last(i)
1539
- @c.last_dataset.opts[:limit].should == i
1540
- end
1541
-
1542
- specify "should return an array with the records if argument is greater than 1" do
1543
- i = rand(10) + 10
1544
- r = @d.order(:a).last(i)
1545
- r.should be_a_kind_of(Array)
1546
- r.size.should == i
1547
- r.each {|row| row.should == {:a => 1, :b => 2}}
1544
+ specify "#last should invert the order" do
1545
+ @d.order(:a).last.pop.should == 'SELECT * FROM test ORDER BY a DESC LIMIT 1'
1546
+ @d.order(:b.desc).last.pop.should == 'SELECT * FROM test ORDER BY b LIMIT 1'
1547
+ @d.order(:c, :d).last.pop.should == 'SELECT * FROM test ORDER BY c DESC, d DESC LIMIT 1'
1548
+ @d.order(:e.desc, :f).last.pop.should == 'SELECT * FROM test ORDER BY e, f DESC LIMIT 1'
1548
1549
  end
1549
1550
  end
1550
1551
 
@@ -1595,10 +1596,10 @@ context "Dataset#[]" do
1595
1596
 
1596
1597
  specify "should return a single record filtered according to the given conditions" do
1597
1598
  @d[:name => 'didi'].should == {1 => 2, 3 => 4}
1598
- @c.last_dataset.opts[:where].should == "(name = 'didi')"
1599
+ @c.last_dataset.literal(@c.last_dataset.opts[:where]).should == "(name = 'didi')"
1599
1600
 
1600
1601
  @d[:id => 5..45].should == {1 => 2, 3 => 4}
1601
- @c.last_dataset.opts[:where].should == "(id >= 5 AND id <= 45)"
1602
+ @c.last_dataset.literal(@c.last_dataset.opts[:where]).should == "((id >= 5) AND (id <= 45))"
1602
1603
  end
1603
1604
  end
1604
1605
 
@@ -1617,14 +1618,18 @@ context "Dataset#single_record" do
1617
1618
  @e = @cc.new(nil).from(:test)
1618
1619
  end
1619
1620
 
1620
- specify "should call each and return the first record" do
1621
- @d.single_record.should == 'SELECT * FROM test'
1621
+ specify "should call each with a limit of 1 and return the record" do
1622
+ @d.single_record.should == 'SELECT * FROM test LIMIT 1'
1622
1623
  end
1623
1624
 
1624
1625
  specify "should pass opts to each" do
1625
- @d.single_record(:limit => 3).should == 'SELECT * FROM test LIMIT 3'
1626
+ @d.single_record(:order => [:name]).should == 'SELECT * FROM test ORDER BY name LIMIT 1'
1626
1627
  end
1627
1628
 
1629
+ specify "should override the limit if passed as an option" do
1630
+ @d.single_record(:limit => 3).should == 'SELECT * FROM test LIMIT 1'
1631
+ end
1632
+
1628
1633
  specify "should return nil if no record is present" do
1629
1634
  @e.single_record.should be_nil
1630
1635
  end
@@ -1646,14 +1651,14 @@ context "Dataset#single_value" do
1646
1651
  end
1647
1652
 
1648
1653
  specify "should call each and return the first value of the first record" do
1649
- @d.single_value.should == 'SELECT * FROM test'
1654
+ @d.single_value.should == 'SELECT * FROM test LIMIT 1'
1650
1655
  end
1651
1656
 
1652
1657
  specify "should pass opts to each" do
1653
- @d.single_value(:limit => 3).should == 'SELECT * FROM test LIMIT 3'
1658
+ @d.single_value(:from => [:blah]).should == 'SELECT * FROM blah LIMIT 1'
1654
1659
  end
1655
1660
 
1656
- specify "should return nil" do
1661
+ specify "should return nil if no records" do
1657
1662
  @e.single_value.should be_nil
1658
1663
  end
1659
1664
  end
@@ -1673,16 +1678,16 @@ context "Dataset#get" do
1673
1678
  end
1674
1679
 
1675
1680
  specify "should select the specified column and fetch its value" do
1676
- @d.get(:name).should == "SELECT name FROM test"
1677
- @d.get(:abc).should == "SELECT abc FROM test" # the first available value is returned always
1681
+ @d.get(:name).should == "SELECT name FROM test LIMIT 1"
1682
+ @d.get(:abc).should == "SELECT abc FROM test LIMIT 1" # the first available value is returned always
1678
1683
  end
1679
1684
 
1680
1685
  specify "should work with filters" do
1681
- @d.filter(:id => 1).get(:name).should == "SELECT name FROM test WHERE (id = 1)"
1686
+ @d.filter(:id => 1).get(:name).should == "SELECT name FROM test WHERE (id = 1) LIMIT 1"
1682
1687
  end
1683
1688
 
1684
1689
  specify "should work with aliased fields" do
1685
- @d.get(:x__b.as(:name)).should == "SELECT x.b AS name FROM test"
1690
+ @d.get(:x__b.as(:name)).should == "SELECT x.b AS name FROM test LIMIT 1"
1686
1691
  end
1687
1692
  end
1688
1693
 
@@ -1749,12 +1754,6 @@ context "Dataset#set_model" do
1749
1754
  @dataset.first.should == @m.new({:kind => 1})
1750
1755
  end
1751
1756
 
1752
- specify "should extend the dataset with a #destroy method" do
1753
- @dataset.should_not respond_to(:destroy)
1754
- @dataset.set_model(@m)
1755
- @dataset.should respond_to(:destroy)
1756
- end
1757
-
1758
1757
  specify "should set opts[:naked] to nil" do
1759
1758
  @dataset.opts[:naked] = true
1760
1759
  @dataset.set_model(@m)
@@ -1964,58 +1963,10 @@ context "A dataset with associated model class(es)" do
1964
1963
  end
1965
1964
  end
1966
1965
 
1967
- context "Dataset#destroy" do
1968
- setup do
1969
- db = Object.new
1970
- m = Module.new do
1971
- def transaction; yield; end
1972
- end
1973
- db.extend(m)
1974
-
1975
- $DESTROYED = []
1976
-
1977
- @m = Class.new do
1978
- def initialize(c)
1979
- @c = c
1980
- end
1981
-
1982
- attr_accessor :c
1983
-
1984
- def ==(o)
1985
- @c == o.c
1986
- end
1987
-
1988
- def destroy
1989
- $DESTROYED << self
1990
- end
1991
- end
1992
- $MODELS = [@m.new(12), @m.new(13)]
1993
-
1994
- c = Class.new(Sequel::Dataset) do
1995
- def fetch_rows(sql, &block)
1996
- (12..13).each(&block)
1997
- end
1998
- end
1999
-
2000
- @d = c.new(db).from(:test)
2001
- @d.set_model(@m)
2002
- end
2003
-
2004
- specify "should call destroy for every model instance in the dataset" do
2005
- count = @d.destroy
2006
- count.should == 2
2007
- $DESTROYED.should == $MODELS
2008
- end
2009
-
2010
- specify "should raise error if no models are associated with the dataset" do
2011
- proc {@d.naked.destroy}.should raise_error(Sequel::Error)
2012
- end
2013
- end
2014
-
2015
1966
  context "Dataset#<<" do
2016
1967
  setup do
2017
1968
  @d = Sequel::Dataset.new(nil)
2018
- @d.meta_def(:insert) do
1969
+ @d.meta_def(:insert) do |*args|
2019
1970
  1234567890
2020
1971
  end
2021
1972
  end
@@ -2080,7 +2031,20 @@ context "A paginated dataset" do
2080
2031
  @d.paginate(4, 50).current_page_record_count.should == 3
2081
2032
  @d.paginate(5, 50).current_page_record_count.should == 0
2082
2033
  end
2083
-
2034
+
2035
+ specify "should know if current page is last page" do
2036
+ @paginated.last_page?.should be_false
2037
+ @d.paginate(2, 20).last_page?.should be_false
2038
+ @d.paginate(5, 30).last_page?.should be_false
2039
+ @d.paginate(6, 30).last_page?.should be_true
2040
+ end
2041
+
2042
+ specify "should know if current page is first page" do
2043
+ @paginated.first_page?.should be_true
2044
+ @d.paginate(1, 20).first_page?.should be_true
2045
+ @d.paginate(2, 20).first_page?.should be_false
2046
+ end
2047
+
2084
2048
  specify "should work with fixed sql" do
2085
2049
  ds = @d.clone(:sql => 'select * from blah')
2086
2050
  ds.meta_def(:count) {150}
@@ -2114,34 +2078,35 @@ context "Dataset#columns" do
2114
2078
  setup do
2115
2079
  @dataset = DummyDataset.new(nil).from(:items)
2116
2080
  @dataset.meta_def(:columns=) {|c| @columns = c}
2117
- @dataset.meta_def(:first) {@columns = select_sql(nil)}
2081
+ i = 'a'
2082
+ @dataset.meta_def(:each) {|o| @columns = select_sql(o||@opts) + i; i = i.next}
2118
2083
  end
2119
2084
 
2120
- specify "should return the value of @columns" do
2085
+ specify "should return the value of @columns if @columns is not nil" do
2121
2086
  @dataset.columns = [:a, :b, :c]
2122
2087
  @dataset.columns.should == [:a, :b, :c]
2123
2088
  end
2124
2089
 
2125
- specify "should call first if @columns is nil" do
2090
+ specify "should attempt to get a single record and return @columns if @columns is nil" do
2126
2091
  @dataset.columns = nil
2127
- @dataset.columns.should == 'SELECT * FROM items'
2092
+ @dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
2128
2093
  @dataset.opts[:from] = [:nana]
2129
- @dataset.columns.should == 'SELECT * FROM items'
2094
+ @dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
2130
2095
  end
2131
2096
  end
2132
2097
 
2133
2098
  context "Dataset#columns!" do
2134
2099
  setup do
2135
2100
  @dataset = DummyDataset.new(nil).from(:items)
2136
- @dataset.meta_def(:columns=) {|c| @columns = c}
2137
- @dataset.meta_def(:first) {@columns = select_sql(nil)}
2101
+ i = 'a'
2102
+ @dataset.meta_def(:each) {|o| @columns = select_sql(o||@opts) + i; i = i.next}
2138
2103
  end
2139
2104
 
2140
- specify "should always call first" do
2141
- @dataset.columns = nil
2142
- @dataset.columns!.should == 'SELECT * FROM items'
2105
+ specify "should always attempt to get a record and return @columns" do
2106
+ @dataset.columns!.should == 'SELECT * FROM items LIMIT 1a'
2107
+ @dataset.columns!.should == 'SELECT * FROM items LIMIT 1b'
2143
2108
  @dataset.opts[:from] = [:nana]
2144
- @dataset.columns!.should == 'SELECT * FROM nana'
2109
+ @dataset.columns!.should == 'SELECT * FROM nana LIMIT 1c'
2145
2110
  end
2146
2111
  end
2147
2112
 
@@ -2336,13 +2301,13 @@ context "Dataset#query" do
2336
2301
  specify "should support #where" do
2337
2302
  q = @d.query do
2338
2303
  from :zzz
2339
- where {:x + 2 > :y + 3}
2304
+ where(:x + 2 > :y + 3)
2340
2305
  end
2341
2306
  q.class.should == @d.class
2342
2307
  q.sql.should == "SELECT * FROM zzz WHERE ((x + 2) > (y + 3))"
2343
2308
 
2344
2309
  q = @d.from(:zzz).query do
2345
- where {:x > 1 && :y > 2}
2310
+ where((:x > 1) & (:y > 2))
2346
2311
  end
2347
2312
  q.class.should == @d.class
2348
2313
  q.sql.should == "SELECT * FROM zzz WHERE ((x > 1) AND (y > 2))"
@@ -2358,7 +2323,7 @@ context "Dataset#query" do
2358
2323
  q = @d.query do
2359
2324
  from :abc
2360
2325
  group_by :id
2361
- having {:x >= 2}
2326
+ having(:x >= 2)
2362
2327
  end
2363
2328
  q.class.should == @d.class
2364
2329
  q.sql.should == "SELECT * FROM abc GROUP BY id HAVING (x >= 2)"
@@ -2374,7 +2339,7 @@ context "Dataset#query" do
2374
2339
  end
2375
2340
 
2376
2341
  specify "should raise on non-chainable method calls" do
2377
- proc {@d.query {count}}.should raise_error(Sequel::Error)
2342
+ proc {@d.query {first_source}}.should raise_error(Sequel::Error)
2378
2343
  end
2379
2344
 
2380
2345
  specify "should raise on each, insert, update, delete" do
@@ -2410,8 +2375,8 @@ context "Dataset" do
2410
2375
  @d.sql.should == "SELECT * FROM x WHERE (y = 1)"
2411
2376
  end
2412
2377
 
2413
- specify "should support self-changing filter! with block" do
2414
- @d.filter! {:y == 2}
2378
+ pt_specify "should support self-changing filter! with block" do
2379
+ @d.filter!{:y == 2}
2415
2380
  @d.sql.should == "SELECT * FROM x WHERE (y = 2)"
2416
2381
  end
2417
2382
 
@@ -2565,27 +2530,27 @@ context "Dataset#transform" do
2565
2530
  specify "should support stock Marshal transformation with Base64 encoding" do
2566
2531
  @ds.transform(:x => :marshal)
2567
2532
 
2568
- @ds.raw = {:x => Base64.encode64(Marshal.dump([1, 2, 3])), :y => 'hello'}
2533
+ @ds.raw = {:x => [Marshal.dump([1, 2, 3])].pack('m'), :y => 'hello'}
2569
2534
  @ds.first.should == {:x => [1, 2, 3], :y => 'hello'}
2570
2535
 
2571
2536
  @ds.insert(:x => :toast)
2572
- @ds.sql.should == "INSERT INTO items (x) VALUES ('#{Base64.encode64(Marshal.dump(:toast))}')"
2537
+ @ds.sql.should == "INSERT INTO items (x) VALUES ('#{[Marshal.dump(:toast)].pack('m')}')"
2573
2538
  @ds.insert(:y => 'butter')
2574
2539
  @ds.sql.should == "INSERT INTO items (y) VALUES ('butter')"
2575
2540
  @ds.update(:x => ['dream'])
2576
- @ds.sql.should == "UPDATE items SET x = '#{Base64.encode64(Marshal.dump(['dream']))}'"
2541
+ @ds.sql.should == "UPDATE items SET x = '#{[Marshal.dump(['dream'])].pack('m')}'"
2577
2542
 
2578
2543
  @ds2 = @ds.filter(:a => 1)
2579
- @ds2.raw = {:x => Base64.encode64(Marshal.dump([1, 2, 3])), :y => 'hello'}
2544
+ @ds2.raw = {:x => [Marshal.dump([1, 2, 3])].pack('m'), :y => 'hello'}
2580
2545
  @ds2.first.should == {:x => [1, 2, 3], :y => 'hello'}
2581
2546
  @ds2.insert(:x => :toast)
2582
- @ds2.sql.should == "INSERT INTO items (x) VALUES ('#{Base64.encode64(Marshal.dump(:toast))}')"
2547
+ @ds2.sql.should == "INSERT INTO items (x) VALUES ('#{[Marshal.dump(:toast)].pack('m')}')"
2583
2548
 
2584
2549
  @ds.row_proc = proc{|r| r[:z] = r[:x] * 2; r}
2585
- @ds.raw = {:x => Base64.encode64(Marshal.dump("wow")), :y => 'hello'}
2550
+ @ds.raw = {:x => [Marshal.dump("wow")].pack('m'), :y => 'hello'}
2586
2551
  @ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
2587
2552
  f = nil
2588
- @ds.raw = {:x => Base64.encode64(Marshal.dump("wow")), :y => 'hello'}
2553
+ @ds.raw = {:x => [Marshal.dump("wow")].pack('m'), :y => 'hello'}
2589
2554
  @ds.each(:naked => true) {|r| f = r}
2590
2555
  f.should == {:x => "wow", :y => 'hello'}
2591
2556
  end
@@ -2611,7 +2576,7 @@ context "A dataset with a transform" do
2611
2576
  specify "should automatically transform hash filters" do
2612
2577
  @ds.filter(:y => 2).sql.should == 'SELECT * FROM items WHERE (y = 2)'
2613
2578
 
2614
- @ds.filter(:x => 2).sql.should == "SELECT * FROM items WHERE (x = '#{Base64.encode64(Marshal.dump(2))}')"
2579
+ @ds.filter(:x => 2).sql.should == "SELECT * FROM items WHERE (x = '#{[Marshal.dump(2)].pack('m')}')"
2615
2580
  end
2616
2581
  end
2617
2582
 
@@ -2647,88 +2612,6 @@ context "Dataset#to_csv" do
2647
2612
  end
2648
2613
  end
2649
2614
 
2650
- ### DEPRECATED
2651
- context "Dataset magic methods" do
2652
- setup do
2653
- @c = Class.new(Sequel::Dataset) do
2654
- @@sqls = []
2655
-
2656
- def self.sqls; @@sqls; end
2657
-
2658
- def fetch_rows(sql)
2659
- @@sqls << sql
2660
- yield({:a => 1, :b => 2})
2661
- end
2662
- end
2663
-
2664
- @ds = @c.new(nil).from(:items)
2665
- end
2666
-
2667
- specify "should support order_by_xxx" do
2668
- @ds.should_not respond_to(:order_by_name)
2669
- proc {@ds.order_by_name}.should_not raise_error
2670
- @ds.should respond_to(:order_by_name)
2671
- @ds.order_by_name.should be_a_kind_of(@c)
2672
- @ds.order_by_name.sql.should == "SELECT * FROM items ORDER BY name"
2673
- end
2674
-
2675
- specify "should support group_by_xxx" do
2676
- @ds.should_not respond_to(:group_by_name)
2677
- proc {@ds.group_by_name}.should_not raise_error
2678
- @ds.should respond_to(:group_by_name)
2679
- @ds.group_by_name.should be_a_kind_of(@c)
2680
- @ds.group_by_name.sql.should == "SELECT * FROM items GROUP BY name"
2681
- end
2682
-
2683
- specify "should support count_by_xxx" do
2684
- @ds.should_not respond_to(:count_by_name)
2685
- proc {@ds.count_by_name}.should_not raise_error
2686
- @ds.should respond_to(:count_by_name)
2687
- @ds.count_by_name.should be_a_kind_of(@c)
2688
- @ds.count_by_name.sql.should == "SELECT name, count(*) AS count FROM items GROUP BY name ORDER BY count"
2689
- end
2690
-
2691
- specify "should support filter_by_xxx" do
2692
- @ds.should_not respond_to(:filter_by_name)
2693
- proc {@ds.filter_by_name('sharon')}.should_not raise_error
2694
- @ds.should respond_to(:filter_by_name)
2695
- @ds.filter_by_name('sharon').should be_a_kind_of(@c)
2696
- @ds.filter_by_name('sharon').sql.should == "SELECT * FROM items WHERE (name = 'sharon')"
2697
- end
2698
-
2699
- specify "should support all_by_xxx" do
2700
- @ds.should_not respond_to(:all_by_name)
2701
- proc {@ds.all_by_name('sharon')}.should_not raise_error
2702
- @ds.should respond_to(:all_by_name)
2703
- @ds.all_by_name('sharon').should == [{:a => 1, :b => 2}]
2704
- @c.sqls.should == ["SELECT * FROM items WHERE (name = 'sharon')"] * 2
2705
- end
2706
-
2707
- specify "should support find_by_xxx" do
2708
- @ds.should_not respond_to(:find_by_name)
2709
- proc {@ds.find_by_name('sharon')}.should_not raise_error
2710
- @ds.should respond_to(:find_by_name)
2711
- @ds.find_by_name('sharon').should == {:a => 1, :b => 2}
2712
- @c.sqls.should == ["SELECT * FROM items WHERE (name = 'sharon') LIMIT 1"] * 2
2713
- end
2714
-
2715
- specify "should support first_by_xxx" do
2716
- @ds.should_not respond_to(:first_by_name)
2717
- proc {@ds.first_by_name('sharon')}.should_not raise_error
2718
- @ds.should respond_to(:first_by_name)
2719
- @ds.first_by_name('sharon').should == {:a => 1, :b => 2}
2720
- @c.sqls.should == ["SELECT * FROM items ORDER BY name LIMIT 1"] * 2
2721
- end
2722
-
2723
- specify "should support last_by_xxx" do
2724
- @ds.should_not respond_to(:last_by_name)
2725
- proc {@ds.last_by_name('sharon')}.should_not raise_error
2726
- @ds.should respond_to(:last_by_name)
2727
- @ds.last_by_name('sharon').should == {:a => 1, :b => 2}
2728
- @c.sqls.should == ["SELECT * FROM items ORDER BY name DESC LIMIT 1"] * 2
2729
- end
2730
- end
2731
-
2732
2615
  context "Dataset#create_view" do
2733
2616
  setup do
2734
2617
  @dbc = Class.new(Sequel::Database) do
@@ -2916,7 +2799,7 @@ context "Dataset#grep" do
2916
2799
 
2917
2800
  specify "should format a SQL filter correctly" do
2918
2801
  @ds.grep(:title, 'ruby').sql.should ==
2919
- "SELECT * FROM posts WHERE (title LIKE 'ruby')"
2802
+ "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
2920
2803
  end
2921
2804
 
2922
2805
  specify "should support multiple columns" do
@@ -2926,30 +2809,19 @@ context "Dataset#grep" do
2926
2809
 
2927
2810
  specify "should support multiple search terms" do
2928
2811
  @ds.grep(:title, ['abc', 'def']).sql.should ==
2929
- "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
2812
+ "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')))"
2930
2813
  end
2931
2814
 
2932
2815
  specify "should support multiple columns and search terms" do
2933
2816
  @ds.grep([:title, :body], ['abc', 'def']).sql.should ==
2934
- "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
2935
- end
2936
-
2937
- specify "should support regexps if the dataset allows it" do
2938
- @ds.meta_def(:match_expr) do |l, r|
2939
- case r
2940
- when String
2941
- "(#{literal(l)} LIKE #{literal(r)})"
2942
- when Regexp
2943
- "(#{literal(l)} =~ #{literal(r.source)})"
2944
- else
2945
- raise Sequel::Error, "Unsupported match pattern class (#{r.class})."
2946
- end
2947
- end
2948
-
2817
+ "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')) OR ((body LIKE 'abc') OR (body LIKE 'def')))"
2818
+ end
2819
+
2820
+ specify "should support regexps though the database may not support it" do
2949
2821
  @ds.grep(:title, /ruby/).sql.should ==
2950
- "SELECT * FROM posts WHERE (title =~ 'ruby')"
2822
+ "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
2951
2823
 
2952
2824
  @ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
2953
- "SELECT * FROM posts WHERE ((title =~ '^ruby') OR (title LIKE 'ruby'))"
2825
+ "SELECT * FROM posts WHERE (((title ~ '^ruby') OR (title LIKE 'ruby')))"
2954
2826
  end
2955
2827
  end