sequel 3.21.0 → 3.28.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 (158) hide show
  1. data/CHANGELOG +294 -0
  2. data/README.rdoc +20 -6
  3. data/Rakefile +20 -15
  4. data/doc/association_basics.rdoc +210 -43
  5. data/doc/dataset_basics.rdoc +4 -4
  6. data/doc/mass_assignment.rdoc +54 -0
  7. data/doc/migration.rdoc +15 -538
  8. data/doc/model_hooks.rdoc +64 -27
  9. data/doc/opening_databases.rdoc +37 -10
  10. data/doc/prepared_statements.rdoc +16 -10
  11. data/doc/reflection.rdoc +8 -2
  12. data/doc/release_notes/3.22.0.txt +39 -0
  13. data/doc/release_notes/3.23.0.txt +172 -0
  14. data/doc/release_notes/3.24.0.txt +420 -0
  15. data/doc/release_notes/3.25.0.txt +88 -0
  16. data/doc/release_notes/3.26.0.txt +88 -0
  17. data/doc/release_notes/3.27.0.txt +82 -0
  18. data/doc/release_notes/3.28.0.txt +304 -0
  19. data/doc/schema_modification.rdoc +547 -0
  20. data/doc/testing.rdoc +106 -0
  21. data/doc/transactions.rdoc +97 -0
  22. data/doc/virtual_rows.rdoc +2 -2
  23. data/lib/sequel/adapters/ado.rb +12 -1
  24. data/lib/sequel/adapters/amalgalite.rb +4 -0
  25. data/lib/sequel/adapters/db2.rb +95 -58
  26. data/lib/sequel/adapters/do.rb +12 -0
  27. data/lib/sequel/adapters/firebird.rb +25 -203
  28. data/lib/sequel/adapters/ibmdb.rb +440 -0
  29. data/lib/sequel/adapters/informix.rb +4 -19
  30. data/lib/sequel/adapters/jdbc/as400.rb +0 -7
  31. data/lib/sequel/adapters/jdbc/db2.rb +49 -0
  32. data/lib/sequel/adapters/jdbc/firebird.rb +34 -0
  33. data/lib/sequel/adapters/jdbc/h2.rb +16 -5
  34. data/lib/sequel/adapters/jdbc/informix.rb +31 -0
  35. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  36. data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
  37. data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
  38. data/lib/sequel/adapters/jdbc/oracle.rb +2 -27
  39. data/lib/sequel/adapters/jdbc/postgresql.rb +6 -0
  40. data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
  41. data/lib/sequel/adapters/jdbc/transactions.rb +34 -0
  42. data/lib/sequel/adapters/jdbc.rb +62 -29
  43. data/lib/sequel/adapters/mysql.rb +22 -139
  44. data/lib/sequel/adapters/mysql2.rb +9 -14
  45. data/lib/sequel/adapters/odbc/db2.rb +21 -0
  46. data/lib/sequel/adapters/odbc.rb +15 -3
  47. data/lib/sequel/adapters/oracle.rb +17 -1
  48. data/lib/sequel/adapters/postgres.rb +111 -16
  49. data/lib/sequel/adapters/shared/access.rb +21 -0
  50. data/lib/sequel/adapters/shared/db2.rb +290 -0
  51. data/lib/sequel/adapters/shared/firebird.rb +214 -0
  52. data/lib/sequel/adapters/shared/informix.rb +45 -0
  53. data/lib/sequel/adapters/shared/mssql.rb +85 -47
  54. data/lib/sequel/adapters/shared/mysql.rb +50 -7
  55. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +143 -0
  56. data/lib/sequel/adapters/shared/oracle.rb +0 -4
  57. data/lib/sequel/adapters/shared/postgres.rb +75 -43
  58. data/lib/sequel/adapters/shared/sqlite.rb +56 -8
  59. data/lib/sequel/adapters/sqlite.rb +12 -11
  60. data/lib/sequel/adapters/swift/mysql.rb +9 -0
  61. data/lib/sequel/adapters/tinytds.rb +139 -7
  62. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +55 -0
  63. data/lib/sequel/ast_transformer.rb +190 -0
  64. data/lib/sequel/connection_pool/threaded.rb +3 -2
  65. data/lib/sequel/connection_pool.rb +1 -1
  66. data/lib/sequel/core.rb +6 -5
  67. data/lib/sequel/database/connecting.rb +5 -5
  68. data/lib/sequel/database/dataset.rb +1 -1
  69. data/lib/sequel/database/dataset_defaults.rb +1 -1
  70. data/lib/sequel/database/logging.rb +1 -1
  71. data/lib/sequel/database/misc.rb +38 -17
  72. data/lib/sequel/database/query.rb +50 -19
  73. data/lib/sequel/database/schema_generator.rb +8 -5
  74. data/lib/sequel/database/schema_methods.rb +52 -27
  75. data/lib/sequel/dataset/actions.rb +167 -48
  76. data/lib/sequel/dataset/features.rb +57 -8
  77. data/lib/sequel/dataset/graph.rb +1 -1
  78. data/lib/sequel/dataset/misc.rb +39 -20
  79. data/lib/sequel/dataset/mutation.rb +3 -3
  80. data/lib/sequel/dataset/prepared_statements.rb +29 -14
  81. data/lib/sequel/dataset/query.rb +182 -32
  82. data/lib/sequel/dataset/sql.rb +31 -58
  83. data/lib/sequel/dataset.rb +8 -0
  84. data/lib/sequel/exceptions.rb +4 -0
  85. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  86. data/lib/sequel/extensions/migration.rb +6 -4
  87. data/lib/sequel/extensions/to_dot.rb +95 -83
  88. data/lib/sequel/model/associations.rb +893 -309
  89. data/lib/sequel/model/base.rb +302 -105
  90. data/lib/sequel/model/errors.rb +1 -1
  91. data/lib/sequel/model/exceptions.rb +5 -1
  92. data/lib/sequel/model.rb +13 -7
  93. data/lib/sequel/plugins/association_pks.rb +22 -4
  94. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  95. data/lib/sequel/plugins/identity_map.rb +113 -6
  96. data/lib/sequel/plugins/many_through_many.rb +67 -5
  97. data/lib/sequel/plugins/prepared_statements.rb +140 -0
  98. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  99. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  100. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  101. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  102. data/lib/sequel/plugins/sharding.rb +12 -20
  103. data/lib/sequel/plugins/single_table_inheritance.rb +2 -0
  104. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  105. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  106. data/lib/sequel/sql.rb +107 -51
  107. data/lib/sequel/timezones.rb +12 -3
  108. data/lib/sequel/version.rb +1 -1
  109. data/spec/adapters/db2_spec.rb +146 -0
  110. data/spec/adapters/mssql_spec.rb +36 -0
  111. data/spec/adapters/mysql_spec.rb +36 -19
  112. data/spec/adapters/postgres_spec.rb +115 -28
  113. data/spec/adapters/spec_helper.rb +6 -0
  114. data/spec/adapters/sqlite_spec.rb +11 -0
  115. data/spec/core/connection_pool_spec.rb +62 -77
  116. data/spec/core/database_spec.rb +244 -287
  117. data/spec/core/dataset_spec.rb +383 -34
  118. data/spec/core/expression_filters_spec.rb +159 -41
  119. data/spec/core/schema_spec.rb +326 -3
  120. data/spec/core/spec_helper.rb +45 -0
  121. data/spec/extensions/association_pks_spec.rb +38 -0
  122. data/spec/extensions/columns_introspection_spec.rb +91 -0
  123. data/spec/extensions/defaults_setter_spec.rb +64 -0
  124. data/spec/extensions/identity_map_spec.rb +162 -0
  125. data/spec/extensions/many_through_many_spec.rb +195 -20
  126. data/spec/extensions/migration_spec.rb +17 -17
  127. data/spec/extensions/nested_attributes_spec.rb +1 -0
  128. data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
  129. data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
  130. data/spec/extensions/prepared_statements_spec.rb +72 -0
  131. data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
  132. data/spec/extensions/schema_dumper_spec.rb +2 -2
  133. data/spec/extensions/schema_spec.rb +12 -20
  134. data/spec/extensions/serialization_modification_detection_spec.rb +36 -0
  135. data/spec/extensions/single_table_inheritance_spec.rb +11 -0
  136. data/spec/extensions/spec_helper.rb +3 -1
  137. data/spec/extensions/to_dot_spec.rb +3 -5
  138. data/spec/extensions/xml_serializer_spec.rb +16 -4
  139. data/spec/integration/associations_test.rb +405 -15
  140. data/spec/integration/database_test.rb +4 -2
  141. data/spec/integration/dataset_test.rb +240 -20
  142. data/spec/integration/plugin_test.rb +142 -5
  143. data/spec/integration/prepared_statement_test.rb +174 -95
  144. data/spec/integration/schema_test.rb +128 -16
  145. data/spec/integration/spec_helper.rb +15 -0
  146. data/spec/integration/transaction_test.rb +40 -0
  147. data/spec/integration/type_test.rb +16 -2
  148. data/spec/model/association_reflection_spec.rb +91 -0
  149. data/spec/model/associations_spec.rb +476 -5
  150. data/spec/model/base_spec.rb +91 -1
  151. data/spec/model/eager_loading_spec.rb +519 -31
  152. data/spec/model/hooks_spec.rb +161 -0
  153. data/spec/model/model_spec.rb +89 -2
  154. data/spec/model/plugins_spec.rb +17 -0
  155. data/spec/model/record_spec.rb +184 -12
  156. data/spec/model/spec_helper.rb +5 -0
  157. data/spec/model/validations_spec.rb +11 -0
  158. metadata +85 -34
