sequel 3.5.0 → 3.6.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.
Files changed (72) hide show
  1. data/CHANGELOG +108 -0
  2. data/README.rdoc +25 -14
  3. data/Rakefile +20 -1
  4. data/doc/advanced_associations.rdoc +61 -64
  5. data/doc/cheat_sheet.rdoc +16 -7
  6. data/doc/opening_databases.rdoc +3 -3
  7. data/doc/prepared_statements.rdoc +1 -1
  8. data/doc/reflection.rdoc +2 -1
  9. data/doc/release_notes/3.6.0.txt +366 -0
  10. data/doc/schema.rdoc +19 -14
  11. data/lib/sequel/adapters/amalgalite.rb +5 -27
  12. data/lib/sequel/adapters/jdbc.rb +13 -3
  13. data/lib/sequel/adapters/jdbc/h2.rb +17 -0
  14. data/lib/sequel/adapters/jdbc/mysql.rb +20 -7
  15. data/lib/sequel/adapters/mysql.rb +4 -3
  16. data/lib/sequel/adapters/oracle.rb +1 -1
  17. data/lib/sequel/adapters/postgres.rb +87 -28
  18. data/lib/sequel/adapters/shared/mssql.rb +47 -6
  19. data/lib/sequel/adapters/shared/mysql.rb +12 -31
  20. data/lib/sequel/adapters/shared/postgres.rb +15 -12
  21. data/lib/sequel/adapters/shared/sqlite.rb +18 -0
  22. data/lib/sequel/adapters/sqlite.rb +1 -16
  23. data/lib/sequel/connection_pool.rb +1 -1
  24. data/lib/sequel/core.rb +1 -1
  25. data/lib/sequel/database.rb +1 -1
  26. data/lib/sequel/database/schema_generator.rb +2 -0
  27. data/lib/sequel/database/schema_sql.rb +1 -1
  28. data/lib/sequel/dataset.rb +5 -179
  29. data/lib/sequel/dataset/actions.rb +123 -0
  30. data/lib/sequel/dataset/convenience.rb +18 -10
  31. data/lib/sequel/dataset/features.rb +65 -0
  32. data/lib/sequel/dataset/prepared_statements.rb +29 -23
  33. data/lib/sequel/dataset/query.rb +429 -0
  34. data/lib/sequel/dataset/sql.rb +67 -435
  35. data/lib/sequel/model/associations.rb +77 -13
  36. data/lib/sequel/model/base.rb +30 -8
  37. data/lib/sequel/model/errors.rb +4 -4
  38. data/lib/sequel/plugins/caching.rb +38 -15
  39. data/lib/sequel/plugins/force_encoding.rb +18 -7
  40. data/lib/sequel/plugins/hook_class_methods.rb +4 -0
  41. data/lib/sequel/plugins/many_through_many.rb +1 -1
  42. data/lib/sequel/plugins/nested_attributes.rb +40 -11
  43. data/lib/sequel/plugins/serialization.rb +17 -3
  44. data/lib/sequel/plugins/validation_helpers.rb +65 -18
  45. data/lib/sequel/sql.rb +23 -1
  46. data/lib/sequel/version.rb +1 -1
  47. data/spec/adapters/mssql_spec.rb +96 -10
  48. data/spec/adapters/mysql_spec.rb +19 -0
  49. data/spec/adapters/postgres_spec.rb +65 -2
  50. data/spec/adapters/sqlite_spec.rb +10 -0
  51. data/spec/core/core_sql_spec.rb +9 -0
  52. data/spec/core/database_spec.rb +8 -4
  53. data/spec/core/dataset_spec.rb +122 -29
  54. data/spec/core/expression_filters_spec.rb +17 -0
  55. data/spec/extensions/caching_spec.rb +43 -3
  56. data/spec/extensions/force_encoding_spec.rb +43 -1
  57. data/spec/extensions/nested_attributes_spec.rb +55 -2
  58. data/spec/extensions/validation_helpers_spec.rb +71 -0
  59. data/spec/integration/associations_test.rb +281 -0
  60. data/spec/integration/dataset_test.rb +383 -9
  61. data/spec/integration/eager_loader_test.rb +0 -65
  62. data/spec/integration/model_test.rb +110 -0
  63. data/spec/integration/plugin_test.rb +306 -0
  64. data/spec/integration/prepared_statement_test.rb +32 -0
  65. data/spec/integration/schema_test.rb +8 -3
  66. data/spec/integration/spec_helper.rb +1 -25
  67. data/spec/model/association_reflection_spec.rb +38 -0
  68. data/spec/model/associations_spec.rb +184 -8
  69. data/spec/model/eager_loading_spec.rb +23 -0
  70. data/spec/model/model_spec.rb +8 -0
  71. data/spec/model/record_spec.rb +84 -1
  72. metadata +9 -2
@@ -25,37 +25,31 @@ describe "Simple Dataset operations" do
25
25
 
26
26
  cspecify "should insert with a primary key specified", :mssql do
27
27
  @ds.insert(:id=>100, :number=>20)
28
- sqls_should_be(/INSERT INTO items \((number, id|id, number)\) VALUES \((100, 20|20, 100)\)/)
29
28
  @ds.count.should == 2
30
29
  @ds.order(:id).all.should == [{:id=>1, :number=>10}, {:id=>100, :number=>20}]
31
30
  end
32
31
 
33
32
  specify "should have insert return primary key value" do
34
33
  @ds.insert(:number=>20).should == 2
35
- sqls_should_be('INSERT INTO items (number) VALUES (20)')
36
34
  @ds.filter(:id=>2).first[:number].should == 20
37
35
  end
38
36
 
39
37
  specify "should delete correctly" do
40
38
  @ds.filter(1=>1).delete.should == 1
41
- sqls_should_be('DELETE FROM items WHERE (1 = 1)')
42
39
  @ds.count.should == 0
43
40
  end
44
41
 
45
42
  specify "should update correctly" do
46
43
  @ds.update(:number=>:number+1).should == 1
47
- sqls_should_be('UPDATE items SET number = (number + 1)')
48
44
  @ds.all.should == [{:id=>1, :number=>11}]
49
45
  end
50
46
 
51
47
  specify "should fetch all results correctly" do
52
48
  @ds.all.should == [{:id=>1, :number=>10}]
53
- sqls_should_be('SELECT * FROM items')
54
49
  end
55
50
 
56
51
  specify "should fetch a single row correctly" do
57
52
  @ds.first.should == {:id=>1, :number=>10}
58
- sqls_should_be('SELECT * FROM items LIMIT 1')
59
53
  end
60
54
 
61
55
  specify "should fetch correctly with a limit" do
@@ -80,7 +74,6 @@ describe "Simple Dataset operations" do
80
74
 
81
75
  specify "should alias columns correctly" do
82
76
  @ds.select(:id___x, :number___n).first.should == {:x=>1, :n=>10}
83
- sqls_should_be("SELECT id AS 'x', number AS 'n' FROM items LIMIT 1")
84
77
  end
85
78
  end
86
79
 
@@ -105,6 +98,20 @@ describe Sequel::Dataset do
105
98
  @d.count.should == 3
106
99
  end
107
100
 
101
+ specify "should handle aggregate methods on limited datasets correctly" do
102
+ @d << {:name => 'abc', :value => 6}
103
+ @d << {:name => 'bcd', :value => 12}
104
+ @d << {:name => 'def', :value => 18}
105
+ @d = @d.order(:name).limit(2)
106
+ @d.count.should == 2
107
+ @d.avg(:value).to_i.should == 9
108
+ @d.min(:value).to_i.should == 6
109
+ @d.reverse.min(:value).to_i.should == 12
110
+ @d.max(:value).to_i.should == 12
111
+ @d.sum(:value).to_i.should == 18
112
+ @d.interval(:value).to_i.should == 6
113
+ end
114
+
108
115
  specify "should return the correct records" do