@@ -186,31 +186,26 @@ describe "Blockless Ruby Filters" do
186
186
  @d.l(~((((:x - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
187
187
  end
188
188
 
189
- it "should not allow negation of string expressions" do
190
- proc{~:x.sql_string}.should raise_error
191
- proc{~([:x, :y].sql_string_join)}.should raise_error
189
+ it "should not add ~ method to string expressions" do
190
+ proc{~:x.sql_string}.should raise_error(NoMethodError)
192
191
  end
193
192
 
194
- it "should not allow mathematical or string operations on true, false, or nil" do
195
- proc{:x + 1}.should_not raise_error
196
- proc{:x - true}.should raise_error(Sequel::Error)
197
- proc{:x / false}.should raise_error(Sequel::Error)
198
- proc{:x * nil}.should raise_error(Sequel::Error)
199
- proc{[:x, nil].sql_string_join}.should raise_error(Sequel::Error)
193
+ it "should allow mathematical or string operations on true, false, or nil" do
194
+ @d.lit(:x + 1).should == '(x + 1)'
195
+ @d.lit(:x - true).should == "(x - 't')"
196
+ @d.lit(:x / false).should == "(x / 'f')"
197
+ @d.lit(:x * nil).should == '(x * NULL)'
198
+ @d.lit([:x, nil].sql_string_join).should == '(x || NULL)'
200
199
  end
201
200
 
202
- it "should not allow mathematical or string operations on boolean complex expressions" do
203
- proc{:x + (:y + 1)}.should_not raise_error
204
- proc{:x - (~:y)}.should raise_error(Sequel::Error)
205
- proc{:x / (:y & :z)}.should raise_error(Sequel::Error)
206
- proc{:x * (:y | :z)}.should raise_error(Sequel::Error)
207
- proc{:x + :y.like('a')}.should raise_error(Sequel::Error)
208
- proc{:x - :y.like(/a/)}.should raise_error(Sequel::Error)
209
- proc{:x * :y.like(/a/i)}.should raise_error(Sequel::Error)
210
- proc{:x + ~:y.like('a')}.should raise_error(Sequel::Error)
211
- proc{:x - ~:y.like(/a/)}.should raise_error(Sequel::Error)
212
- proc{:x * ~:y.like(/a/i)}.should raise_error(Sequel::Error)
213
- proc{[:x, ~:y.like(/a/i)].sql_string_join}.should raise_error(Sequel::Error)
201
+ it "should allow mathematical or string operations on boolean complex expressions" do
202
+ @d.lit(:x + (:y + 1)).should == '(x + y + 1)'
203
+ @d.lit(:x - ~:y).should == '(x - NOT y)'
204
+ @d.lit(:x / (:y & :z)).should == '(x / (y AND z))'
205
+ @d.lit(:x * (:y | :z)).should == '(x * (y OR z))'
206
+ @d.lit(:x + :y.like('a')).should == "(x + (y LIKE 'a'))"
207
+ @d.lit(:x - ~:y.like('a')).should == "(x - (y NOT LIKE 'a'))"
208
+ @d.lit([:x, ~:y.like('a')].sql_string_join).should == "(x || (y NOT LIKE 'a'))"
214
209
  end
215
210
 
216
211
  it "should support AND conditions via &" do
@@ -382,12 +377,12 @@ describe "Blockless Ruby Filters" do
382
377
  @d.l((:x + 1) & (:x + 2) > 100).should == '(((x + 1) & (x + 2)) > 100)'
383
378
  end
384
379
 
385
- it "should raise an error if use a Bitwise method on a ComplexExpression that isn't a NumericExpression" do
386
- proc{(:x + 1) & (:x & 2)}.should raise_error(Sequel::Error)
380
+ it "should allow using a Bitwise method on a ComplexExpression that isn't a NumericExpression" do
381
+ @d.lit((:x + 1) & (:x + '2')).should == "((x + 1) & (x || '2'))"
387
382
  end
388
383
 
389
- it "should raise an error if use a Boolean method on a ComplexExpression that isn't a BooleanExpression" do
390
- proc{:x & (:x + 2)}.should raise_error(Sequel::Error)
384
+ it "should allow using a Boolean method on a ComplexExpression that isn't a BooleanExpression" do
385
+ @d.l(:x & (:x + '2')).should == "(x AND (x || '2'))"
391
386
  end
392
387
 
393
388
  it "should raise an error if attempting to invert a ComplexExpression that isn't a BooleanExpression" do
@@ -424,10 +419,94 @@ describe "Blockless Ruby Filters" do
424
419
  @d.l(~{:x => Sequel::SQLFALSE}).should == '(x IS NOT FALSE)'
425
420
  end
426
421
 
422
+ it "should support direct negation of SQL::Constants" do
423
+ @d.l({:x => ~Sequel::NULL}).should == '(x IS NOT NULL)'
424
+ @d.l({:x => ~Sequel::NOTNULL}).should == '(x IS NULL)'
425
+ @d.l({:x => ~Sequel::TRUE}).should == '(x IS FALSE)'
426
+ @d.l({:x => ~Sequel::FALSE}).should == '(x IS TRUE)'
427
+ @d.l({:x => ~Sequel::SQLTRUE}).should == '(x IS FALSE)'
428
+ @d.l({:x => ~Sequel::SQLFALSE}).should == '(x IS TRUE)'
429
+ end
430
+
431
+ it "should raise an error if trying to invert an invalid SQL::Constant" do
432
+ proc{~Sequel::CURRENT_DATE}.should raise_error(Sequel::Error)
433
+ end
434
+
427
435
  it "should raise an error if trying to create an invalid complex expression" do
428
436
  proc{Sequel::SQL::ComplexExpression.new(:BANG, 1, 2)}.should raise_error(Sequel::Error)
429
437
  end
430
438
 
439
+ it "should use a string concatentation for + if given a string" do
440
+ @d.lit(:x + '1').should == "(x || '1')"
441
+ @d.lit(:x + '1' + '1').should == "(x || '1' || '1')"
442
+ end
443
+
444
+ it "should use an addition for + if given a literal string" do
445
+ @d.lit(:x + '1'.lit).should == "(x + 1)"
446
+ @d.lit(:x + '1'.lit + '1'.lit).should == "(x + 1 + 1)"
447
+ end
448
+
449
+ it "should use a bitwise operator for & and | if given an integer" do
450
+ @d.lit(:x & 1).should == "(x & 1)"
451
+ @d.lit(:x | 1).should == "(x | 1)"
452
+ @d.lit(:x & 1 & 1).should == "(x & 1 & 1)"
453
+ @d.lit(:x | 1 | 1).should == "(x | 1 | 1)"
454
+ end
455
+
456
+ it "should allow adding a string to an integer expression" do
457
+ @d.lit(:x + 1 + 'a').should == "(x + 1 + 'a')"
458
+ end
459
+
460
+ it "should allow adding an integer to an string expression" do
461
+ @d.lit(:x + 'a' + 1).should == "(x || 'a' || 1)"
462
+ end
463
+
464
+ it "should allow adding a boolean to an integer expression" do
465
+ @d.lit(:x + 1 + true).should == "(x + 1 + 't')"
466
+ end
467
+
468
+ it "should allow adding a boolean to an string expression" do
469
+ @d.lit(:x + 'a' + true).should == "(x || 'a' || 't')"
470
+ end
471
+
472
+ it "should allow using a boolean operation with an integer on an boolean expression" do
473
+ @d.lit(:x & :a & 1).should == "(x AND a AND 1)"
474
+ end
475
+
476
+ it "should allow using a boolean operation with a string on an boolean expression" do
477
+ @d.lit(:x & :a & 'a').should == "(x AND a AND 'a')"
478
+ end
479
+
480
+ it "should allowing AND of boolean expression and literal string" do
481
+ @d.lit(:x & :a & 'a'.lit).should == "(x AND a AND a)"
482
+ end
483
+
484
+ it "should allowing + of integer expression and literal string" do
485
+ @d.lit(:x + :a + 'a'.lit).should == "(x + a + a)"
486
+ end
487
+
488
+ it "should allowing + of string expression and literal string" do
489
+ @d.lit(:x + 'a' + 'a'.lit).should == "(x || 'a' || a)"
490
+ end
491
+
492
+ it "should allow sql_{string,boolean,number} methods on numeric expressions" do
493
+ @d.lit((:x + 1).sql_string + 'a').should == "((x + 1) || 'a')"
494
+ @d.lit((:x + 1).sql_boolean & 1).should == "((x + 1) AND 1)"
495
+ @d.lit((:x + 1).sql_number + 'a').should == "(x + 1 + 'a')"
496
+ end
497
+
498
+ it "should allow sql_{string,boolean,number} methods on string expressions" do
499
+ @d.lit((:x + 'a').sql_string + 'a').should == "(x || 'a' || 'a')"
500
+ @d.lit((:x + 'a').sql_boolean & 1).should == "((x || 'a') AND 1)"
501
+ @d.lit((:x + 'a').sql_number + 'a').should == "((x || 'a') + 'a')"
502
+ end
503
+
504
+ it "should allow sql_{string,boolean,number} methods on boolean expressions" do
505
+ @d.lit((:x & :y).sql_string + 'a').should == "((x AND y) || 'a')"
506
+ @d.lit((:x & :y).sql_boolean & 1).should == "(x AND y AND 1)"
507
+ @d.lit((:x & :y).sql_number + 'a').should == "((x AND y) + 'a')"
508
+ end
509
+
431
510
  it "should raise an error if trying to literalize an invalid complex expression" do
432
511
  ce = :x + 1
433
512
  ce.instance_variable_set(:@op, :BANG)
@@ -439,26 +518,65 @@ describe "Blockless Ruby Filters" do
439
518
  e2 = ~:comment.like('%:hidden:%')
440
519
  e1.should == e2
441
520
  end
521
+
522
+ it "should support expression filter methods on Datasets" do
523
+ d = @d.select(:a)
524
+
525
+ @d.lit(d + 1).should == '((SELECT a FROM items) + 1)'
526
+ @d.lit(d - 1).should == '((SELECT a FROM items) - 1)'
527
+ @d.lit(d * 1).should == '((SELECT a FROM items) * 1)'
528
+ @d.lit(d / 1).should == '((SELECT a FROM items) / 1)'
529
+
530
+ @d.lit(d => 1).should == '((SELECT a FROM items) = 1)'
531
+ @d.lit(~{d => 1}).should == '((SELECT a FROM items) != 1)'
532
+ @d.lit(d > 1).should == '((SELECT a FROM items) > 1)'
533
+ @d.lit(d < 1).should == '((SELECT a FROM items) < 1)'
534
+ @d.lit(d >= 1).should == '((SELECT a FROM items) >= 1)'
535
+ @d.lit(d <= 1).should == '((SELECT a FROM items) <= 1)'
536
+
537
+ @d.lit(d.as(:b)).should == '(SELECT a FROM items) AS b'
538
+
539
+ @d.lit(d & :b).should == '((SELECT a FROM items) AND b)'
540
+ @d.lit(d | :b).should == '((SELECT a FROM items) OR b)'
541
+ @d.lit(~d).should == 'NOT (SELECT a FROM items)'
542
+
543
+ @d.lit(d.cast(Integer)).should == 'CAST((SELECT a FROM items) AS integer)'
544
+ @d.lit(d.cast_numeric).should == 'CAST((SELECT a FROM items) AS integer)'
545
+ @d.lit(d.cast_string).should == 'CAST((SELECT a FROM items) AS varchar(255))'
546
+ @d.lit(d.cast_numeric << :b).should == '(CAST((SELECT a FROM items) AS integer) << b)'
547
+ @d.lit(d.cast_string + :b).should == '(CAST((SELECT a FROM items) AS varchar(255)) || b)'
548
+
549
+ @d.lit(d.extract(:year)).should == 'extract(year FROM (SELECT a FROM items))'
550
+ @d.lit(d.sql_boolean & :b).should == '((SELECT a FROM items) AND b)'
551
+ @d.lit(d.sql_number << :b).should == '((SELECT a FROM items) << b)'
552
+ @d.lit(d.sql_string + :b).should == '((SELECT a FROM items) || b)'
553
+
554
+ @d.lit(d.asc).should == '(SELECT a FROM items) ASC'
555
+ @d.lit(d.desc).should == '(SELECT a FROM items) DESC'
556
+
557
+ @d.lit(d.like(:b)).should == '((SELECT a FROM items) LIKE b)'
558
+ @d.lit(d.ilike(:b)).should == '((SELECT a FROM items) ILIKE b)'
559
+ end
442
560
 
443
561
  if RUBY_VERSION < '1.9.0'
444
562
  it "should not allow inequality operations on true, false, or nil" do
445
- proc{:x > 1}.should_not raise_error
446
- proc{:x < true}.should raise_error(Sequel::Error)
447
- proc{:x >= false}.should raise_error(Sequel::Error)
448
- proc{:x <= nil}.should raise_error(Sequel::Error)
563
+ @d.lit(:x > 1).should == "(x > 1)"
564
+ @d.lit(:x < true).should == "(x < 't')"
565
+ @d.lit(:x >= false).should == "(x >= 'f')"
566
+ @d.lit(:x <= nil).should == "(x <= NULL)"
449
567
  end
450
568
 
451
569
  it "should not allow inequality operations on boolean complex expressions" do
452
- proc{:x > (:y > 5)}.should raise_error(Sequel::Error)
453
- proc{:x < (:y < 5)}.should raise_error(Sequel::Error)
454
- proc{:x >= (:y >= 5)}.should raise_error(Sequel::Error)
455
- proc{:x <= (:y <= 5)}.should raise_error(Sequel::Error)
456
- proc{:x > {:y => nil}}.should raise_error(Sequel::Error)
457
- proc{:x < ~{:y => nil}}.should raise_error(Sequel::Error)
458
- proc{:x >= {:y => 5}}.should raise_error(Sequel::Error)
459
- proc{:x <= ~{:y => 5}}.should raise_error(Sequel::Error)
460
- proc{:x >= {:y => [1,2,3]}}.should raise_error(Sequel::Error)
461
- proc{:x <= ~{:y => [1,2,3]}}.should raise_error(Sequel::Error)
570
+ @d.lit(:x > (:y > 5)).should == "(x > (y > 5))"
571
+ @d.lit(:x < (:y < 5)).should == "(x < (y < 5))"
572
+ @d.lit(:x >= (:y >= 5)).should == "(x >= (y >= 5))"
573
+ @d.lit(:x <= (:y <= 5)).should == "(x <= (y <= 5))"
574
+ @d.lit(:x > {:y => nil}).should == "(x > (y IS NULL))"
575
+ @d.lit(:x < ~{:y => nil}).should == "(x < (y IS NOT NULL))"
576
+ @d.lit(:x >= {:y => 5}).should == "(x >= (y = 5))"
577
+ @d.lit(:x <= ~{:y => 5}).should == "(x <= (y != 5))"
578
+ @d.lit(:x >= {:y => [1,2,3]}).should == "(x >= (y IN (1, 2, 3)))"
579
+ @d.lit(:x <= ~{:y => [1,2,3]}).should == "(x <= (y NOT IN (1, 2, 3)))"
462
580
  end
463
581
 
464
582
  it "should support >, <, >=, and <= via Symbol#>,<,>=,<=" do
@@ -553,7 +671,7 @@ describe Sequel::SQL::VirtualRow do
553
671
  end
554
672
 
555
673
  it "should support :frame=>:rows option for window function calls" do
556
- @d.l{rank(:over, :frame=>:rows){}}.should == 'rank() OVER (ROWS UNBOUNDED PRECEDING)'
674
+ @d.l{rank(:over, :frame=>:rows){}}.should == 'rank() OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)'
557
675
  end
558
676
 
559
677
  it "should support :frame=>'some string' option for window function calls" do
@@ -565,7 +683,7 @@ describe Sequel::SQL::VirtualRow do
565
683
  end
566
684
 
567
685
  it "should support all these options together" do
568
- @d.l{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}.should == 'count(*) OVER ("win" PARTITION BY "a" ORDER BY "b" ROWS UNBOUNDED PRECEDING)'
686
+ @d.l{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}.should == 'count(*) OVER ("win" PARTITION BY "a" ORDER BY "b" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)'
569
687
  end
570
688
 
571
689
  it "should raise an error if window functions are not supported" do
@@ -281,6 +281,13 @@ describe "DB#create_table" do
281
281
  @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects DEFERRABLE INITIALLY DEFERRED)"]
282
282
  end
283
283
 
284
+ specify "should accept collation" do
285
+ @db.create_table(:cats) do
286
+ varchar :name, :collate => :utf8_bin
287
+ end
288
+ @db.sqls.should == ["CREATE TABLE cats (name varchar(255) COLLATE utf8_bin)"]
289
+ end
290
+
284
291
  specify "should accept inline index definition" do
285
292
  @db.create_table(:cats) do
286
293
  integer :id, :index => true
@@ -548,8 +555,15 @@ describe "DB#create_table!" do
548
555
  @db = SchemaDummyDatabase.new
549
556
  end
550
557
 
551
- specify "should drop the table and then create it" do
552
- @db.create_table!(:cats) {}
558
+ specify "should create the table if it does not exist" do
559
+ @db.meta_def(:table_exists?){|a| false}
560
+ @db.create_table!(:cats){|*a|}
561
+ @db.sqls.should == ['CREATE TABLE cats ()']
562
+ end
563
+
564
+ specify "should drop the table before creating it if it already exists" do
565
+ @db.meta_def(:table_exists?){|a| true}
566
+ @db.create_table!(:cats){|*a|}
553
567
  @db.sqls.should == ['DROP TABLE cats', 'CREATE TABLE cats ()']
554
568
  end
555
569
  end
@@ -570,6 +584,12 @@ describe "DB#create_table?" do
570
584
  @db.create_table?(:cats){|*a|}
571
585
  @db.sqls.should == ['CREATE TABLE cats ()']
572
586
  end
587
+
588
+ specify "should use IF NOT EXISTS if the database supports that" do
589
+ @db.meta_def(:supports_create_table_if_not_exists?){true}
590
+ @db.create_table?(:cats){|*a|}
591
+ @db.sqls.should == ['CREATE TABLE IF NOT EXISTS cats ()']
592
+ end
573
593
  end
574
594
 
575
595
  describe "DB#drop_table" do
@@ -581,6 +601,16 @@ describe "DB#drop_table" do
581
601
  @db.drop_table :cats
582
602
  @db.sqls.should == ['DROP TABLE cats']
583
603
  end
604
+
605
+ specify "should drop multiple tables at once" do
606
+ @db.drop_table :cats, :dogs
607
+ @db.sqls.should == ['DROP TABLE cats', 'DROP TABLE dogs']
608
+ end
609
+
610
+ specify "should take an options hash and support the :cascade option" do
611
+ @db.drop_table :cats, :dogs, :cascade=>true
612
+ @db.sqls.should == ['DROP TABLE cats CASCADE', 'DROP TABLE dogs CASCADE']
613
+ end
584
614
  end
585
615
 
586
616
  describe "DB#alter_table" do
@@ -709,6 +739,13 @@ describe "DB#alter_table" do
709
739
  @db.sqls.should == ["ALTER TABLE cats DROP COLUMN score"]
710
740
  end
711
741
 
742
+ specify "should support drop_column with :cascade=>true option" do
743
+ @db.alter_table(:cats) do
744
+ drop_column :score, :cascade=>true
745
+ end
746
+ @db.sqls.should == ["ALTER TABLE cats DROP COLUMN score CASCADE"]
747
+ end
748
+
712
749
  specify "should support drop_constraint" do
713
750
  @db.alter_table(:cats) do
714
751
  drop_constraint :valid_score
@@ -716,6 +753,13 @@ describe "DB#alter_table" do
716
753
  @db.sqls.should == ["ALTER TABLE cats DROP CONSTRAINT valid_score"]
717
754
  end
718
755
 
756
+ specify "should support drop_constraint with :cascade=>true option" do
757
+ @db.alter_table(:cats) do
758
+ drop_constraint :valid_score, :cascade=>true
759
+ end
760
+ @db.sqls.should == ["ALTER TABLE cats DROP CONSTRAINT valid_score CASCADE"]
761
+ end
762
+
719
763
  specify "should support drop_index" do
720
764
  @db.alter_table(:cats) do
721
765
  drop_index :name
@@ -763,6 +807,286 @@ describe "DB#alter_table" do
763
807
  end
764
808
  end
765
809
 
810
+ describe "Database#create_table" do
811
+ before do
812
+ @db = DummyDatabase.new
813
+ end
814
+
815
+ specify "should construct proper SQL" do
816
+ @db.create_table :test do
817
+ primary_key :id, :integer, :null => false
818
+ column :name, :text
819
+ index :name, :unique => true
820
+ end
821
+ @db.sqls.should == [
822
+ 'CREATE TABLE test (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
823
+ 'CREATE UNIQUE INDEX test_name_index ON test (name)'
824
+ ]
825
+ end
826
+
827
+ specify "should create a temporary table" do
828
+ @db.create_table :test_tmp, :temp => true do
829
+ primary_key :id, :integer, :null => false
830
+ column :name, :text
831
+ index :name, :unique => true
832
+ end
833
+
834
+ @db.sqls.should == [
835
+ 'CREATE TEMPORARY TABLE test_tmp (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
836
+ 'CREATE UNIQUE INDEX test_tmp_name_index ON test_tmp (name)'
837
+ ]
838
+ end
839
+
840
+ specify "should not use default schema when creating a temporary table" do
841
+ @db.default_schema = :foo
842
+ @db.create_table :test_tmp, :temp => true do
843
+ column :name, :text
844
+ end
845
+ @db.sqls.should == ['CREATE TEMPORARY TABLE test_tmp (name text)']
846
+ end
847
+ end
848
+
849
+ describe "Database#alter_table" do
850
+ before do
851
+ @db = DummyDatabase.new
852
+ end
853
+
854
+ specify "should construct proper SQL" do
855
+ @db.alter_table :xyz do
856
+ add_column :aaa, :text, :null => false, :unique => true
857
+ drop_column :bbb
858
+ rename_column :ccc, :ddd
859
+ set_column_type :eee, :integer
860
+ set_column_default :hhh, 'abcd'
861
+
862
+ add_index :fff, :unique => true
863
+ drop_index :ggg
864
+ end
865
+
866
+ @db.sqls.should == [
867
+ 'ALTER TABLE xyz ADD COLUMN aaa text NOT NULL UNIQUE',
868
+ 'ALTER TABLE xyz DROP COLUMN bbb',
869
+ 'ALTER TABLE xyz RENAME COLUMN ccc TO ddd',
870
+ 'ALTER TABLE xyz ALTER COLUMN eee TYPE integer',
871
+ "ALTER TABLE xyz ALTER COLUMN hhh SET DEFAULT 'abcd'",
872
+
873
+ 'CREATE UNIQUE INDEX xyz_fff_index ON xyz (fff)',
874
+ 'DROP INDEX xyz_ggg_index'
875
+ ]
876
+ end
877
+ end
878
+
879
+ describe "Database#add_column" do
880
+ before do
881
+ @db = DummyDatabase.new
882
+ end
883
+
884
+ specify "should construct proper SQL" do
885
+ @db.add_column :test, :name, :text, :unique => true
886
+ @db.sqls.should == [
887
+ 'ALTER TABLE test ADD COLUMN name text UNIQUE'
888
+ ]
889
+ end
890
+ end
891
+
892
+ describe "Database#drop_column" do
893
+ before do
894
+ @db = DummyDatabase.new
895
+ end
896
+
897
+ specify "should construct proper SQL" do
898
+ @db.drop_column :test, :name
899
+ @db.sqls.should == ['ALTER TABLE test DROP COLUMN name']
900
+ end
901
+
902
+ specify "should use CASCADE for :cascade=>true option" do
903
+ @db.drop_column :test, :name, :cascade=>true
904
+ @db.sqls.should == ['ALTER TABLE test DROP COLUMN name CASCADE']
905
+ end
906
+ end
907
+
908
+ describe "Database#rename_column" do
909
+ before do
910
+ @db = DummyDatabase.new
911
+ end
912
+
913
+ specify "should construct proper SQL" do
914
+ @db.rename_column :test, :abc, :def
915
+ @db.sqls.should == [
916
+ 'ALTER TABLE test RENAME COLUMN abc TO def'
917
+ ]
918
+ end
919
+ end
920
+
921
+ describe "Database#set_column_type" do
922
+ before do
923
+ @db = DummyDatabase.new
924
+ end
925
+
926
+ specify "should construct proper SQL" do
927
+ @db.set_column_type :test, :name, :integer
928
+ @db.sqls.should == [
929
+ 'ALTER TABLE test ALTER COLUMN name TYPE integer'
930
+ ]
931
+ end
932
+ end
933
+
934
+ describe "Database#set_column_default" do
935
+ before do
936
+ @db = DummyDatabase.new
937
+ end
938
+
939
+ specify "should construct proper SQL" do
940
+ @db.set_column_default :test, :name, 'zyx'
941
+ @db.sqls.should == [
942
+ "ALTER TABLE test ALTER COLUMN name SET DEFAULT 'zyx'"
943
+ ]
944
+ end
945
+ end
946
+
947
+ describe "Database#add_index" do
948
+ before do
949
+ @db = DummyDatabase.new
950
+ end
951
+
952
+ specify "should construct proper SQL" do
953
+ @db.add_index :test, :name, :unique => true
954
+ @db.sqls.should == [
955
+ 'CREATE UNIQUE INDEX test_name_index ON test (name)'
956
+ ]
957
+ end
958
+
959
+ specify "should accept multiple columns" do
960
+ @db.add_index :test, [:one, :two]
961
+ @db.sqls.should == [
962
+ 'CREATE INDEX test_one_two_index ON test (one, two)'
963
+ ]
964
+ end
965
+ end
966
+
967
+ describe "Database#drop_index" do
968
+ before do
969
+ @db = DummyDatabase.new
970
+ end
971
+
972
+ specify "should construct proper SQL" do
973
+ @db.drop_index :test, :name
974
+ @db.sqls.should == [
975
+ 'DROP INDEX test_name_index'
976
+ ]
977
+ end
978
+
979
+ end
980
+
981
+ describe "Database#drop_table" do
982
+ before do
983
+ @db = DummyDatabase.new
984
+ end
985
+
986
+ specify "should construct proper SQL" do
987
+ @db.drop_table :test
988
+ @db.sqls.should == ['DROP TABLE test']
989
+ end
990
+
991
+ specify "should accept multiple table names" do
992
+ @db.drop_table :a, :bb, :ccc
993
+ @db.sqls.should == [
994
+ 'DROP TABLE a',
995
+ 'DROP TABLE bb',
996
+ 'DROP TABLE ccc'
997
+ ]
998
+ end
999
+ end
1000
+
1001
+ describe "Database#rename_table" do
1002
+ before do
1003
+ @db = DummyDatabase.new
1004
+ end
1005
+
1006
+ specify "should construct proper SQL" do
1007
+ @db.rename_table :abc, :xyz
1008
+ @db.sqls.should == ['ALTER TABLE abc RENAME TO xyz']
1009
+ end
1010
+ end
1011
+
1012
+ describe "Database#create_view" do
1013
+ before do
1014
+ @db = DummyDatabase.new
1015
+ end
1016
+
1017
+ specify "should construct proper SQL with raw SQL" do
1018
+ @db.create_view :test, "SELECT * FROM xyz"
1019
+ @db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
1020
+ @db.sqls.clear
1021
+ @db.create_view :test.identifier, "SELECT * FROM xyz"
1022
+ @db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
1023
+ end
1024
+
1025
+ specify "should construct proper SQL with dataset" do
1026
+ @db.create_view :test, @db[:items].select(:a, :b).order(:c)
1027
+ @db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
1028
+ @db.sqls.clear
1029
+ @db.create_view :test.qualify(:sch), @db[:items].select(:a, :b).order(:c)
1030
+ @db.sqls.should == ['CREATE VIEW sch.test AS SELECT a, b FROM items ORDER BY c']
1031
+ end
1032
+ end
1033
+
1034
+ describe "Database#create_or_replace_view" do
1035
+ before do
1036
+ @db = DummyDatabase.new
1037
+ end
1038
+
1039
+ specify "should construct proper SQL with raw SQL" do
1040
+ @db.create_or_replace_view :test, "SELECT * FROM xyz"
1041
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT * FROM xyz']
1042
+ @db.sqls.clear
1043
+ @db.create_or_replace_view :sch__test, "SELECT * FROM xyz"
1044
+ @db.sqls.should == ['CREATE OR REPLACE VIEW sch.test AS SELECT * FROM xyz']
1045
+ end
1046
+
1047
+ specify "should construct proper SQL with dataset" do
1048
+ @db.create_or_replace_view :test, @db[:items].select(:a, :b).order(:c)
1049
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
1050
+ @db.sqls.clear
1051
+ @db.create_or_replace_view :test.identifier, @db[:items].select(:a, :b).order(:c)
1052
+ @db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
1053
+ end
1054
+ end
1055
+
1056
+ describe "Database#drop_view" do
1057
+ before do
1058
+ @db = DummyDatabase.new
1059
+ end
1060
+
1061
+ specify "should construct proper SQL" do
1062
+ @db.drop_view :test
1063
+ @db.drop_view :test.identifier
1064
+ @db.drop_view :sch__test
1065
+ @db.drop_view :test.qualify(:sch)
1066
+ @db.sqls.should == ['DROP VIEW test', 'DROP VIEW test', 'DROP VIEW sch.test', 'DROP VIEW sch.test']
1067
+ end
1068
+
1069
+ specify "should drop multiple views at once" do
1070
+ @db.drop_view :cats, :dogs
1071
+ @db.sqls.should == ['DROP VIEW cats', 'DROP VIEW dogs']
1072
+ end
1073
+
1074
+ specify "should take an options hash and support the :cascade option" do
1075
+ @db.drop_view :cats, :dogs, :cascade=>true
1076
+ @db.sqls.should == ['DROP VIEW cats CASCADE', 'DROP VIEW dogs CASCADE']
1077
+ end
1078
+ end
1079
+
1080
+ describe "Database#alter_table_sql" do
1081
+ before do
1082
+ @db = DummyDatabase.new
1083
+ end
1084
+
1085
+ specify "should raise error for an invalid op" do
1086
+ proc {@db.send(:alter_table_sql, :mau, :op => :blah)}.should raise_error(Sequel::Error)
1087
+ end
1088
+ end
1089
+
766
1090
  describe "Schema Parser" do
767
1091
  before do
768
1092
  @sqls = []
@@ -829,7 +1153,6 @@ describe "Schema Parser" do
829
1153
  @db.schema(:"time with time zone").first.last[:type].should == :time
830
1154
  @db.schema(:"time without time zone").first.last[:type].should == :time
831
1155
  @db.schema(:boolean).first.last[:type].should == :boolean
832
- @db.schema(:bit).first.last[:type].should == :boolean
833
1156
  @db.schema(:real).first.last[:type].should == :float
834
1157
  @db.schema(:float).first.last[:type].should == :float
835
1158
  @db.schema(:double).first.last[:type].should == :float