109
116
  @d.to_a.should == []
110
117
  @d << {:name => 'abc', :value => 123}
@@ -247,7 +254,6 @@ describe "Simple Dataset operations in transactions" do
247
254
  cspecify "should insert correctly with a primary key specified inside a transaction", :mssql do
248
255
  INTEGRATION_DB.transaction do
249
256
  @ds.insert(:id=>100, :number=>20)
250
- sqls_should_be('BEGIN', /INSERT INTO items_insert_in_transaction \((number, id|id, number)\) VALUES \((100, 20|20, 100)\)/)
251
257
  @ds.count.should == 1
252
258
  @ds.order(:id).all.should == [{:id=>100, :number=>20}]
253
259
  end
@@ -256,7 +262,6 @@ describe "Simple Dataset operations in transactions" do
256
262
  specify "should have insert return primary key value inside a transaction" do
257
263
  INTEGRATION_DB.transaction do
258
264
  @ds.insert(:number=>20).should == 1
259
- sqls_should_be('BEGIN', /INSERT INTO items_insert_in_transaction \(number\) VALUES \(20\)/)
260
265
  @ds.count.should == 1
261
266
  @ds.order(:id).all.should == [{:id=>1, :number=>20}]
262
267
  end
@@ -495,4 +500,373 @@ describe "Sequel::Dataset#import and #multi_insert" do
495
500
  @ids.import([:i], @eds)
496
501
  @ids.all.should == [{:i=>10}, {:i=>20}]
497
502
  end
503
+
504
+ it "should have import work with the :slice_size option" do
505
+ @ids.import([:i], [[10], [20], [30]], :slice_size=>1)
506
+ @ids.all.should == [{:i=>10}, {:i=>20}, {:i=>30}]
507
+ @ids.delete
508
+ @ids.import([:i], [[10], [20], [30]], :slice_size=>2)
509
+ @ids.all.should == [{:i=>10}, {:i=>20}, {:i=>30}]
510
+ @ids.delete
511
+ @ids.import([:i], [[10], [20], [30]], :slice_size=>3)
512
+ @ids.all.should == [{:i=>10}, {:i=>20}, {:i=>30}]
513
+ end
514
+ end
515
+
516
+ describe "Sequel::Dataset convenience methods" do
517
+ before do
518
+ @db = INTEGRATION_DB
519
+ @db.create_table!(:a){Integer :a; Integer :b}
520
+ @ds = @db[:a].order(:a)
521
+ end
522
+ after do
523
+ @db.drop_table(:a)
524
+ end
525
+
526
+ it "#[]= should update matching rows" do
527
+ @ds.insert(20, 10)
528
+ @ds[:a=>20] = {:b=>30}
529
+ @ds.all.should == [{:a=>20, :b=>30}]
530
+ end
531
+
532
+ it "#empty? should return whether the dataset returns no rows" do
533
+ @ds.empty?.should == true
534
+ @ds.insert(20, 10)
535
+ @ds.empty?.should == false
536
+ end
537
+
538
+ it "#group_and_count should return a grouping by count" do
539
+ @ds.group_and_count(:a).all.should == []
540
+ @ds.insert(20, 10)
541
+ @ds.group_and_count(:a).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>1}]
542
+ @ds.insert(20, 30)
543
+ @ds.group_and_count(:a).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>2}]
544
+ @ds.insert(30, 30)
545
+ @ds.group_and_count(:a).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>30, :count=>1}, {:a=>20, :count=>2}]
546
+ end
547
+
548
+ it "#group_and_count should support column aliases" do
549
+ @ds.group_and_count(:a___c).all.should == []
550
+ @ds.insert(20, 10)
551
+ @ds.group_and_count(:a___c).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>1}]
552
+ @ds.insert(20, 30)
553
+ @ds.group_and_count(:a___c).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>2}]
554
+ @ds.insert(30, 30)
555
+ @ds.group_and_count(:a___c).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>30, :count=>1}, {:c=>20, :count=>2}]
556
+ end
557
+
558
+ cspecify "#range should return the range between the maximum and minimum values", :sqlite do
559
+ @ds = @ds.unordered
560
+ @ds.insert(20, 10)
561
+ @ds.insert(30, 10)
562
+ @ds.range(:a).should == (20..30)
563
+ @ds.range(:b).should == (10..10)
564
+ end
565
+
566
+ it "#interval should return the different between the maximum and minimum values" do
567
+ @ds = @ds.unordered
568
+ @ds.insert(20, 10)
569
+ @ds.insert(30, 10)
570
+ @ds.interval(:a).to_i.should == 10
571
+ @ds.interval(:b).to_i.should == 0
572
+ end
573
+ end
574
+
575
+ describe "Sequel::Dataset main SQL methods" do
576
+ before do
577
+ @db = INTEGRATION_DB
578
+ @db.create_table!(:a){Integer :a; Integer :b}
579
+ @ds = @db[:a].order(:a)
580
+ end
581
+ after do
582
+ @db.drop_table(:a)
583
+ end
584
+
585
+ it "#exists should return a usable exists clause" do
586
+ @ds.filter(@db[:a___c].filter(:c__a=>:a__b).exists).all.should == []
587
+ @ds.insert(20, 30)
588
+ @ds.insert(10, 20)
589
+ @ds.filter(@db[:a___c].filter(:c__a=>:a__b).exists).all.should == [{:a=>10, :b=>20}]
590
+ end
591
+
592
+ it "#filter and #exclude should work with placeholder strings" do
593
+ @ds.insert(20, 30)
594
+ @ds.filter("a > ?", 15).all.should == [{:a=>20, :b=>30}]
595
+ @ds.exclude("b < ?", 15).all.should == [{:a=>20, :b=>30}]
596
+ @ds.filter("b < ?", 15).invert.all.should == [{:a=>20, :b=>30}]
597
+ end
598
+
599
+ it "#and and #or should work with placeholder strings" do
600
+ @ds.insert(20, 30)
601
+ @ds.filter(:a=>20).and(:b=>30).all.should == [{:a=>20, :b=>30}]
602
+ @ds.filter(:a=>20).and(:b=>15).all.should == []
603
+ @ds.filter(:a=>20).or(:b=>15).all.should == [{:a=>20, :b=>30}]
604
+ @ds.filter(:a=>10).or(:b=>15).all.should == []
605
+ end
606
+
607
+ it "#having should work correctly" do
608
+ @ds.unordered!
609
+ @ds.select{[b, max(a).as(c)]}.group(:b).having{max(a) > 30}.all.should == []
610
+ @ds.insert(20, 30)
611
+ @ds.select{[b, max(a).as(c)]}.group(:b).having{max(a) > 30}.all.should == []
612
+ @ds.insert(40, 20)
613
+ @ds.select{[b, max(a).as(c)]}.group(:b).having{max(a) > 30}.all.each{|h| h[:c] = h[:c].to_i}.should == [{:b=>20, :c=>40}]
614
+ end
615
+
616
+ cspecify "#having should work without a previous group", :sqlite do
617
+ @ds.unordered!
618
+ @ds.select{max(a).as(c)}.having{max(a) > 30}.all.should == []
619
+ @ds.insert(20, 30)
620
+ @ds.select{max(a).as(c)}.having{max(a) > 30}.all.should == []
621
+ @ds.insert(40, 20)
622
+ @ds.select{max(a).as(c)}.having{max(a) > 30}.all.each{|h| h[:c] = h[:c].to_i}.should == [{:c=>40}]
623
+ end
624
+ end
625
+
626
+ describe "Sequel::Dataset DSL support" do
627
+ before do
628
+ @db = INTEGRATION_DB
629
+ @db.create_table!(:a){Integer :a; Integer :b}
630
+ @ds = @db[:a].order(:a)
631
+ end
632
+ after do
633
+ @db.drop_table(:a)
634
+ end
635
+
636
+ it "should work with standard mathematical operators" do
637
+ @ds.insert(20, 10)
638
+ @ds.get{a + b}.to_i.should == 30
639
+ @ds.get{a - b}.to_i.should == 10
640
+ @ds.get{a * b}.to_i.should == 200
641
+ @ds.get{a / b}.to_i.should == 2
642
+ end
643
+
644
+ cspecify "should work with standard bitwise mathematical operators", :mssql, :h2 do
645
+ @ds.insert(24, 2)
646
+ @ds.get{a.sql_number << b}.to_i.should == 96
647
+ @ds.get{a.sql_number >> b}.to_i.should == 6
648
+ @ds.delete
649
+ @ds.insert(3, 5)
650
+ @ds.get{a.sql_number | b}.to_i.should == 7
651
+ @ds.get{a.sql_number & b}.to_i.should == 1
652
+ end
653
+
654
+ cspecify "should work with the bitwise compliment operator", :mysql, :h2 do
655
+ @ds.insert(3, 5)
656
+ @ds.get{~a.sql_number}.to_i.should == -4
657
+ end
658
+
659
+ cspecify "should work with inequality operators", :mssql do
660
+ @ds.insert(20, 20)
661
+ ['0', 0, false].should include(@ds.get{a > b})
662
+ ['0', 0, false].should include(@ds.get{a < b})
663
+ ['1', 1, true].should include(@ds.get{a <= b})
664
+ ['1', 1, true].should include(@ds.get{a >= b})
665
+ end
666
+
667
+ cspecify "should work with casting and string concatentation", :mssql do
668
+ @ds.insert(20, 20)
669
+ @ds.get{a.cast_string + b}.should == '2020'
670
+ end
671
+
672
+ it "should work with ordering" do
673
+ @ds.insert(10, 20)
674
+ @ds.insert(20, 10)
675
+ @ds.order(:a, :b).all.should == [{:a=>10, :b=>20}, {:a=>20, :b=>10}]
676
+ @ds.order(:a.asc, :b.asc).all.should == [{:a=>10, :b=>20}, {:a=>20, :b=>10}]
677
+ @ds.order(:a.desc, :b.desc).all.should == [{:a=>20, :b=>10}, {:a=>10, :b=>20}]
678
+ end
679
+
680
+ it "should work with qualifying" do
681
+ @ds.insert(10, 20)
682
+ @ds.get(:a__b).should == 20
683
+ @ds.get{a__b}.should == 20
684
+ @ds.get(:b.qualify(:a)).should == 20
685
+ end
686
+
687
+ it "should work with aliasing" do
688
+ @ds.insert(10, 20)
689
+ @ds.get(:a__b___c).should == 20
690
+ @ds.get{a__b.as(c)}.should == 20
691
+ @ds.get(:b.qualify(:a).as(:c)).should == 20
692
+ @ds.get(:b.as(:c)).should == 20
693
+ end
694
+
695
+ it "should work with selecting all columns of a table" do
696
+ @ds.insert(20, 10)
697
+ @ds.select(:a.*).all.should == [{:a=>20, :b=>10}]
698
+ end
699
+
700
+ it "should work with ranges as hash values" do
701
+ @ds.insert(20, 10)
702
+ @ds.filter(:a=>(10..30)).all.should == [{:a=>20, :b=>10}]
703
+ @ds.filter(:a=>(25..30)).all.should == []
704
+ @ds.filter(:a=>(10..15)).all.should == []
705
+ @ds.exclude(:a=>(10..30)).all.should == []
706
+ @ds.exclude(:a=>(25..30)).all.should == [{:a=>20, :b=>10}]
707
+ @ds.exclude(:a=>(10..15)).all.should == [{:a=>20, :b=>10}]
708
+ end
709
+
710
+ it "should work with nil as hash value" do
711
+ @ds.insert(20, nil)
712
+ @ds.filter(:a=>nil).all.should == []
713
+ @ds.filter(:b=>nil).all.should == [{:a=>20, :b=>nil}]
714
+ @ds.exclude(:b=>nil).all.should == []
715
+ @ds.exclude(:a=>nil).all.should == [{:a=>20, :b=>nil}]
716
+ end
717
+
718
+ it "should work with ranges as hash values" do
719
+ @ds.insert(20, 10)
720
+ @ds.filter(:a=>(10..30)).all.should == [{:a=>20, :b=>10}]
721
+ @ds.filter(:a=>(25..30)).all.should == []
722
+ @ds.filter(:a=>(10..15)).all.should == []
723
+ @ds.exclude(:a=>(10..30)).all.should == []
724
+ @ds.exclude(:a=>(25..30)).all.should == [{:a=>20, :b=>10}]
725
+ @ds.exclude(:a=>(10..15)).all.should == [{:a=>20, :b=>10}]
726
+ end
727
+
728
+ it "should work with CASE statements" do
729
+ @ds.insert(20, 10)
730
+ @ds.filter({{:a=>20}=>20}.case(0) > 0).all.should == [{:a=>20, :b=>10}]
731
+ @ds.filter({{:a=>15}=>20}.case(0) > 0).all.should == []
732
+ @ds.filter({20=>20}.case(0, :a) > 0).all.should == [{:a=>20, :b=>10}]
733
+ @ds.filter({15=>20}.case(0, :a) > 0).all.should == []
734
+ end
735
+
736
+ it "should work multiple value arrays" do
737
+ @ds.insert(20, 10)
738
+ @ds.quote_identifiers = false
739
+ @ds.filter([:a, :b]=>[[20, 10]].sql_array).all.should == [{:a=>20, :b=>10}]
740
+ @ds.filter([:a, :b]=>[[10, 20]].sql_array).all.should == []
741
+ @ds.filter([:a, :b]=>[[20, 10], [1, 2]].sql_array).all.should == [{:a=>20, :b=>10}]
742
+ @ds.filter([:a, :b]=>[[10, 10], [20, 20]].sql_array).all.should == []
743
+
744
+ @ds.exclude([:a, :b]=>[[20, 10]].sql_array).all.should == []
745
+ @ds.exclude([:a, :b]=>[[10, 20]].sql_array).all.should == [{:a=>20, :b=>10}]
746
+ @ds.exclude([:a, :b]=>[[20, 10], [1, 2]].sql_array).all.should == []
747
+ @ds.exclude([:a, :b]=>[[10, 10], [20, 20]].sql_array).all.should == [{:a=>20, :b=>10}]
748
+ end
749
+
750
+ it "should work multiple conditions" do
751
+ @ds.insert(20, 10)
752
+ @ds.filter(:a=>20, :b=>10).all.should == [{:a=>20, :b=>10}]
753
+ @ds.filter([[:a, 20], [:b, 10]]).all.should == [{:a=>20, :b=>10}]
754
+ @ds.filter({:a=>20} & {:b=>10}).all.should == [{:a=>20, :b=>10}]
755
+ @ds.filter({:a=>20} | {:b=>5}).all.should == [{:a=>20, :b=>10}]
756
+ @ds.filter(~{:a=>10}).all.should == [{:a=>20, :b=>10}]
757
+ end
758
+ end
759
+
760
+ describe "SQL Extract Function" do
761
+ before do
762
+ @db = INTEGRATION_DB
763
+ @db.create_table!(:a){DateTime :a}
764
+ @ds = @db[:a].order(:a)
765
+ end
766
+ after do
767
+ @db.drop_table(:a)
768
+ end
769
+
770
+ cspecify "should return the part of the datetime asked for", :sqlite, :mssql do
771
+ t = Time.now
772
+ @ds.insert(t)
773
+ @ds.get{a.extract(:year)}.should == t.year
774
+ @ds.get{a.extract(:month)}.should == t.month
775
+ @ds.get{a.extract(:day)}.should == t.day
776
+ end
777
+ end
778
+
779
+ describe "Dataset string methods" do
780
+ before do
781
+ @db = INTEGRATION_DB
782
+ @db.create_table!(:a){String :a; String :b}
783
+ @ds = @db[:a].order(:a)
784
+ end
785
+ after do
786
+ @db.drop_table(:a)
787
+ end
788
+
789
+ it "#grep should return matching rows" do
790
+ @ds.insert('foo', 'bar')
791
+ @ds.grep(:a, 'foo').all.should == [{:a=>'foo', :b=>'bar'}]
792
+ @ds.grep(:b, 'foo').all.should == []
793
+ @ds.grep(:b, 'bar').all.should == [{:a=>'foo', :b=>'bar'}]
794
+ @ds.grep(:a, 'bar').all.should == []
795
+ @ds.grep([:a, :b], %w'foo bar').all.should == [{:a=>'foo', :b=>'bar'}]
796
+ @ds.grep([:a, :b], %w'boo far').all.should == []
797
+ end
798
+
799
+ it "#like should return matching rows" do
800
+ @ds.insert('foo', 'bar')
801
+ @ds.filter(:a.like('foo')).all.should == [{:a=>'foo', :b=>'bar'}]
802
+ @ds.filter(:a.like('bar')).all.should == []
803
+ @ds.filter(:a.like('foo', 'bar')).all.should == [{:a=>'foo', :b=>'bar'}]
804
+ end
805
+
806
+ it "#ilike should return matching rows, in a case insensitive manner" do
807
+ @ds.insert('foo', 'bar')
808
+ @ds.filter(:a.ilike('Foo')).all.should == [{:a=>'foo', :b=>'bar'}]
809
+ @ds.filter(:a.ilike('baR')).all.should == []
810
+ @ds.filter(:a.ilike('FOO', 'BAR')).all.should == [{:a=>'foo', :b=>'bar'}]
811
+ end
812
+
813
+ it "should work with strings created with sql_string_join" do
814
+ @ds.insert('foo', 'bar')
815
+ @ds.get([:a, :b].sql_string_join).should == 'foobar'
816
+ @ds.get([:a, :b].sql_string_join(' ')).should == 'foo bar'
817
+ end
818
+ end
819
+
820
+ describe "Dataset identifier methods" do
821
+ before do
822
+ class ::String
823
+ def uprev
824
+ upcase.reverse
825
+ end
826
+ end
827
+ @db = INTEGRATION_DB
828
+ @db.create_table!(:a){Integer :ab}
829
+ @ds = @db[:a].order(:ab)
830
+ @ds.insert(1)
831
+ end
832
+ after do
833
+ @db.drop_table(:a)
834
+ end
835
+
836
+ it "#identifier_output_method should change how identifiers are output" do
837
+ @ds.identifier_output_method = :upcase
838
+ @ds.first.should == {:AB=>1}
839
+ @ds.identifier_output_method = :uprev
840
+ @ds.first.should == {:BA=>1}
841
+ end
842
+
843
+ it "should work when not quoting identifiers" do
844
+ @ds.quote_identifiers = false
845
+ @ds.first.should == {:ab=>1}
846
+ end
847
+ end
848
+
849
+ describe "Dataset defaults and overrides" do
850
+ before do
851
+ @db = INTEGRATION_DB
852
+ @db.create_table!(:a){Integer :a}
853
+ @ds = @db[:a].order(:a)
854
+ end
855
+ after do
856
+ @db.drop_table(:a)
857
+ end
858
+
859
+ it "#set_defaults should set defaults that can be overridden" do
860
+ @ds = @ds.set_defaults(:a=>10)
861
+ @ds.insert
862
+ @ds.insert(:a=>20)
863
+ @ds.all.should == [{:a=>10}, {:a=>20}]
864
+ end
865
+
866
+ it "#set_overrides should set defaults that cannot be overridden" do
867
+ @ds = @ds.set_overrides(:a=>10)
868
+ @ds.insert
869
+ @ds.insert(:a=>20)
870
+ @ds.all.should == [{:a=>10}, {:a=>10}]
871
+ end
498
872
  end