sequel 4.45.0 → 4.46.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +108 -0
  3. data/doc/release_notes/4.46.0.txt +404 -0
  4. data/doc/security.rdoc +9 -0
  5. data/doc/sql.rdoc +2 -2
  6. data/doc/testing.rdoc +1 -1
  7. data/doc/validations.rdoc +1 -2
  8. data/lib/sequel/adapters/ado.rb +8 -3
  9. data/lib/sequel/adapters/ado/access.rb +8 -4
  10. data/lib/sequel/adapters/ado/mssql.rb +3 -1
  11. data/lib/sequel/adapters/amalgalite.rb +5 -0
  12. data/lib/sequel/adapters/cubrid.rb +16 -7
  13. data/lib/sequel/adapters/do.rb +7 -1
  14. data/lib/sequel/adapters/do/mysql.rb +8 -4
  15. data/lib/sequel/adapters/ibmdb.rb +10 -5
  16. data/lib/sequel/adapters/jdbc.rb +8 -2
  17. data/lib/sequel/adapters/jdbc/as400.rb +10 -3
  18. data/lib/sequel/adapters/jdbc/db2.rb +27 -16
  19. data/lib/sequel/adapters/jdbc/derby.rb +47 -20
  20. data/lib/sequel/adapters/jdbc/h2.rb +13 -7
  21. data/lib/sequel/adapters/jdbc/hsqldb.rb +18 -9
  22. data/lib/sequel/adapters/jdbc/mssql.rb +5 -2
  23. data/lib/sequel/adapters/jdbc/mysql.rb +3 -2
  24. data/lib/sequel/adapters/jdbc/oracle.rb +3 -2
  25. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -3
  26. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +2 -1
  27. data/lib/sequel/adapters/jdbc/sqlite.rb +10 -3
  28. data/lib/sequel/adapters/jdbc/sqlserver.rb +23 -0
  29. data/lib/sequel/adapters/jdbc/transactions.rb +16 -10
  30. data/lib/sequel/adapters/mock.rb +5 -0
  31. data/lib/sequel/adapters/mysql.rb +8 -1
  32. data/lib/sequel/adapters/mysql2.rb +6 -1
  33. data/lib/sequel/adapters/odbc.rb +20 -8
  34. data/lib/sequel/adapters/odbc/mssql.rb +6 -3
  35. data/lib/sequel/adapters/oracle.rb +12 -6
  36. data/lib/sequel/adapters/postgres.rb +20 -8
  37. data/lib/sequel/adapters/shared/access.rb +76 -47
  38. data/lib/sequel/adapters/shared/cubrid.rb +16 -11
  39. data/lib/sequel/adapters/shared/db2.rb +46 -19
  40. data/lib/sequel/adapters/shared/firebird.rb +20 -8
  41. data/lib/sequel/adapters/shared/informix.rb +6 -3
  42. data/lib/sequel/adapters/shared/mssql.rb +132 -72
  43. data/lib/sequel/adapters/shared/mysql.rb +112 -65
  44. data/lib/sequel/adapters/shared/oracle.rb +36 -21
  45. data/lib/sequel/adapters/shared/postgres.rb +91 -56
  46. data/lib/sequel/adapters/shared/sqlanywhere.rb +65 -37
  47. data/lib/sequel/adapters/shared/sqlite.rb +67 -32
  48. data/lib/sequel/adapters/sqlanywhere.rb +9 -1
  49. data/lib/sequel/adapters/sqlite.rb +8 -1
  50. data/lib/sequel/adapters/swift.rb +5 -0
  51. data/lib/sequel/adapters/swift/mysql.rb +4 -2
  52. data/lib/sequel/adapters/swift/sqlite.rb +1 -1
  53. data/lib/sequel/adapters/tinytds.rb +10 -3
  54. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
  55. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
  56. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -0
  57. data/lib/sequel/adapters/utils/pg_types.rb +14 -6
  58. data/lib/sequel/adapters/utils/replace.rb +4 -2
  59. data/lib/sequel/connection_pool/single.rb +2 -2
  60. data/lib/sequel/core.rb +24 -11
  61. data/lib/sequel/database/connecting.rb +9 -3
  62. data/lib/sequel/database/dataset_defaults.rb +7 -1
  63. data/lib/sequel/database/logging.rb +1 -0
  64. data/lib/sequel/database/misc.rb +5 -2
  65. data/lib/sequel/database/query.rb +7 -5
  66. data/lib/sequel/database/schema_generator.rb +1 -0
  67. data/lib/sequel/database/schema_methods.rb +50 -27
  68. data/lib/sequel/database/transactions.rb +19 -9
  69. data/lib/sequel/dataset/actions.rb +15 -6
  70. data/lib/sequel/dataset/graph.rb +15 -5
  71. data/lib/sequel/dataset/misc.rb +12 -4
  72. data/lib/sequel/dataset/mutation.rb +17 -8
  73. data/lib/sequel/dataset/prepared_statements.rb +3 -2
  74. data/lib/sequel/dataset/query.rb +84 -38
  75. data/lib/sequel/dataset/sql.rb +302 -191
  76. data/lib/sequel/deprecated.rb +26 -17
  77. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +2 -2
  78. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  79. data/lib/sequel/extensions/from_block.rb +1 -0
  80. data/lib/sequel/extensions/graph_each.rb +1 -1
  81. data/lib/sequel/extensions/identifier_mangling.rb +2 -2
  82. data/lib/sequel/extensions/migration.rb +28 -4
  83. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -0
  84. data/lib/sequel/extensions/schema_dumper.rb +4 -4
  85. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +5 -3
  86. data/lib/sequel/extensions/set_overrides.rb +2 -0
  87. data/lib/sequel/extensions/split_array_nil.rb +2 -2
  88. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  89. data/lib/sequel/model.rb +11 -7
  90. data/lib/sequel/model/associations.rb +5 -7
  91. data/lib/sequel/model/base.rb +47 -45
  92. data/lib/sequel/model/dataset_module.rb +9 -14
  93. data/lib/sequel/model/plugins.rb +3 -0
  94. data/lib/sequel/no_core_ext.rb +1 -0
  95. data/lib/sequel/plugins/blacklist_security.rb +1 -1
  96. data/lib/sequel/plugins/boolean_subsets.rb +7 -5
  97. data/lib/sequel/plugins/class_table_inheritance.rb +47 -10
  98. data/lib/sequel/plugins/dataset_associations.rb +1 -1
  99. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  100. data/lib/sequel/plugins/finder.rb +240 -0
  101. data/lib/sequel/plugins/inverted_subsets.rb +19 -12
  102. data/lib/sequel/plugins/many_through_many.rb +1 -1
  103. data/lib/sequel/plugins/nested_attributes.rb +1 -1
  104. data/lib/sequel/plugins/schema.rb +1 -1
  105. data/lib/sequel/plugins/single_table_inheritance.rb +7 -1
  106. data/lib/sequel/plugins/subset_conditions.rb +11 -3
  107. data/lib/sequel/plugins/whitelist_security.rb +118 -0
  108. data/lib/sequel/sql.rb +80 -36
  109. data/lib/sequel/timezones.rb +2 -0
  110. data/lib/sequel/version.rb +1 -1
  111. data/spec/adapters/mssql_spec.rb +20 -0
  112. data/spec/adapters/mysql_spec.rb +1 -1
  113. data/spec/adapters/oracle_spec.rb +12 -8
  114. data/spec/adapters/postgres_spec.rb +1 -1
  115. data/spec/adapters/spec_helper.rb +1 -1
  116. data/spec/adapters/sqlite_spec.rb +36 -34
  117. data/spec/core/connection_pool_spec.rb +2 -1
  118. data/spec/core/database_spec.rb +87 -9
  119. data/spec/core/dataset_spec.rb +501 -129
  120. data/spec/core/deprecated_spec.rb +1 -1
  121. data/spec/core/expression_filters_spec.rb +146 -60
  122. data/spec/core/mock_adapter_spec.rb +1 -1
  123. data/spec/core/object_graph_spec.rb +61 -9
  124. data/spec/core/placeholder_literalizer_spec.rb +20 -2
  125. data/spec/core/schema_generator_spec.rb +6 -6
  126. data/spec/core/schema_spec.rb +54 -5
  127. data/spec/core_extensions_spec.rb +122 -18
  128. data/spec/deprecation_helper.rb +27 -2
  129. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +6 -6
  130. data/spec/extensions/association_proxies_spec.rb +2 -2
  131. data/spec/extensions/auto_literal_strings_spec.rb +212 -0
  132. data/spec/extensions/blacklist_security_spec.rb +1 -0
  133. data/spec/extensions/class_table_inheritance_spec.rb +1037 -39
  134. data/spec/extensions/column_select_spec.rb +20 -8
  135. data/spec/extensions/columns_introspection_spec.rb +3 -3
  136. data/spec/extensions/core_refinements_spec.rb +29 -12
  137. data/spec/extensions/dataset_associations_spec.rb +12 -12
  138. data/spec/extensions/def_dataset_method_spec.rb +100 -0
  139. data/spec/extensions/error_sql_spec.rb +1 -1
  140. data/spec/extensions/finder_spec.rb +260 -0
  141. data/spec/extensions/graph_each_spec.rb +2 -2
  142. data/spec/extensions/identifier_mangling_spec.rb +14 -8
  143. data/spec/extensions/inverted_subsets_spec.rb +4 -4
  144. data/spec/extensions/lazy_attributes_spec.rb +7 -0
  145. data/spec/extensions/many_through_many_spec.rb +38 -14
  146. data/spec/extensions/nested_attributes_spec.rb +18 -6
  147. data/spec/extensions/no_auto_literal_strings_spec.rb +1 -1
  148. data/spec/extensions/pg_enum_spec.rb +16 -1
  149. data/spec/extensions/pg_interval_spec.rb +11 -2
  150. data/spec/extensions/pg_loose_count_spec.rb +5 -0
  151. data/spec/extensions/pg_row_spec.rb +25 -0
  152. data/spec/extensions/prepared_statements_spec.rb +10 -1
  153. data/spec/extensions/query_spec.rb +2 -2
  154. data/spec/extensions/schema_dumper_spec.rb +2 -2
  155. data/spec/extensions/schema_spec.rb +2 -2
  156. data/spec/extensions/set_overrides_spec.rb +7 -3
  157. data/spec/extensions/sql_expr_spec.rb +0 -1
  158. data/spec/extensions/subset_conditions_spec.rb +6 -6
  159. data/spec/extensions/table_select_spec.rb +24 -12
  160. data/spec/extensions/to_dot_spec.rb +4 -4
  161. data/spec/extensions/whitelist_security_spec.rb +131 -0
  162. data/spec/integration/dataset_test.rb +9 -5
  163. data/spec/integration/model_test.rb +2 -0
  164. data/spec/integration/plugin_test.rb +2 -2
  165. data/spec/integration/spec_helper.rb +1 -1
  166. data/spec/model/associations_spec.rb +39 -11
  167. data/spec/model/base_spec.rb +44 -24
  168. data/spec/model/class_dataset_methods_spec.rb +18 -16
  169. data/spec/model/dataset_methods_spec.rb +4 -4
  170. data/spec/model/eager_loading_spec.rb +84 -24
  171. data/spec/model/model_spec.rb +97 -63
  172. data/spec/model/record_spec.rb +21 -13
  173. metadata +13 -2
@@ -5,7 +5,7 @@ module Sequel
5
5
  MAJOR = 4
6
6
  # The minor version of Sequel. Bumped for every non-patch level
7
7
  # release, generally around once a month.
8
- MINOR = 45
8
+ MINOR = 46
9
9
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
10
10
  # releases that fix regressions from previous versions.
11
11
  TINY = 0
@@ -68,6 +68,26 @@ describe "MSSQL" do
68
68
  it "should should support OUTER APPLY" do
69
69
  @db[:test3].outer_apply(@db[:test4].where(Sequel[:test3][:v3]=>Sequel[:test4][:v4])).select_order_map([:v3, :v4]).must_equal [[1,1], [2, nil]]
70
70
  end
71
+
72
+ cspecify "should handle time values with fractional seconds", [:ado] do
73
+ # ado: Returns nil values
74
+ t = Sequel::SQLTime.create(10, 20, 30, 999900)
75
+ v = @db.get(Sequel.cast(t, 'time'))
76
+ v = Sequel.string_to_time(v) if v.is_a?(String)
77
+ pr = lambda{|x| [:hour, :min, :sec, :usec].map{|m| x.send(m)}}
78
+ pr[v].must_equal(pr[t])
79
+ end
80
+
81
+ cspecify "should get datetimeoffset values as Time with fractional seconds", [:odbc], [:ado], [:tinytds, proc{|db| TinyTds::VERSION < '0.9'}] do
82
+ # odbc: Returns string rounded to nearest second
83
+ # ado: Returns nil values
84
+ # tiny_tds < 0.9: Returns wrong value for hour
85
+ t = Time.local(2010, 11, 12, 10, 20, 30, 999000)
86
+ v = @db.get(Sequel.cast(t, 'datetimeoffset'))
87
+ v = Sequel.string_to_datetime(v) if v.is_a?(String)
88
+ pr = lambda{|x| [:year, :month, :day, :hour, :min, :sec, :usec].map{|m| x.send(m)}}
89
+ pr[v].must_equal(pr[t])
90
+ end
71
91
  end
72
92
 
73
93
  # This spec is currently disabled as the SQL Server 2008 R2 Express doesn't support
@@ -354,7 +354,7 @@ describe "A MySQL database" do
354
354
 
355
355
  it "should handle qualified tables in #indexes" do
356
356
  DB.create_table!(:test_innodb){primary_key :id; String :name; index :name, :unique=>true, :name=>:test_innodb_name_idx}
357
- DB.indexes(Sequel.qualify(DB.get{database{}}, :test_innodb)).must_equal(:test_innodb_name_idx=>{:unique=>true, :columns=>[:name]})
357
+ DB.indexes(Sequel.qualify(DB.get{database.function}, :test_innodb)).must_equal(:test_innodb_name_idx=>{:unique=>true, :columns=>[:name]})
358
358
  end
359
359
  end
360
360
 
@@ -63,15 +63,19 @@ describe "An Oracle database" do
63
63
  DB.view_exists?(:cats).must_equal false
64
64
  DB.create_view(:cats, DB[:categories])
65
65
  DB.view_exists?(:cats).must_equal true
66
- om = DB.identifier_output_method
67
- im = DB.identifier_input_method
68
- DB.identifier_output_method = :reverse
69
- DB.identifier_input_method = :reverse
70
- DB.view_exists?(:STAC).must_equal true
71
- DB.view_exists?(:cats).must_equal false
66
+ if IDENTIFIER_MANGLING && !DB.frozen?
67
+ om = DB.identifier_output_method
68
+ im = DB.identifier_input_method
69
+ DB.identifier_output_method = :reverse
70
+ DB.identifier_input_method = :reverse
71
+ DB.view_exists?(:STAC).must_equal true
72
+ DB.view_exists?(:cats).must_equal false
73
+ end
72
74
  ensure
73
- DB.identifier_output_method = om
74
- DB.identifier_input_method = im
75
+ if IDENTIFIER_MANGLING && !DB.frozen?
76
+ DB.identifier_output_method = om
77
+ DB.identifier_input_method = im
78
+ end
75
79
  DB.drop_view(:cats)
76
80
  end
77
81
  end
@@ -463,7 +463,7 @@ describe "A PostgreSQL dataset" do
463
463
  end if DB.server_version >= 90300
464
464
 
465
465
  it "should support ordered-set and hypothetical-set aggregate functions" do
466
- @d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{mode{}.within_group(:a)}.must_equal 1
466
+ @d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{mode.function.within_group(:a)}.must_equal 1
467
467
  end if DB.server_version >= 90400
468
468
 
469
469
  it "should support filtered aggregate functions" do
@@ -40,7 +40,7 @@ class Minitest::HooksSpec
40
40
  end
41
41
  end
42
42
 
43
- IDENTIFIER_MANGLING = !ENV['SEQUEL_NO_MANGLE'] unless defined?(IDENTIFIER_MANGLING)
43
+ IDENTIFIER_MANGLING = !!ENV['SEQUEL_IDENTIFIER_MANGLING'] unless defined?(IDENTIFIER_MANGLING)
44
44
 
45
45
  unless defined?(DB)
46
46
  env_var = "SEQUEL_#{SEQUEL_ADAPTER_TEST.to_s.upcase}_URL"
@@ -5,19 +5,23 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
5
5
  describe "An SQLite database" do
6
6
  before do
7
7
  @db = DB
8
+ deprecated do
8
9
  @fk = @db.foreign_keys
10
+ end
9
11
  end
10
12
  after do
11
13
  @db.drop_table?(:fk)
12
- @db.auto_vacuum = :none
13
- @db.run 'VACUUM'
14
- @db.foreign_keys = @fk
15
- @db.case_sensitive_like = true
14
+ deprecated do
15
+ @db.auto_vacuum = :none
16
+ @db.run 'VACUUM'
17
+ @db.foreign_keys = @fk
18
+ @db.case_sensitive_like = true
19
+ end
16
20
  @db.use_timestamp_timezones = false
17
21
  Sequel.datetime_class = Time
18
22
  end
19
23
 
20
- it "should support getting setting pragma values" do
24
+ deprecated "should support getting setting pragma values" do
21
25
  @db.pragma_set(:auto_vacuum, '0')
22
26
  @db.run 'VACUUM'
23
27
  @db.pragma_get(:auto_vacuum).to_s.must_equal '0'
@@ -29,7 +33,7 @@ describe "An SQLite database" do
29
33
  @db.pragma_get(:auto_vacuum).to_s.must_equal '2'
30
34
  end
31
35
 
32
- it "should support getting and setting the auto_vacuum pragma" do
36
+ deprecated "should support getting and setting the auto_vacuum pragma" do
33
37
  @db.auto_vacuum = :full
34
38
  @db.run 'VACUUM'
35
39
  @db.auto_vacuum.must_equal :full
@@ -40,12 +44,12 @@ describe "An SQLite database" do
40
44
  proc {@db.auto_vacuum = :invalid}.must_raise(Sequel::Error)
41
45
  end
42
46
 
43
- it "should respect case sensitive like false" do
47
+ deprecated "should respect case sensitive like false" do
44
48
  @db.case_sensitive_like = false
45
49
  @db.get(Sequel.like('a', 'A')).to_s.must_equal '1'
46
50
  end
47
51
 
48
- it "should respect case sensitive like true" do
52
+ deprecated "should respect case sensitive like true" do
49
53
  @db.case_sensitive_like = true
50
54
  @db.get(Sequel.like('a', 'A')).to_s.must_equal '0'
51
55
  end
@@ -63,13 +67,13 @@ describe "An SQLite database" do
63
67
  @db.sqlite_version.must_be_kind_of(Integer)
64
68
  end
65
69
 
66
- it "should support setting and getting the foreign_keys pragma" do
70
+ deprecated "should support setting and getting the foreign_keys pragma" do
67
71
  (@db.sqlite_version >= 30619 ? [true, false] : [nil]).must_include(@db.foreign_keys)
68
72
  @db.foreign_keys = true
69
73
  @db.foreign_keys = false
70
74
  end
71
75
 
72
- it "should enforce foreign key integrity if foreign_keys pragma is set" do
76
+ deprecated "should enforce foreign key integrity if foreign_keys pragma is set" do
73
77
  @db.foreign_keys = true
74
78
  @db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
75
79
  @db[:fk].insert(1, nil)
@@ -78,7 +82,7 @@ describe "An SQLite database" do
78
82
  proc{@db[:fk].insert(4, 5)}.must_raise(Sequel::ForeignKeyConstraintViolation, Sequel::ConstraintViolation, Sequel::DatabaseError)
79
83
  end if DB.sqlite_version >= 30619
80
84
 
81
- it "should not enforce foreign key integrity if foreign_keys pragma is unset" do
85
+ deprecated "should not enforce foreign key integrity if foreign_keys pragma is unset" do
82
86
  @db.foreign_keys = false
83
87
  @db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
84
88
  @db[:fk].insert(1, 2)
@@ -104,7 +108,7 @@ describe "An SQLite database" do
104
108
  @db.tables.must_include(:fk)
105
109
  end
106
110
 
107
- it "should support getting and setting the synchronous pragma" do
111
+ deprecated "should support getting and setting the synchronous pragma" do
108
112
  @db.synchronous = :off
109
113
  @db.synchronous.must_equal :off
110
114
  @db.synchronous = :normal
@@ -115,7 +119,7 @@ describe "An SQLite database" do
115
119
  proc {@db.synchronous = :invalid}.must_raise(Sequel::Error)
116
120
  end
117
121
 
118
- it "should support getting and setting the temp_store pragma" do
122
+ deprecated "should support getting and setting the temp_store pragma" do
119
123
  @db.temp_store = :default
120
124
  @db.temp_store.must_equal :default
121
125
  @db.temp_store = :file
@@ -527,30 +531,28 @@ describe "A SQLite database" do
527
531
  @db[:test3].select(:id).all.must_equal [{:id => 1}, {:id => 3}]
528
532
  end
529
533
 
530
- if DB.foreign_keys
531
- it "should keep foreign keys when dropping a column" do
532
- @db.create_table! :test do
533
- primary_key :id
534
- String :name
535
- Integer :value
536
- end
537
- @db.create_table! :test3 do
538
- String :name
539
- Integer :value
540
- foreign_key :test_id, :test, :on_delete => :set_null, :on_update => :cascade
541
- end
534
+ it "should keep foreign keys when dropping a column" do
535
+ @db.create_table! :test do
536
+ primary_key :id
537
+ String :name
538
+ Integer :value
539
+ end
540
+ @db.create_table! :test3 do
541
+ String :name
542
+ Integer :value
543
+ foreign_key :test_id, :test, :on_delete => :set_null, :on_update => :cascade
544
+ end
542
545
 
543
- @db[:test3].insert(:name => "abc", :test_id => @db[:test].insert(:name => "foo", :value => 3))
544
- @db[:test3].insert(:name => "def", :test_id => @db[:test].insert(:name => "bar", :value => 4))
546
+ @db[:test3].insert(:name => "abc", :test_id => @db[:test].insert(:name => "foo", :value => 3))
547
+ @db[:test3].insert(:name => "def", :test_id => @db[:test].insert(:name => "bar", :value => 4))
545
548
 
546
- @db.drop_column :test3, :value
549
+ @db.drop_column :test3, :value
547
550
 
548
- @db[:test].filter(:name => 'bar').delete
549
- @db[:test3][:name => 'def'][:test_id].must_be_nil
551
+ @db[:test].filter(:name => 'bar').delete
552
+ @db[:test3][:name => 'def'][:test_id].must_be_nil
550
553
 
551
- @db[:test].filter(:name => 'foo').update(:id=>100)
552
- @db[:test3][:name => 'abc'][:test_id].must_equal 100
553
- end
554
+ @db[:test].filter(:name => 'foo').update(:id=>100)
555
+ @db[:test3][:name => 'abc'][:test_id].must_equal 100
554
556
  end
555
557
 
556
558
  it "should support rename_column operations" do
@@ -690,7 +692,7 @@ describe "A SQLite database" do
690
692
  sqls.last.must_equal "BEGIN DEFERRED TRANSACTION"
691
693
  end
692
694
  @db.transaction do
693
- sqls.last.must_equal Sequel::Database::SQL_BEGIN
695
+ sqls.last.must_equal 'BEGIN'
694
696
  end
695
697
 
696
698
  @db.transaction_mode.must_be_nil
@@ -761,11 +761,12 @@ describe "SingleConnectionPool" do
761
761
  it "should provide a #disconnect method" do
762
762
  conn = nil
763
763
  x = nil
764
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| conn = c}){1234}, ST_CONNECTION_POOL_DEFAULTS)
764
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| conn = c; c.must_be_kind_of(Integer)}){1234}, ST_CONNECTION_POOL_DEFAULTS)
765
765
  pool.hold{|c| x = c}
766
766
  x.must_equal 1234
767
767
  pool.disconnect
768
768
  conn.must_equal 1234
769
+ pool.disconnect
769
770
  end
770
771
  end
771
772
 
@@ -38,6 +38,7 @@ describe "A new Database" do
38
38
  it "should support :preconnect option to preconnect to database" do
39
39
  @db.pool.size.must_equal 0
40
40
  c = Class.new(Sequel::Database) do
41
+ def dataset_class_default; Sequel::Dataset end
41
42
  def connect(_)
42
43
  :connect
43
44
  end
@@ -191,17 +192,17 @@ describe "Database#log_yield" do
191
192
  @db = Sequel::Database.new(:logger=>@o)
192
193
  end
193
194
 
194
- it "should yield to the passed block" do
195
+ deprecated "should yield to the passed block" do
195
196
  a = nil
196
197
  @db.log_yield('blah'){a = 1}
197
198
  a.must_equal 1
198
199
  end
199
200
 
200
- it "should raise an exception if a block is not passed" do
201
+ deprecated "should raise an exception if a block is not passed" do
201
202
  proc{@db.log_yield('blah')}.must_raise LocalJumpError
202
203
  end
203
204
 
204
- it "should log message with duration at info level to all loggers" do
205
+ deprecated "should log message with duration at info level to all loggers" do
205
206
  @db.log_yield('blah'){}
206
207
  @o.logs.length.must_equal 1
207
208
  @o.logs.first.length.must_equal 2
@@ -209,7 +210,7 @@ describe "Database#log_yield" do
209
210
  @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
210
211
  end
211
212
 
212
- it "should respect sql_log_level setting" do
213
+ deprecated "should respect sql_log_level setting" do
213
214
  @db.sql_log_level = :debug
214
215
  @db.log_yield('blah'){}
215
216
  @o.logs.length.must_equal 1
@@ -218,7 +219,7 @@ describe "Database#log_yield" do
218
219
  @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
219
220
  end
220
221
 
221
- it "should log message with duration at warn level if duration greater than log_warn_duration" do
222
+ deprecated "should log message with duration at warn level if duration greater than log_warn_duration" do
222
223
  @db.log_warn_duration = 0
223
224
  @db.log_yield('blah'){}
224
225
  @o.logs.length.must_equal 1
@@ -227,7 +228,7 @@ describe "Database#log_yield" do
227
228
  @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
228
229
  end
229
230
 
230
- it "should log message with duration at info level if duration less than log_warn_duration" do
231
+ deprecated "should log message with duration at info level if duration less than log_warn_duration" do
231
232
  @db.log_warn_duration = 1000
232
233
  @db.log_yield('blah'){}
233
234
  @o.logs.length.must_equal 1
@@ -236,7 +237,7 @@ describe "Database#log_yield" do
236
237
  @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
237
238
  end
238
239
 
239
- it "should log message at error level if block raises an error" do
240
+ deprecated "should log message at error level if block raises an error" do
240
241
  @db.log_warn_duration = 0
241
242
  proc{@db.log_yield('blah'){raise Sequel::Error, 'adsf'}}.must_raise Sequel::Error
242
243
  @o.logs.length.must_equal 1
@@ -245,7 +246,7 @@ describe "Database#log_yield" do
245
246
  @o.logs.first.last.must_match(/\ASequel::Error: adsf: blah\z/)
246
247
  end
247
248
 
248
- it "should include args with message if args passed" do
249
+ deprecated "should include args with message if args passed" do
249
250
  @db.log_yield('blah', [1, 2]){}
250
251
  @o.logs.length.must_equal 1
251
252
  @o.logs.first.length.must_equal 2
@@ -259,6 +260,7 @@ describe "Database#log_connection_yield" do
259
260
  @o = Object.new
260
261
  def @o.logs; @logs || []; end
261
262
  def @o.to_ary; [self]; end
263
+ def @o.warn(*args); (@logs ||= []) << [:warn] + args; end
262
264
  def @o.method_missing(*args); (@logs ||= []) << args; end
263
265
  @conn = Object.new
264
266
  @db = Sequel::Database.new(:logger=>@o)
@@ -281,11 +283,74 @@ describe "Database#log_connection_yield" do
281
283
  @o.logs.first.first.must_equal :info
282
284
  @o.logs.first.last.must_match(/\(conn: -?\d+\) some SQL\z/)
283
285
  end
286
+
287
+ it "should yield to the passed block" do
288
+ a = nil
289
+ @db.log_connection_yield('blah', @conn){a = 1}
290
+ a.must_equal 1
291
+ end
292
+
293
+ it "should raise an exception if a block is not passed" do
294
+ proc{@db.log_connection_yield('blah', @conn)}.must_raise LocalJumpError
295
+ end
296
+
297
+ it "should log message with duration at info level to all loggers" do
298
+ @db.log_connection_yield('blah', @conn){}
299
+ @o.logs.length.must_equal 1
300
+ @o.logs.first.length.must_equal 2
301
+ @o.logs.first.first.must_equal :info
302
+ @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
303
+ end
304
+
305
+ it "should respect sql_log_level setting" do
306
+ @db.sql_log_level = :debug
307
+ @db.log_connection_yield('blah', @conn){}
308
+ @o.logs.length.must_equal 1
309
+ @o.logs.first.length.must_equal 2
310
+ @o.logs.first.first.must_equal :debug
311
+ @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
312
+ end
313
+
314
+ it "should log message with duration at warn level if duration greater than log_warn_duration" do
315
+ @db.log_warn_duration = 0
316
+ @db.log_connection_yield('blah', @conn){}
317
+ @o.logs.length.must_equal 1
318
+ @o.logs.first.length.must_equal 2
319
+ @o.logs.first.first.must_equal :warn
320
+ @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
321
+ end
322
+
323
+ it "should log message with duration at info level if duration less than log_warn_duration" do
324
+ @db.log_warn_duration = 1000
325
+ @db.log_connection_yield('blah', @conn){}
326
+ @o.logs.length.must_equal 1
327
+ @o.logs.first.length.must_equal 2
328
+ @o.logs.first.first.must_equal :info
329
+ @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
330
+ end
331
+
332
+ it "should log message at error level if block raises an error" do
333
+ @db.log_warn_duration = 0
334
+ proc{@db.log_connection_yield('blah', @conn){raise Sequel::Error, 'adsf'}}.must_raise Sequel::Error
335
+ @o.logs.length.must_equal 1
336
+ @o.logs.first.length.must_equal 2
337
+ @o.logs.first.first.must_equal :error
338
+ @o.logs.first.last.must_match(/\ASequel::Error: adsf: blah\z/)
339
+ end
340
+
341
+ it "should include args with message if args passed" do
342
+ @db.log_connection_yield('blah', @conn, [1, 2]){}
343
+ @o.logs.length.must_equal 1
344
+ @o.logs.first.length.must_equal 2
345
+ @o.logs.first.first.must_equal :info
346
+ @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah; \[1, 2\]\z/)
347
+ end
284
348
  end
285
349
 
286
350
  describe "Database#uri" do
287
351
  before do
288
352
  @c = Class.new(Sequel::Database) do
353
+ def dataset_class_default; Sequel::Dataset end
289
354
  set_adapter_scheme :mau
290
355
  end
291
356
 
@@ -310,6 +375,7 @@ describe "Database.adapter_scheme and #adapter_scheme" do
310
375
  Sequel::Database.adapter_scheme.must_be_nil
311
376
 
312
377
  @c = Class.new(Sequel::Database) do
378
+ def dataset_class_default; Sequel::Dataset end
313
379
  set_adapter_scheme :mau
314
380
  end
315
381
 
@@ -723,6 +789,18 @@ DatabaseTransactionSpecs = shared_description do
723
789
  @db.sqls.must_equal ['BEGIN']
724
790
  end
725
791
 
792
+ it "should raise original exception if there is an exception raised when rolling back when using :rollback=>:always" do
793
+ ec = Class.new(StandardError)
794
+ meta_def(@db, :database_error_classes){[ec]}
795
+ meta_def(@db, :log_connection_execute){|c, sql| sql =~ /ROLLBACK/ ? raise(ec, 'bad') : super(c, sql)}
796
+ begin
797
+ @db.transaction(:rollback=>:always){}
798
+ rescue => e
799
+ end
800
+ e.must_be_kind_of(ec)
801
+ @db.sqls.must_equal ['BEGIN']
802
+ end
803
+
726
804
  it "should issue ROLLBACK if Sequel::Rollback is called in the transaction" do
727
805
  @db.transaction do
728
806
  @db.drop_table(:a)
@@ -834,7 +912,7 @@ DatabaseTransactionSpecs = shared_description do
834
912
  tr.must_be :empty?
835
913
  end
836
914
 
837
- it "should correctly handle nested transacation use with separate shards" do
915
+ it "should correctly handle nested transaction use with separate shards" do
838
916
  @db.transaction do |c1|
839
917
  @db.transaction(:server=>:test) do |c2|
840
918
  c1.wont_equal c2
@@ -310,10 +310,13 @@ describe "Dataset#unused_table_alias" do
310
310
  @ds.from(:test, :test_0).cross_join(:test_1).unused_table_alias(:test).must_equal :test_2
311
311
  end
312
312
 
313
- it "should return an appropriate symbol if given other forms of identifiers" do
314
- @ds.unused_table_alias('test').must_equal :test_0
313
+ with_symbol_splitting "should return an appropriate symbol if given splittable symbol" do
315
314
  @ds.unused_table_alias(:b__t___test).must_equal :test_0
316
315
  @ds.unused_table_alias(:b__test).must_equal :test_0
316
+ end
317
+
318
+ it "should return an appropriate symbol if given other forms of identifiers" do
319
+ @ds.unused_table_alias('test').must_equal :test_0
317
320
  @ds.unused_table_alias(Sequel.qualify(:b, :test)).must_equal :test_0
318
321
  @ds.unused_table_alias(Sequel.expr(:b).as(:test)).must_equal :test_0
319
322
  @ds.unused_table_alias(Sequel.expr(:b).as(Sequel.identifier(:test))).must_equal :test_0
@@ -346,65 +349,116 @@ describe "Dataset#where" do
346
349
  before do
347
350
  @dataset = Sequel.mock[:test]
348
351
  @d1 = @dataset.where(:region => 'Asia')
349
- @d2 = @dataset.where('region = ?', 'Asia')
350
- @d3 = @dataset.where("a = 1")
351
352
  end
352
353
 
353
- it "should just clone if given an empty argument" do
354
+ if false # SEQUEL5: remove if
355
+ it "should just clone if given no arguments or block" do
356
+ proc{@dataset.where}.must_raise Sequel::Error
357
+ end
358
+
359
+ it "should handle nil argument if block is given" do
360
+ @d1.where(nil){a}.sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND NULL AND a)"
361
+ end
362
+
363
+ it "should handle nil argument if block has no existing filter" do
364
+ @dataset.where(nil).sql.must_equal "SELECT * FROM test WHERE NULL"
365
+ end
366
+ end
367
+
368
+ it "should just clone if given an empty array or hash argument" do
354
369
  @dataset.where({}).sql.must_equal @dataset.sql
355
370
  @dataset.where([]).sql.must_equal @dataset.sql
356
- @dataset.where('').sql.must_equal @dataset.sql
357
371
 
358
372
  @dataset.filter({}).sql.must_equal @dataset.sql
359
373
  @dataset.filter([]).sql.must_equal @dataset.sql
374
+ end
375
+
376
+ deprecated "should just clone if given an empty string argument" do
377
+ @dataset.where('').sql.must_equal @dataset.sql
360
378
  @dataset.filter('').sql.must_equal @dataset.sql
361
379
  end
362
380
 
381
+ deprecated "should just clone if given no arguments or block" do
382
+ @dataset.where.sql.must_equal @dataset.sql
383
+ @dataset.filter.sql.must_equal @dataset.sql
384
+ end
385
+
386
+ deprecated "should ignore nil argument if block is given" do
387
+ @d1.where(nil){a}.sql.must_equal @d1.where(:a).sql
388
+ end
389
+
390
+ deprecated "should ignore nil argument if block has no existing filter" do
391
+ @dataset.where(nil).sql.must_equal @dataset.sql
392
+ end
393
+
363
394
  it "should work with hashes" do
364
395
  @dataset.where(:name => 'xyz', :price => 342).select_sql.
365
396
  must_match(/WHERE \(\(name = 'xyz'\) AND \(price = 342\)\)|WHERE \(\(price = 342\) AND \(name = 'xyz'\)\)/)
366
397
  end
367
398
 
368
- it "should work with a string with placeholders and arguments for those placeholders" do
399
+ deprecated "should handle literal strings in arrays in filter methods" do
400
+ @dataset.where([Sequel.lit("a")]).sql.must_equal 'SELECT * FROM test WHERE (a)'
401
+ end
402
+
403
+ deprecated "should work with a string with placeholders and arguments for those placeholders" do
369
404
  @dataset.where('price < ? AND id in ?', 100, [1, 2, 3]).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
370
405
  end
371
406
 
372
- it "should not modify passed array with placeholders" do
407
+ it "should work with a placeholder literal string" do
408
+ @dataset.where(Sequel.lit('price < ? AND id in ?', 100, [1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
409
+ end
410
+
411
+ deprecated "should not modify passed array with placeholders" do
373
412
  a = ['price < ? AND id in ?', 100, 1, 2, 3]
374
413
  b = a.dup
375
414
  @dataset.where(a)
376
415
  b.must_equal a
377
416
  end
378
417
 
379
- it "should work with strings (custom SQL expressions)" do
380
- @dataset.where('(a = 1 AND b = 2)').select_sql.
381
- must_equal "SELECT * FROM test WHERE ((a = 1 AND b = 2))"
418
+ deprecated "should work with strings (custom SQL expressions)" do
419
+ @dataset.where('(a = 1 AND b = 2)').select_sql.must_equal "SELECT * FROM test WHERE ((a = 1 AND b = 2))"
420
+ end
421
+
422
+ it "should work with literal strings" do
423
+ @dataset.where(Sequel.lit('(a = 1 AND b = 2)')).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1 AND b = 2))"
424
+ end
425
+
426
+ deprecated "should work with a string with named placeholders and a hash of placeholder value arguments" do
427
+ @dataset.where('price < :price AND id in :ids', :price=>100, :ids=>[1, 2, 3]).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
382
428
  end
383
429
 
384
- it "should work with a string with named placeholders and a hash of placeholder value arguments" do
385
- @dataset.where('price < :price AND id in :ids', :price=>100, :ids=>[1, 2, 3]).select_sql.
386
- must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
430
+ it "should work with named placeholder strings" do
431
+ @dataset.where(Sequel.lit('price < :price AND id in :ids', :price=>100, :ids=>[1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
387
432
  end
388
433
 
389
- it "should not modify passed array with named placeholders" do
434
+ deprecated "should not modify passed array with named placeholders" do
390
435
  a = ['price < :price AND id in :ids', {:price=>100}]
391
436
  b = a.dup
392
437
  @dataset.where(a)
393
438
  b.must_equal a
394
439
  end
395
440
 
396
- it "should not replace named placeholders that don't exist in the hash" do
441
+ deprecated "should not replace named placeholders that don't exist in the hash" do
397
442
  @dataset.where('price < :price AND id in :ids', :price=>100).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in :ids)"
398
443
  end
399
444
 
400
- it "should raise an error for a mismatched number of placeholders" do
445
+ it "should not replace named placeholders that don't exist in the hash when using placeholder strings" do
446
+ @dataset.where(Sequel.lit('price < :price AND id in :ids', :price=>100)).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in :ids)"
447
+ end
448
+
449
+ deprecated "should raise an error for a mismatched number of placeholders" do
401
450
  proc{@dataset.where('price < ? AND id in ?', 100).select_sql}.must_raise(Sequel::Error)
402
451
  proc{@dataset.where('price < ? AND id in ?', 100, [1, 2, 3], 4).select_sql}.must_raise(Sequel::Error)
403
452
  end
404
453
 
454
+ it "should raise an error for a mismatched number of placeholders in placeholder literal strings" do
455
+ proc{@dataset.where(Sequel.lit('price < ? AND id in ?', 100)).select_sql}.must_raise(Sequel::Error)
456
+ proc{@dataset.where(Sequel.lit('price < ? AND id in ?', 100, [1, 2, 3], 4)).select_sql}.must_raise(Sequel::Error)
457
+ end
458
+
405
459
  it "should handle placeholders when using an array" do
406
- @dataset.where(Sequel.lit(['price < ', ' AND id in '], 100, [1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE price < 100 AND id in (1, 2, 3)"
407
- @dataset.where(Sequel.lit(['price < ', ' AND id in '], 100)).select_sql.must_equal "SELECT * FROM test WHERE price < 100 AND id in "
460
+ @dataset.where(Sequel.lit(['price < ', ' AND id in '], 100, [1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
461
+ @dataset.where(Sequel.lit(['price < ', ' AND id in '], 100)).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in )"
408
462
  end
409
463
 
410
464
  it "should handle a mismatched number of placeholders when using an array" do
@@ -412,24 +466,49 @@ describe "Dataset#where" do
412
466
  proc{@dataset.where(Sequel.lit(['price < ', ' AND id in '], 100, [1, 2, 3], 4)).select_sql}.must_raise(Sequel::Error)
413
467
  end
414
468
 
415
- it "should handle partial names" do
469
+ deprecated "should handle partial names" do
416
470
  @dataset.where('price < :price AND id = :p', :p=>2, :price=>100).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id = 2)"
417
471
  end
418
472
 
419
- it "should handle ::cast syntax when no parameters are supplied" do
473
+ it "should handle partial names when using placeholder literal strings" do
474
+ @dataset.where(Sequel.lit('price < :price AND id = :p', :p=>2, :price=>100)).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id = 2)"
475
+ end
476
+
477
+ deprecated "should handle ::cast syntax when no parameters are supplied" do
420
478
  @dataset.where('price::float = 10', {}).select_sql.must_equal "SELECT * FROM test WHERE (price::float = 10)"
421
479
  @dataset.where('price::float ? 10', {}).select_sql.must_equal "SELECT * FROM test WHERE (price::float ? 10)"
422
480
  end
423
481
 
482
+ it "should handle ::cast syntax when no parameters are supplied when using placeholder strings" do
483
+ @dataset.where(Sequel.lit('price::float = 10', {})).select_sql.must_equal "SELECT * FROM test WHERE (price::float = 10)"
484
+ @dataset.where(Sequel.lit('price::float ? 10', {})).select_sql.must_equal "SELECT * FROM test WHERE (price::float ? 10)"
485
+ end
486
+
424
487
  it "should affect select, delete and update statements" do
425
488
  @d1.select_sql.must_equal "SELECT * FROM test WHERE (region = 'Asia')"
426
489
  @d1.delete_sql.must_equal "DELETE FROM test WHERE (region = 'Asia')"
427
490
  @d1.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
491
+ end
428
492
 
493
+ deprecated "should affect select, delete and update statements when using strings" do
494
+ @d2 = @dataset.where('region = ?', 'Asia')
495
+ @d2.select_sql.must_equal "SELECT * FROM test WHERE (region = 'Asia')"
496
+ @d2.delete_sql.must_equal "DELETE FROM test WHERE (region = 'Asia')"
497
+ @d2.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
498
+
499
+ @d3 = @dataset.where("a = 1")
500
+ @d3.select_sql.must_equal "SELECT * FROM test WHERE (a = 1)"
501
+ @d3.delete_sql.must_equal "DELETE FROM test WHERE (a = 1)"
502
+ @d3.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (a = 1)"
503
+ end
504
+
505
+ it "should affect select, delete and update statements when using literal strings" do
506
+ @d2 = @dataset.where(Sequel.lit('region = ?', 'Asia'))
429
507
  @d2.select_sql.must_equal "SELECT * FROM test WHERE (region = 'Asia')"
430
508
  @d2.delete_sql.must_equal "DELETE FROM test WHERE (region = 'Asia')"
431
509
  @d2.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
432
510
 
511
+ @d3 = @dataset.where(Sequel.lit("a = 1"))
433
512
  @d3.select_sql.must_equal "SELECT * FROM test WHERE (a = 1)"
434
513
  @d3.delete_sql.must_equal "DELETE FROM test WHERE (a = 1)"
435
514
  @d3.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (a = 1)"
@@ -437,27 +516,48 @@ describe "Dataset#where" do
437
516
 
438
517
  it "should be composable using AND operator (for scoping)" do
439
518
  @d1.where(:size => 'big').select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (size = 'big'))"
440
- @d1.where('population > 1000').select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (population > 1000))"
441
- @d1.where('(a > 1) OR (b < 2)').select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND ((a > 1) OR (b < 2)))"
442
- @d1.where('GDP > ?', 1000).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
519
+ @d1.where{population > 1000}.select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (population > 1000))"
520
+ @d1.where{(a > 1) | (b < 2)}.select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND ((a > 1) OR (b < 2)))"
521
+ @d1.where{GDP() > 1000}.select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
522
+ end
523
+
524
+ deprecated "should be composable using AND operator (for scoping) when using strings" do
525
+ @d2 = @dataset.where('region = ?', 'Asia')
443
526
  @d2.where('GDP > ?', 1000).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
444
527
  @d2.where(:name => ['Japan', 'China']).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
445
528
  @d2.where('GDP > ?').select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
529
+
530
+ @d3 = @dataset.where("a = 1")
446
531
  @d3.where('b = 2').select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
447
532
  @d3.where(:c => 3).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
448
533
  @d3.where('d = ?', 4).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
449
534
  end
450
535
 
451
- it "should be composable using AND operator (for scoping) with block" do
452
- @d3.where{e < 5}.select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
536
+ it "should be composable using AND operator (for scoping) when using literal strings" do
537
+ @d2 = @dataset.where(Sequel.lit('region = ?', 'Asia'))
538
+ @d2.where(Sequel.lit('GDP > ?', 1000)).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
539
+ @d2.where(:name => ['Japan', 'China']).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
540
+ @d2.where(Sequel.lit('GDP > ?')).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
541
+
542
+ @d3 = @dataset.where(Sequel.lit("a = 1"))
543
+ @d3.where(Sequel.lit('b = 2')).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
544
+ @d3.where(:c => 3).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
545
+ @d3.where(Sequel.lit('d = ?', 4)).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
546
+ end
547
+
548
+ deprecated "should be composable using AND operator (for scoping) with block and string" do
549
+ @dataset.where("a = 1").where{e < 5}.select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
550
+ end
551
+
552
+ it "should be composable using AND operator (for scoping) with block and literal string" do
553
+ @dataset.where(Sequel.lit("a = 1")).where{e < 5}.select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
453
554
  end
454
555
 
455
556
  it "should accept ranges" do
456
557
  @dataset.filter(:id => 4..7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id <= 7))'
457
558
  @dataset.filter(:id => 4...7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
458
-
459
- @dataset.filter(:table__id => 4..7).sql.must_equal 'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id <= 7))'
460
- @dataset.filter(:table__id => 4...7).sql.must_equal 'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id < 7))'
559
+ @dataset.filter(:id => 4..7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id <= 7))'
560
+ @dataset.filter(:id => 4...7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
461
561
  end
462
562
 
463
563
  it "should accept nil" do
@@ -465,7 +565,7 @@ describe "Dataset#where" do
465
565
  end
466
566
 
467
567
  it "should accept a subquery" do
468
- @dataset.filter('gdp > ?', @d1.select(Sequel.function(:avg, :gdp))).sql.must_equal "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
568
+ @dataset.filter{|o| o.gdp > @d1.select(Sequel.function(:avg, :gdp))}.sql.must_equal "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
469
569
  end
470
570
 
471
571
  it "should handle all types of IN/NOT IN queries with empty arrays" do
@@ -578,16 +678,16 @@ describe "Dataset#where" do
578
678
  x = nil
579
679
  @dataset.filter{|r| x = r; false}
580
680
  x.must_be_kind_of(Sequel::SQL::VirtualRow)
581
- @dataset.filter{|r| ((r.name < 'b') & {r.table__id => 1}) | r.is_active(r.blah, r.xx, r.x__y_z)}.sql.
582
- must_equal "SELECT * FROM test WHERE (((name < 'b') AND (table.id = 1)) OR is_active(blah, xx, x.y_z))"
681
+ @dataset.filter{|r| ((r.name < 'b') & {r.table_id => 1}) | r.is_active(r.blah, r.xx, r.x_y_z)}.sql.
682
+ must_equal "SELECT * FROM test WHERE (((name < 'b') AND (table_id = 1)) OR is_active(blah, xx, x_y_z))"
583
683
  end
584
684
 
585
685
  it "should instance_eval the block in the context of a VirtualRow if the block doesn't request an argument" do
586
686
  x = nil
587
687
  @dataset.filter{x = self; false}
588
688
  x.must_be_kind_of(Sequel::SQL::VirtualRow)
589
- @dataset.filter{((name < 'b') & {table__id => 1}) | is_active(blah, xx, x__y_z)}.sql.
590
- must_equal "SELECT * FROM test WHERE (((name < 'b') AND (table.id = 1)) OR is_active(blah, xx, x.y_z))"
689
+ @dataset.filter{((name < 'b') & {table_id => 1}) | is_active(blah, xx, x_y_z)}.sql.
690
+ must_equal "SELECT * FROM test WHERE (((name < 'b') AND (table_id = 1)) OR is_active(blah, xx, x_y_z))"
591
691
  end
592
692
 
593
693
  it "should handle arbitrary objects" do
@@ -620,9 +720,12 @@ describe "Dataset#or" do
620
720
  @dataset.or(:a => 1).sql.must_equal 'SELECT * FROM test'
621
721
  end
622
722
 
623
- it "should just clone if given an empty argument" do
723
+ it "should just clone if given an empty array or hash argument" do
624
724
  @d1.or({}).sql.must_equal @d1.sql
625
725
  @d1.or([]).sql.must_equal @d1.sql
726
+ end
727
+
728
+ deprecated "should just clone if given an empty string argument" do
626
729
  @d1.or('').sql.must_equal @d1.sql
627
730
  end
628
731
 
@@ -630,8 +733,15 @@ describe "Dataset#or" do
630
733
  @d1.or(:y => 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
631
734
  end
632
735
 
633
- it "should accept all forms of filters" do
736
+ deprecated "should accept string filters" do
634
737
  @d1.or('y > ?', 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
738
+ end
739
+
740
+ it "should accept literal string filters" do
741
+ @d1.or(Sequel.lit('y > ?', 2)).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
742
+ end
743
+
744
+ it "should accept expression filters" do
635
745
  @d1.or(Sequel.expr(:yy) > 3).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
636
746
  end
637
747
 
@@ -663,8 +773,15 @@ describe "Dataset#and" do
663
773
  @d1.and(:y => 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
664
774
  end
665
775
 
666
- it "should accept different types of filters" do
776
+ deprecated "should accept string filters with placeholders" do
667
777
  @d1.and('y > ?', 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
778
+ end
779
+
780
+ it "should accept placeholder literal string filters" do
781
+ @d1.and(Sequel.lit('y > ?', 2)).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
782
+ end
783
+
784
+ it "should accept expression filters" do
668
785
  @d1.and(Sequel.expr(:yy) > 3).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
669
786
  end
670
787
 
@@ -693,14 +810,22 @@ describe "Dataset#exclude" do
693
810
  /WHERE \(\(name != 'Japan'\) OR \(region != 'Asia'\)\)/))
694
811
  end
695
812
 
696
- it "should parenthesize a single string condition correctly" do
813
+ deprecated "should parenthesize a single string condition correctly" do
697
814
  @dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
698
815
  end
699
816
 
700
- it "should parenthesize an array condition correctly" do
817
+ deprecated "should parenthesize an array condition correctly" do
701
818
  @dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
702
819
  end
703
820
 
821
+ it "should parenthesize a single literal string condition correctly" do
822
+ @dataset.exclude(Sequel.lit("region = 'Asia' AND name = 'Japan'")).select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
823
+ end
824
+
825
+ it "should parenthesize a placeholder literal string condition correctly" do
826
+ @dataset.exclude(Sequel.lit('region = ? AND name = ?', 'Asia', 'Japan')).select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
827
+ end
828
+
704
829
  it "should correctly parenthesize when it is used twice" do
705
830
  @dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.must_equal "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
706
831
  end
@@ -763,16 +888,23 @@ describe "Dataset#having" do
763
888
  @grouped = @dataset.group(:region).select(:region, Sequel.function(:sum, :population), Sequel.function(:avg, :gdp))
764
889
  end
765
890
 
766
- it "should just clone if given an empty argument" do
891
+ it "should just clone if given an empty array or hash argument" do
767
892
  @dataset.having({}).sql.must_equal @dataset.sql
768
893
  @dataset.having([]).sql.must_equal @dataset.sql
894
+ end
895
+
896
+ deprecated "should just clone if given an empty string argument" do
769
897
  @dataset.having('').sql.must_equal @dataset.sql
770
898
  end
771
899
 
772
- it "should affect select statements" do
900
+ deprecated "should handle string arguments" do
773
901
  @grouped.having('sum(population) > 10').select_sql.must_equal "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
774
902
  end
775
903
 
904
+ it "should handle literal string arguments" do
905
+ @grouped.having(Sequel.lit('sum(population) > 10')).select_sql.must_equal "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
906
+ end
907
+
776
908
  it "should support proc expressions" do
777
909
  @grouped.having{Sequel.function(:sum, :population) > 10}.sql.must_equal "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
778
910
  end
@@ -908,21 +1040,57 @@ describe "Dataset#as" do
908
1040
  end
909
1041
  end
910
1042
 
911
- describe "Dataset#literal" do
1043
+ describe "Dataset#literal with expressions" do
1044
+ before do
1045
+ @ds = Sequel.mock.dataset
1046
+ end
1047
+
1048
+ it "should convert qualified identifiers into dot notation" do
1049
+ @ds.literal(Sequel[:abc][:def]).must_equal 'abc.def'
1050
+ end
1051
+
1052
+ it "should convert aliased expressions into SQL AS notation" do
1053
+ @ds.literal(Sequel[:xyz].as(:x)).must_equal 'xyz AS x'
1054
+ @ds.literal(Sequel[:abc][:def].as(:x)).must_equal 'abc.def AS x'
1055
+ end
1056
+
1057
+ it "should support names with digits" do
1058
+ @ds.literal(:abc2).must_equal 'abc2'
1059
+ @ds.literal(Sequel[:xx][:yy3]).must_equal 'xx.yy3'
1060
+ @ds.literal(Sequel[:ab34][:temp3_4ax]).must_equal 'ab34.temp3_4ax'
1061
+ @ds.literal(Sequel[:x1].as(:y2)).must_equal 'x1 AS y2'
1062
+ @ds.literal(Sequel[:abc2][:def3].as(:ggg4)).must_equal 'abc2.def3 AS ggg4'
1063
+ end
1064
+
1065
+ it "should support upper case and lower case" do
1066
+ @ds.literal(:ABC).must_equal 'ABC'
1067
+ @ds.literal(Sequel[:Zvashtoy][:aBcD]).must_equal 'Zvashtoy.aBcD'
1068
+ end
1069
+
1070
+ it "should support spaces inside column names" do
1071
+ @ds = @ds.with_quote_identifiers(true)
1072
+ @ds.literal(:"AB C").must_equal '"AB C"'
1073
+ @ds.literal(Sequel[:"Zvas htoy"][:"aB cD"]).must_equal '"Zvas htoy"."aB cD"'
1074
+ @ds.literal(Sequel[:"aB cD"].as(:"XX XX")).must_equal '"aB cD" AS "XX XX"'
1075
+ @ds.literal(Sequel[:"Zva shtoy"][:"aB cD"].as("XX XX")).must_equal '"Zva shtoy"."aB cD" AS "XX XX"'
1076
+ end
1077
+ end
1078
+
1079
+ describe "Dataset#literal with splittable symbols" do
912
1080
  before do
913
1081
  @ds = Sequel.mock.dataset
914
1082
  end
915
1083
 
916
- it "should convert qualified symbol notation into dot notation" do
1084
+ with_symbol_splitting "should convert qualified symbol notation into dot notation" do
917
1085
  @ds.literal(:abc__def).must_equal 'abc.def'
918
1086
  end
919
1087
 
920
- it "should convert AS symbol notation into SQL AS notation" do
1088
+ with_symbol_splitting "should convert AS symbol notation into SQL AS notation" do
921
1089
  @ds.literal(:xyz___x).must_equal 'xyz AS x'
922
1090
  @ds.literal(:abc__def___x).must_equal 'abc.def AS x'
923
1091
  end
924
1092
 
925
- it "should support names with digits" do
1093
+ with_symbol_splitting "should support names with digits" do
926
1094
  @ds.literal(:abc2).must_equal 'abc2'
927
1095
  @ds.literal(:xx__yy3).must_equal 'xx.yy3'
928
1096
  @ds.literal(:ab34__temp3_4ax).must_equal 'ab34.temp3_4ax'
@@ -930,12 +1098,12 @@ describe "Dataset#literal" do
930
1098
  @ds.literal(:abc2__def3___ggg4).must_equal 'abc2.def3 AS ggg4'
931
1099
  end
932
1100
 
933
- it "should support upper case and lower case" do
1101
+ with_symbol_splitting "should support upper case and lower case" do
934
1102
  @ds.literal(:ABC).must_equal 'ABC'
935
1103
  @ds.literal(:Zvashtoy__aBcD).must_equal 'Zvashtoy.aBcD'
936
1104
  end
937
1105
 
938
- it "should support spaces inside column names" do
1106
+ with_symbol_splitting "should support spaces inside column names" do
939
1107
  @ds = @ds.with_quote_identifiers(true)
940
1108
  @ds.literal(:"AB C").must_equal '"AB C"'
941
1109
  @ds.literal(:"Zvas htoy__aB cD").must_equal '"Zvas htoy"."aB cD"'
@@ -980,6 +1148,9 @@ describe "Dataset#literal" do
980
1148
 
981
1149
  it "should literalize symbols as column references" do
982
1150
  @dataset.literal(:name).must_equal "name"
1151
+ end
1152
+
1153
+ with_symbol_splitting "should literalize symbols with embedded qualifiers as column references" do
983
1154
  @dataset.literal(:items__name).must_equal "items.name"
984
1155
  @dataset.literal(:"items__na#m$e").must_equal "items.na#m$e"
985
1156
  end
@@ -1023,6 +1194,13 @@ describe "Dataset#literal" do
1023
1194
  @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).must_equal "'2010-01-02 03:04:05.500'"
1024
1195
  end
1025
1196
 
1197
+ it "should literalize times properly for databases with different time and timestamp precision" do
1198
+ @dataset = @dataset.with_extend{def timestamp_precision; 3 end; def sqltime_precision; 6 end}
1199
+ @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 500000)).must_equal "'01:02:03.500000'"
1200
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5, 500000)).must_equal "'2010-01-02 03:04:05.500'"
1201
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).must_equal "'2010-01-02 03:04:05.500'"
1202
+ end
1203
+
1026
1204
  it "should literalize Date properly" do
1027
1205
  d = Date.today
1028
1206
  s = d.strftime("'%Y-%m-%d'")
@@ -1143,7 +1321,7 @@ describe "Dataset#from" do
1143
1321
  @dataset.select_sql.must_equal "SELECT * FROM DEFFROM"
1144
1322
  end
1145
1323
 
1146
- it "should accept :schema__table___alias symbol format" do
1324
+ with_symbol_splitting "should accept :schema__table___alias symbol format" do
1147
1325
  @dataset.from(:abc__def).select_sql.must_equal "SELECT * FROM abc.def"
1148
1326
  @dataset.from(:a_b__c).select_sql.must_equal "SELECT * FROM a_b.c"
1149
1327
  @dataset.from(:'#__#').select_sql.must_equal 'SELECT * FROM #.#'
@@ -1155,7 +1333,7 @@ describe "Dataset#from" do
1155
1333
  @dataset.from(:'#___#').select_sql.must_equal 'SELECT * FROM # AS #'
1156
1334
  end
1157
1335
 
1158
- it "should not handle :foo__schema__table___alias specially" do
1336
+ with_symbol_splitting "should not handle multi level qualification in embedded symbols specially" do
1159
1337
  @dataset.from(:foo__schema__table___alias).select_sql.must_equal "SELECT * FROM foo.schema__table AS alias"
1160
1338
  end
1161
1339
 
@@ -1176,15 +1354,20 @@ describe "Dataset#select" do
1176
1354
 
1177
1355
  it "should accept variable arity" do
1178
1356
  @d.select(:name).sql.must_equal 'SELECT name FROM test'
1179
- @d.select(:a, :b, :test__c).sql.must_equal 'SELECT a, b, test.c FROM test'
1357
+ @d.select(:a, :b, Sequel[:test][:c]).sql.must_equal 'SELECT a, b, test.c FROM test'
1358
+ end
1359
+
1360
+ with_symbol_splitting "should accept symbols with embedded qualification and aliasing" do
1361
+ @d.select(:test__cc).sql.must_equal 'SELECT test.cc FROM test'
1362
+ @d.select(:test___cc).sql.must_equal 'SELECT test AS cc FROM test'
1363
+ @d.select(:test__name___n).sql.must_equal 'SELECT test.name AS n FROM test'
1180
1364
  end
1181
1365
 
1182
1366
  it "should accept symbols and literal strings" do
1183
1367
  @d.select(Sequel.lit('aaa')).sql.must_equal 'SELECT aaa FROM test'
1184
1368
  @d.select(:a, Sequel.lit('b')).sql.must_equal 'SELECT a, b FROM test'
1185
- @d.select(:test__cc, Sequel.lit('test.d AS e')).sql.must_equal 'SELECT test.cc, test.d AS e FROM test'
1186
- @d.select(Sequel.lit('test.d AS e'), :test__cc).sql.must_equal 'SELECT test.d AS e, test.cc FROM test'
1187
- @d.select(:test__name___n).sql.must_equal 'SELECT test.name AS n FROM test'
1369
+ @d.select(:test, Sequel.lit('test.d AS e')).sql.must_equal 'SELECT test, test.d AS e FROM test'
1370
+ @d.select(Sequel.lit('test.d AS e'), :test).sql.must_equal 'SELECT test.d AS e, test FROM test'
1188
1371
  end
1189
1372
 
1190
1373
  it "should accept ColumnAlls" do
@@ -1192,6 +1375,10 @@ describe "Dataset#select" do
1192
1375
  end
1193
1376
 
1194
1377
  it "should accept QualifiedIdentifiers" do
1378
+ @d.select(Sequel.expr(Sequel[:test][:name]).as(:n)).sql.must_equal 'SELECT test.name AS n FROM test'
1379
+ end
1380
+
1381
+ with_symbol_splitting "should accept qualified identifiers in symbols in expressions" do
1195
1382
  @d.select(Sequel.expr(:test__name).as(:n)).sql.must_equal 'SELECT test.name AS n FROM test'
1196
1383
  end
1197
1384
 
@@ -1214,7 +1401,7 @@ describe "Dataset#select" do
1214
1401
 
1215
1402
  it "should accept arbitrary objects and literalize them correctly" do
1216
1403
  @d.select(1, :a, 't').sql.must_equal "SELECT 1, a, 't' FROM test"
1217
- @d.select(nil, Sequel.function(:sum, :t), :x___y).sql.must_equal "SELECT NULL, sum(t), x AS y FROM test"
1404
+ @d.select(nil, Sequel.function(:sum, :t), Sequel[:x].as(:y)).sql.must_equal "SELECT NULL, sum(t), x AS y FROM test"
1218
1405
  @d.select(nil, 1, Sequel.as(:x, :y)).sql.must_equal "SELECT NULL, 1, x AS y FROM test"
1219
1406
  end
1220
1407
 
@@ -1240,6 +1427,10 @@ describe "Dataset#select_group" do
1240
1427
 
1241
1428
  it "should set both SELECT and GROUP" do
1242
1429
  @d.select_group(:name).sql.must_equal 'SELECT name FROM test GROUP BY name'
1430
+ @d.select_group(:a, Sequel[:b][:c], Sequel[:d].as(:e)).sql.must_equal 'SELECT a, b.c, d AS e FROM test GROUP BY a, b.c, d'
1431
+ end
1432
+
1433
+ with_symbol_splitting "should set both SELECT and GROUP when using splittable symbols" do
1243
1434
  @d.select_group(:a, :b__c, :d___e).sql.must_equal 'SELECT a, b.c, d AS e FROM test GROUP BY a, b.c, d'
1244
1435
  end
1245
1436
 
@@ -1275,11 +1466,11 @@ describe "Dataset#select_all" do
1275
1466
  @d.select_all(:test, :foo).sql.must_equal 'SELECT test.*, foo.* FROM test'
1276
1467
  end
1277
1468
 
1278
- it "should work correctly with qualified symbols" do
1469
+ with_symbol_splitting "should work correctly with qualified symbols" do
1279
1470
  @d.select_all(:sch__test).sql.must_equal 'SELECT sch.test.* FROM test'
1280
1471
  end
1281
1472
 
1282
- it "should work correctly with aliased symbols" do
1473
+ with_symbol_splitting "should work correctly with aliased symbols" do
1283
1474
  @d.select_all(:test___al).sql.must_equal 'SELECT al.* FROM test'
1284
1475
  @d.select_all(:sch__test___al).sql.must_equal 'SELECT al.* FROM test'
1285
1476
  end
@@ -1296,10 +1487,15 @@ describe "Dataset#select_all" do
1296
1487
  @d.select_all(Sequel.expr(:test).as(:al)).sql.must_equal 'SELECT al.* FROM test'
1297
1488
  end
1298
1489
 
1299
- it "should work correctly with SQL::JoinClauses" do
1490
+ with_symbol_splitting "should work correctly with SQL::JoinClauses with splittable symbols" do
1300
1491
  d = @d.cross_join(:foo).cross_join(:test___al)
1301
1492
  @d.select_all(*d.opts[:join]).sql.must_equal 'SELECT foo.*, al.* FROM test'
1302
1493
  end
1494
+
1495
+ it "should work correctly with SQL::JoinClauses" do
1496
+ d = @d.cross_join(:foo).cross_join(Sequel[:test].as(:al))
1497
+ @d.select_all(*d.opts[:join]).sql.must_equal 'SELECT foo.*, al.* FROM test'
1498
+ end
1303
1499
  end
1304
1500
 
1305
1501
  describe "Dataset#select_more" do
@@ -1734,10 +1930,14 @@ describe "Dataset#qualified_column_name" do
1734
1930
  @dataset.literal(@dataset.send(:qualified_column_name, :b1, :items)).must_equal 'items.b1'
1735
1931
  end
1736
1932
 
1737
- it "should not changed the qualifed column's table if given a qualified symbol" do
1933
+ with_symbol_splitting "should not changed the qualifed column's table if given a qualified symbol" do
1738
1934
  @dataset.literal(@dataset.send(:qualified_column_name, :ccc__b, :items)).must_equal 'ccc.b'
1739
1935
  end
1740
1936
 
1937
+ it "should not changed the qualifed column's table if given a qualified identifier" do
1938
+ @dataset.literal(@dataset.send(:qualified_column_name, Sequel[:ccc][:b], :items)).must_equal 'ccc.b'
1939
+ end
1940
+
1741
1941
  it "should handle an aliased identifier" do
1742
1942
  @dataset.literal(@dataset.send(:qualified_column_name, :ccc, Sequel.expr(:items).as(:i))).must_equal 'i.ccc'
1743
1943
  end
@@ -2018,6 +2218,11 @@ describe "Dataset#group_and_count" do
2018
2218
  end
2019
2219
 
2020
2220
  it "should format column aliases in the select clause but not in the group clause" do
2221
+ @ds.group_and_count(Sequel[:name].as(:n)).sql.must_equal "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
2222
+ @ds.group_and_count(Sequel[:name][:n]).sql.must_equal "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
2223
+ end
2224
+
2225
+ with_symbol_splitting "should format column aliases in the select clause but not in the group clause when using splittable symbols" do
2021
2226
  @ds.group_and_count(:name___n).sql.must_equal "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
2022
2227
  @ds.group_and_count(:name__n).sql.must_equal "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
2023
2228
  end
@@ -2066,23 +2271,35 @@ describe "Dataset#first_source_alias" do
2066
2271
  @ds = Sequel.mock.dataset
2067
2272
  end
2068
2273
 
2274
+ it "should be the entire first source if not aliased" do
2275
+ deprecated do
2276
+ # SEQUEL5: Remove deprecation block, but keep code
2277
+ @ds.from(:s__t).first_source_alias.must_equal :s__t
2278
+ end
2279
+ end
2280
+
2281
+ with_symbol_splitting "should be the alias if aliased when using symbol splitting" do
2282
+ @ds.from(:t___a).first_source_alias.must_equal :a
2283
+ @ds.from(:s__t___a).first_source_alias.must_equal :a
2284
+ end
2285
+
2286
+ with_symbol_splitting "should be aliased as first_source when using symbol splitting" do
2287
+ @ds.from(:s__t___a).first_source.must_equal :a
2288
+ end
2289
+
2069
2290
  it "should be the entire first source if not aliased" do
2070
2291
  @ds.from(:t).first_source_alias.must_equal :t
2071
2292
  @ds.from(Sequel.identifier(:t__a)).first_source_alias.must_equal Sequel.identifier(:t__a)
2072
- @ds.from(:s__t).first_source_alias.must_equal :s__t
2073
2293
  @ds.from(Sequel.qualify(:s, :t)).first_source_alias.must_equal Sequel.qualify(:s, :t)
2074
2294
  end
2075
2295
 
2076
2296
  it "should be the alias if aliased" do
2077
- @ds.from(:t___a).first_source_alias.must_equal :a
2078
- @ds.from(:s__t___a).first_source_alias.must_equal :a
2079
2297
  @ds.from(Sequel.expr(:t).as(:a)).first_source_alias.must_equal :a
2080
2298
  end
2081
2299
 
2082
2300
  it "should be aliased as first_source" do
2083
2301
  @ds.from(:t).first_source.must_equal :t
2084
2302
  @ds.from(Sequel.identifier(:t__a)).first_source.must_equal Sequel.identifier(:t__a)
2085
- @ds.from(:s__t___a).first_source.must_equal :a
2086
2303
  @ds.from(Sequel.expr(:t).as(:a)).first_source.must_equal :a
2087
2304
  end
2088
2305
 
@@ -2098,14 +2315,23 @@ describe "Dataset#first_source_table" do
2098
2315
 
2099
2316
  it "should be the entire first source if not aliased" do
2100
2317
  @ds.from(:t).first_source_table.must_equal :t
2318
+ deprecated do
2319
+ # SEQUEL5: Remove deprecation block, but keep code
2320
+ @ds.from(:s__t).first_source_table.must_equal :s__t
2321
+ end
2322
+ end
2323
+
2324
+ it "should be the entire first source if not aliased" do
2101
2325
  @ds.from(Sequel.identifier(:t__a)).first_source_table.must_equal Sequel.identifier(:t__a)
2102
- @ds.from(:s__t).first_source_table.must_equal :s__t
2103
2326
  @ds.from(Sequel.qualify(:s, :t)).first_source_table.must_equal Sequel.qualify(:s, :t)
2104
2327
  end
2105
2328
 
2106
- it "should be the unaliased part if aliased" do
2329
+ with_symbol_splitting "should be the unaliased part if aliased symbols with embedded aliasing" do
2107
2330
  @ds.literal(@ds.from(:t___a).first_source_table).must_equal "t"
2108
2331
  @ds.literal(@ds.from(:s__t___a).first_source_table).must_equal "s.t"
2332
+ end
2333
+
2334
+ it "should be the unaliased part if aliased" do
2109
2335
  @ds.literal(@ds.from(Sequel.expr(:t).as(:a)).first_source_table).must_equal "t"
2110
2336
  end
2111
2337
 
@@ -2184,6 +2410,10 @@ describe "Dataset#join_table" do
2184
2410
  end
2185
2411
 
2186
2412
  it "should support multiple joins" do
2413
+ @d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => Sequel[:b][:id]).sql.must_equal 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
2414
+ end
2415
+
2416
+ with_symbol_splitting "should support multiple joins with splittable symbols" do
2187
2417
  @d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.must_equal 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
2188
2418
  end
2189
2419
 
@@ -2260,11 +2490,11 @@ describe "Dataset#join_table" do
2260
2490
  @d.from(Sequel.as(:foo, :f)).join_table(:inner, :bar, :id => :bar_id).sql.must_equal 'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
2261
2491
  end
2262
2492
 
2263
- it "should support implicit schemas in from table symbols" do
2493
+ with_symbol_splitting "should support implicit schemas in from table symbols" do
2264
2494
  @d.from(:s__t).join(:u__v, {:id => :player_id}).sql.must_equal 'SELECT * FROM "s"."t" INNER JOIN "u"."v" ON ("u"."v"."id" = "s"."t"."player_id")'
2265
2495
  end
2266
2496
 
2267
- it "should support implicit aliases in from table symbols" do
2497
+ with_symbol_splitting "should support implicit aliases in from table symbols" do
2268
2498
  @d.from(:t___z).join(:v___y, {:id => :player_id}).sql.must_equal 'SELECT * FROM "t" AS "z" INNER JOIN "v" AS "y" ON ("y"."id" = "z"."player_id")'
2269
2499
  @d.from(:s__t___z).join(:u__v___y, {:id => :player_id}).sql.must_equal 'SELECT * FROM "s"."t" AS "z" INNER JOIN "u"."v" AS "y" ON ("y"."id" = "z"."player_id")'
2270
2500
  end
@@ -2318,6 +2548,11 @@ describe "Dataset#join_table" do
2318
2548
  end
2319
2549
 
2320
2550
  it "should support joining datasets and aliasing the join" do
2551
+ ds = Sequel.mock.dataset.from(:categories)
2552
+ @d.join_table(:left_outer, ds, {Sequel[:ds][:item_id] => :id}, :table_alias=>:ds).sql.must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
2553
+ end
2554
+
2555
+ with_symbol_splitting "should support joining datasets and aliasing the join when using symbols with embedded qualification" do
2321
2556
  ds = Sequel.mock.dataset.from(:categories)
2322
2557
  @d.join_table(:left_outer, ds, {:ds__item_id => :id}, :table_alias=>:ds).sql.must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
2323
2558
  end
@@ -2325,7 +2560,7 @@ describe "Dataset#join_table" do
2325
2560
  it "should support joining multiple datasets" do
2326
2561
  ds = Sequel.mock.dataset.from(:categories)
2327
2562
  ds2 = Sequel.mock.dataset.from(:nodes).select(:name)
2328
- ds3 = Sequel.mock.dataset.from(:attributes).filter("name = 'blah'")
2563
+ ds3 = Sequel.mock.dataset.from(:attributes).where(Sequel.lit("name = 'blah'"))
2329
2564
 
2330
2565
  @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.
2331
2566
  must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id") ' \
@@ -2333,10 +2568,14 @@ describe "Dataset#join_table" do
2333
2568
  'RIGHT OUTER JOIN (SELECT * FROM attributes WHERE (name = \'blah\')) AS "t3" ON ("t3"."attribute_id" = "t2"."id")'
2334
2569
  end
2335
2570
 
2336
- it "should support using an SQL String as the join condition" do
2571
+ deprecated "should support using a string as the join condition" do
2337
2572
  @d.join(:categories, "c.item_id = items.id", :table_alias=>:c).sql.must_equal 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
2338
2573
  end
2339
2574
 
2575
+ it "should support using a literal string as the join condition" do
2576
+ @d.join(:categories, Sequel.lit("c.item_id = items.id"), :table_alias=>:c).sql.must_equal 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
2577
+ end
2578
+
2340
2579
  it "should support using a boolean column as the join condition" do
2341
2580
  @d.join(:categories, :active).sql.must_equal 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
2342
2581
  end
@@ -2374,6 +2613,14 @@ describe "Dataset#join_table" do
2374
2613
  proc{@d.join(:categories, [:id]){|j,lj,js|}}.must_raise(Sequel::Error)
2375
2614
  end
2376
2615
 
2616
+ with_symbol_splitting "should support using a block that receieves the join table/alias, last join table/alias, and array of previous joins when using splittable symbols" do
2617
+ @d.from(:items___i).join(:categories, nil, :table_alias=>:c) do |join_alias, last_join_alias, joins|
2618
+ join_alias.must_equal :c
2619
+ last_join_alias.must_equal :i
2620
+ joins.must_equal []
2621
+ end
2622
+ end
2623
+
2377
2624
  it "should support using a block that receieves the join table/alias, last join table/alias, and array of previous joins" do
2378
2625
  @d.join(:categories) do |join_alias, last_join_alias, joins|
2379
2626
  join_alias.must_equal :categories
@@ -2387,12 +2634,6 @@ describe "Dataset#join_table" do
2387
2634
  joins.must_equal []
2388
2635
  end
2389
2636
 
2390
- @d.from(:items___i).join(:categories, nil, :table_alias=>:c) do |join_alias, last_join_alias, joins|
2391
- join_alias.must_equal :c
2392
- last_join_alias.must_equal :i
2393
- joins.must_equal []
2394
- end
2395
-
2396
2637
  @d.join(:blah).join(:categories, nil, :table_alias=>:c) do |join_alias, last_join_alias, joins|
2397
2638
  join_alias.must_equal :c
2398
2639
  last_join_alias.must_equal :blah
@@ -2434,6 +2675,12 @@ describe "Dataset#join_table" do
2434
2675
  end
2435
2676
 
2436
2677
  it "should prefer explicit aliases over implicit" do
2678
+ @d.from(Sequel[:items].as(:i)).join(Sequel[:categories].as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
2679
+ @d.from(Sequel.expr(:items).as(:i)).join(Sequel.expr(:categories).as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.
2680
+ must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
2681
+ end
2682
+
2683
+ with_symbol_splitting "should prefer explicit aliases over implicit when using splittable symbols" do
2437
2684
  @d.from(:items___i).join(:categories___c, {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
2438
2685
  @d.from(Sequel.expr(:items).as(:i)).join(Sequel.expr(:categories).as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.
2439
2686
  must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
@@ -2478,7 +2725,7 @@ describe "Dataset aggregate methods" do
2478
2725
 
2479
2726
  it "should accept qualified columns" do
2480
2727
  5.times do
2481
- @d.avg(:test__bc).must_equal 'SELECT avg(test.bc) AS avg FROM test LIMIT 1'
2728
+ @d.avg(Sequel[:test][:bc]).must_equal 'SELECT avg(test.bc) AS avg FROM test LIMIT 1'
2482
2729
  end
2483
2730
  end
2484
2731
 
@@ -2586,9 +2833,9 @@ describe "Dataset #first and #last" do
2586
2833
  ds = @d.order(:a).freeze
2587
2834
  5.times do
2588
2835
  ds.first(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1')
2589
- ds.first('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
2836
+ ds.first([[:z, 15]]).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
2590
2837
  ds.last(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1')
2591
- ds.last('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1')
2838
+ ds.last([[:z, 15]]).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1')
2592
2839
  end
2593
2840
  end
2594
2841
 
@@ -2613,10 +2860,30 @@ describe "Dataset #first and #last" do
2613
2860
  ds = @d.order(:name).freeze
2614
2861
  5.times do
2615
2862
  @d.first(:y=>25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
2616
- ds.last('y = ?', 16){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
2863
+ ds.last(:y=>16){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
2617
2864
  end
2618
2865
  end
2619
2866
 
2867
+ it "should combine block and standard argument filters if argument is a literal string" do
2868
+ ds = @d.order(:name).freeze
2869
+ 5.times do
2870
+ @d.first(Sequel.lit('y = 25')){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
2871
+ ds.last(Sequel.lit('y = 16')){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
2872
+ @d.first(Sequel.lit('y = ?', 25)){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
2873
+ ds.last(Sequel.lit('y = ?', 16)){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
2874
+ end
2875
+ end
2876
+
2877
+ deprecated "should combine block and standard argument filters if argument is a string" do
2878
+ ds = @d.order(:name).freeze
2879
+ 5.times do
2880
+ @d.first('y = 25'){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
2881
+ ds.last('y = 16'){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
2882
+ @d.first('y = ?', 25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
2883
+ ds.last('y = ?', 16){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
2884
+ end
2885
+ end
2886
+
2620
2887
  it "should filter and return an array of records if an Integer argument is provided and a block is given" do
2621
2888
  ds = @d.order(:a).freeze
2622
2889
  5.times do
@@ -2657,7 +2924,7 @@ describe "Dataset #first!" do
2657
2924
 
2658
2925
  it "should return the first! matching record if argument is not an Integer" do
2659
2926
  @d.order(:a).first!(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1')
2660
- @d.order(:a).first!('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
2927
+ @d.order(:a).first!(Sequel.lit('z = ?', 15)).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
2661
2928
  end
2662
2929
 
2663
2930
  it "should set the limit and return an array of records if the given number is > 1" do
@@ -2902,7 +3169,7 @@ describe "Dataset#get" do
2902
3169
  it "should work with aliased fields" do
2903
3170
  @d.freeze
2904
3171
  5.times do
2905
- @d.get(Sequel.expr(:x__b).as(:name)).must_equal "SELECT x.b AS name FROM test LIMIT 1"
3172
+ @d.get(Sequel.expr(Sequel[:x][:b]).as(:name)).must_equal "SELECT x.b AS name FROM test LIMIT 1"
2906
3173
  end
2907
3174
  end
2908
3175
 
@@ -2914,7 +3181,7 @@ describe "Dataset#get" do
2914
3181
  end
2915
3182
 
2916
3183
  it "should accept a block that yields a virtual row" do
2917
- @d.get{|o| o.x__b.as(:name)}.must_equal "SELECT x.b AS name FROM test LIMIT 1"
3184
+ @d.get{|o| o.x_b.as(:name)}.must_equal "SELECT x_b AS name FROM test LIMIT 1"
2918
3185
  @d.get{x(1).as(:name)}.must_equal "SELECT x(1) AS name FROM test LIMIT 1"
2919
3186
  end
2920
3187
 
@@ -2937,26 +3204,32 @@ describe "Dataset#get" do
2937
3204
  @d.get([:name]).must_equal ['SELECT name FROM test LIMIT 1']
2938
3205
  end
2939
3206
 
2940
- it "should handle an array with aliases" do
3207
+ it "should handle an array with aliased expressions" do
2941
3208
  @d = @d.with_fetch(:name=>1, :abc=>2)
2942
- @d.get([:n___name, Sequel.as(:a, :abc)]).must_equal [1, 2]
3209
+ @d.get([Sequel[:n].as(:name), Sequel.as(:a, :abc)]).must_equal [1, 2]
2943
3210
  @d.db.sqls.must_equal ['SELECT n AS name, a AS abc FROM test LIMIT 1']
2944
3211
  end
2945
3212
 
3213
+ with_symbol_splitting "should handle an array with symbols with embedded aliases" do
3214
+ @d = @d.with_fetch(:name=>1, :abc=>2)
3215
+ @d.get([:n___name, :a__b___abc]).must_equal [1, 2]
3216
+ @d.db.sqls.must_equal ['SELECT n AS name, a.b AS abc FROM test LIMIT 1']
3217
+ end
3218
+
2946
3219
  it "should raise an Error if an alias cannot be determined" do
2947
3220
  proc{@d.with_fetch(:name=>1, :abc=>2).get([Sequel.+(:a, 1), :a])}.must_raise(Sequel::Error)
2948
3221
  end
2949
3222
 
2950
3223
  it "should support an array of expressions in a virtual row" do
2951
3224
  @d = @d.with_fetch(:name=>1, :abc=>2)
2952
- @d.get{[name, n__abc]}.must_equal [1, 2]
3225
+ @d.get{[name, n[abc]]}.must_equal [1, 2]
2953
3226
  @d.db.sqls.must_equal ['SELECT name, n.abc FROM test LIMIT 1']
2954
3227
  end
2955
3228
 
2956
3229
  it "should work with static SQL" do
2957
3230
  @d.with_sql('SELECT foo').get(:name).must_equal "SELECT foo"
2958
3231
  @d = @d.with_fetch(:name=>1, :abc=>2)
2959
- @d.with_sql('SELECT foo').get{[name, n__abc]}.must_equal [1, 2]
3232
+ @d.with_sql('SELECT foo').get{[name, n[abc]]}.must_equal [1, 2]
2960
3233
  @d.db.sqls.must_equal ['SELECT foo'] * 2
2961
3234
  end
2962
3235
 
@@ -3023,7 +3296,7 @@ describe "Dataset#columns" do
3023
3296
  @dataset.db.sqls.must_equal ['SELECT * FROM items LIMIT 1']
3024
3297
  @dataset.columns.must_equal [:a]
3025
3298
  @dataset.db.sqls.must_equal []
3026
- ds = @dataset.select{foo{}}
3299
+ ds = @dataset.select{foo.function}
3027
3300
  ds.columns.must_equal [:b]
3028
3301
  @dataset.db.sqls.must_equal ['SELECT foo() FROM items LIMIT 1']
3029
3302
  end
@@ -3251,7 +3524,7 @@ describe "Dataset#multi_insert" do
3251
3524
  'COMMIT']
3252
3525
  end
3253
3526
 
3254
- it "should handle different formats for tables" do
3527
+ with_symbol_splitting "should handle splittable symbols for tables" do
3255
3528
  @ds = @ds.from(:sch__tab)
3256
3529
  @ds.multi_insert(@list)
3257
3530
  @db.sqls.must_equal ['BEGIN',
@@ -3259,7 +3532,9 @@ describe "Dataset#multi_insert" do
3259
3532
  "INSERT INTO sch.tab (name) VALUES ('def')",
3260
3533
  "INSERT INTO sch.tab (name) VALUES ('ghi')",
3261
3534
  'COMMIT']
3535
+ end
3262
3536
 
3537
+ it "should handle SQL::QualifiedIdentifier for tables" do
3263
3538
  @ds = @ds.from(Sequel.qualify(:sch, :tab))
3264
3539
  @ds.multi_insert(@list)
3265
3540
  @db.sqls.must_equal ['BEGIN',
@@ -3267,7 +3542,9 @@ describe "Dataset#multi_insert" do
3267
3542
  "INSERT INTO sch.tab (name) VALUES ('def')",
3268
3543
  "INSERT INTO sch.tab (name) VALUES ('ghi')",
3269
3544
  'COMMIT']
3545
+ end
3270
3546
 
3547
+ it "should handle SQL::Identifier for tables" do
3271
3548
  @ds = @ds.from(Sequel.identifier(:sch__tab))
3272
3549
  @ds.multi_insert(@list)
3273
3550
  @db.sqls.must_equal ['BEGIN',
@@ -3320,11 +3597,19 @@ describe "Dataset#update_sql" do
3320
3597
  @ds = Sequel.mock.dataset.from(:items)
3321
3598
  end
3322
3599
 
3323
- it "should accept strings" do
3600
+ deprecated "should accept strings" do
3324
3601
  @ds.update_sql("a = b").must_equal "UPDATE items SET a = b"
3325
3602
  end
3326
3603
 
3327
- it "should handle implicitly qualified symbols" do
3604
+ it "should accept literal strings" do
3605
+ @ds.update_sql(Sequel.lit("a = b")).must_equal "UPDATE items SET a = b"
3606
+ end
3607
+
3608
+ it "should handle qualified identifiers" do
3609
+ @ds.update_sql(Sequel[:items][:a]=>:b).must_equal "UPDATE items SET items.a = b"
3610
+ end
3611
+
3612
+ with_symbol_splitting "should handle implicitly qualified symbols" do
3328
3613
  @ds.update_sql(:items__a=>:b).must_equal "UPDATE items SET items.a = b"
3329
3614
  end
3330
3615
 
@@ -3400,8 +3685,11 @@ describe "Dataset#insert_sql" do
3400
3685
  @ds.insert_sql([:a, :b, :c], Sequel.lit('VALUES (1, 2, 3)')).must_equal "INSERT INTO items (a, b, c) VALUES (1, 2, 3)"
3401
3686
  end
3402
3687
 
3403
- it "should use unaliased table name" do
3688
+ with_symbol_splitting "should use unaliased table name when using splittable symbol" do
3404
3689
  @ds.from(:items___i).insert_sql(1).must_equal "INSERT INTO items VALUES (1)"
3690
+ end
3691
+
3692
+ it "should use unaliased table name" do
3405
3693
  @ds.from(Sequel.as(:items, :i)).insert_sql(1).must_equal "INSERT INTO items VALUES (1)"
3406
3694
  end
3407
3695
  end
@@ -3724,11 +4012,16 @@ describe "Dataset prepared statements and bound variables " do
3724
4012
  '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
3725
4013
  end
3726
4014
 
3727
- it "should handle literal strings" do
4015
+ deprecated "should handle literal strings" do
3728
4016
  @ds.filter("num = ?", :$n).call(:select, :n=>1)
3729
4017
  @db.sqls.must_equal ['SELECT * FROM items WHERE (num = 1)']
3730
4018
  end
3731
4019
 
4020
+ it "should handle literal strings" do
4021
+ @ds.filter(Sequel.lit("num = ?", :$n)).call(:select, :n=>1)
4022
+ @db.sqls.must_equal ['SELECT * FROM items WHERE (num = 1)']
4023
+ end
4024
+
3732
4025
  it "should handle columns on prepared statements correctly" do
3733
4026
  @db.columns = [:num]
3734
4027
  @ds = @ds.with_extend{def select_where_sql(sql) super(sql); sql << " OR #{columns.first} = 1" if opts[:where] end}
@@ -3751,11 +4044,16 @@ describe "Dataset prepared statements and bound variables " do
3751
4044
  @db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num IN (SELECT num FROM items WHERE (num = 1))))))']
3752
4045
  end
3753
4046
 
3754
- it "should handle subselects with literal strings" do
4047
+ deprecated "should handle subselects with strings" do
3755
4048
  @ds.filter(:$b).filter(:num=>@ds.select(:num).filter("num = ?", :$n)).call(:select, :n=>1, :b=>0)
3756
4049
  @db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
3757
4050
  end
3758
4051
 
4052
+ it "should handle subselects with literal strings" do
4053
+ @ds.filter(:$b).filter(:num=>@ds.select(:num).filter(Sequel.lit("num = ?", :$n))).call(:select, :n=>1, :b=>0)
4054
+ @db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
4055
+ end
4056
+
3759
4057
  it "should handle subselects with static sql and placeholders" do
3760
4058
  @ds.filter(:$b).filter(:num=>@db["SELECT num FROM items WHERE (num = ?)", :$n]).call(:select, :n=>1, :b=>0)
3761
4059
  @db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
@@ -3873,6 +4171,10 @@ describe "Sequel::Dataset#qualify" do
3873
4171
  end
3874
4172
 
3875
4173
  it "should handle symbols" do
4174
+ @ds.select(:a).qualify.sql.must_equal 'SELECT t.a FROM t'
4175
+ end
4176
+
4177
+ with_symbol_splitting "should handle splittable symbols" do
3876
4178
  @ds.select(:a, :b__c, :d___e, :f__g___h).qualify.sql.must_equal 'SELECT t.a, b.c, t.d AS e, f.g AS h FROM t'
3877
4179
  end
3878
4180
 
@@ -3922,11 +4224,11 @@ describe "Sequel::Dataset#qualify" do
3922
4224
  end
3923
4225
 
3924
4226
  it "should handle SQL::PlaceholderLiteralStrings" do
3925
- @ds.filter('? > ?', :a, 1).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.a > 1)'
4227
+ @ds.filter(Sequel.lit('? > ?', :a, 1)).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.a > 1)'
3926
4228
  end
3927
4229
 
3928
4230
  it "should handle SQL::PlaceholderLiteralStrings with named placeholders" do
3929
- @ds.filter(':a > :b', :a=>:c, :b=>1).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.c > 1)'
4231
+ @ds.filter(Sequel.lit(':a > :b', :a=>:c, :b=>1)).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.c > 1)'
3930
4232
  end
3931
4233
 
3932
4234
  it "should handle SQL::Wrappers" do
@@ -3960,7 +4262,7 @@ describe "Sequel::Dataset#qualify" do
3960
4262
  end
3961
4263
 
3962
4264
  it "should handle all other objects by returning them unchanged" do
3963
- @ds.select("a").filter{a(3)}.filter('blah').order(Sequel.lit('true')).group(Sequel.lit('a > ?', 1)).having(false).qualify.sql.must_equal "SELECT 'a' FROM t WHERE (a(3) AND (blah)) GROUP BY a > 1 HAVING 'f' ORDER BY true"
4265
+ @ds.select("a").filter{a(3)}.filter(Sequel.lit('blah')).order(Sequel.lit('true')).group(Sequel.lit('a > ?', 1)).having(false).qualify.sql.must_equal "SELECT 'a' FROM t WHERE (a(3) AND (blah)) GROUP BY a > 1 HAVING 'f' ORDER BY true"
3964
4266
  end
3965
4267
  end
3966
4268
 
@@ -4313,7 +4615,12 @@ describe "Sequel::Dataset#select_map" do
4313
4615
  @ds.db.sqls.must_equal ['SELECT a FROM t']
4314
4616
  end
4315
4617
 
4316
- it "should handle implicit qualifiers in arguments" do
4618
+ it "should handle qualified identifiers in arguments" do
4619
+ @ds.select_map(Sequel[:a][:b]).must_equal [1, 2]
4620
+ @ds.db.sqls.must_equal ['SELECT a.b FROM t']
4621
+ end
4622
+
4623
+ with_symbol_splitting "should handle implicit qualifiers in arguments" do
4317
4624
  @ds.select_map(:a__b).must_equal [1, 2]
4318
4625
  @ds.db.sqls.must_equal ['SELECT a.b FROM t']
4319
4626
  end
@@ -4321,14 +4628,19 @@ describe "Sequel::Dataset#select_map" do
4321
4628
  it "should raise if multiple arguments and can't determine alias" do
4322
4629
  proc{@ds.select_map([Sequel.function(:a), :b])}.must_raise(Sequel::Error)
4323
4630
  proc{@ds.select_map(Sequel.function(:a)){b}}.must_raise(Sequel::Error)
4324
- proc{@ds.select_map{[a{}, b]}}.must_raise(Sequel::Error)
4631
+ proc{@ds.select_map{[a.function, b]}}.must_raise(Sequel::Error)
4325
4632
  end
4326
4633
 
4327
- it "should handle implicit aliases in arguments" do
4634
+ with_symbol_splitting "should handle implicit aliases in arguments" do
4328
4635
  @ds.select_map(:a___b).must_equal [1, 2]
4329
4636
  @ds.db.sqls.must_equal ['SELECT a AS b FROM t']
4330
4637
  end
4331
4638
 
4639
+ it "should handle aliased expressions in arguments" do
4640
+ @ds.select_map(Sequel[:a].as(:b)).must_equal [1, 2]
4641
+ @ds.db.sqls.must_equal ['SELECT a AS b FROM t']
4642
+ end
4643
+
4332
4644
  it "should handle other objects" do
4333
4645
  @ds.select_map(Sequel.lit("a").as(:b)).must_equal [1, 2]
4334
4646
  @ds.db.sqls.must_equal ['SELECT a AS b FROM t']
@@ -4345,35 +4657,40 @@ describe "Sequel::Dataset#select_map" do
4345
4657
  end
4346
4658
 
4347
4659
  it "should handle an expression without a determinable alias" do
4348
- @ds.select_map{a(t__c)}.must_equal [1, 2]
4660
+ @ds.select_map{a(t[c])}.must_equal [1, 2]
4349
4661
  @ds.db.sqls.must_equal ['SELECT a(t.c) AS v FROM t']
4350
4662
  end
4351
4663
 
4352
4664
  it "should accept a block" do
4353
- @ds.select_map{a(t__c).as(b)}.must_equal [1, 2]
4665
+ @ds.select_map{a(t[c]).as(b)}.must_equal [1, 2]
4354
4666
  @ds.db.sqls.must_equal ['SELECT a(t.c) AS b FROM t']
4355
4667
  end
4356
4668
 
4357
4669
  it "should accept a block with an array of columns" do
4358
- @ds.select_map{[a(t__c).as(c), a(t__c).as(c)]}.must_equal [[1, 1], [2, 2]]
4670
+ @ds.select_map{[a(t[c]).as(c), a(t[c]).as(c)]}.must_equal [[1, 1], [2, 2]]
4359
4671
  @ds.db.sqls.must_equal ['SELECT a(t.c) AS c, a(t.c) AS c FROM t']
4360
4672
  end
4361
4673
 
4362
4674
  it "should accept a block with a column" do
4363
- @ds.select_map(:c){a(t__c).as(c)}.must_equal [[1, 1], [2, 2]]
4675
+ @ds.select_map(:c){a(t[c]).as(c)}.must_equal [[1, 1], [2, 2]]
4364
4676
  @ds.db.sqls.must_equal ['SELECT c, a(t.c) AS c FROM t']
4365
4677
  end
4366
4678
 
4367
4679
  it "should accept a block and array of arguments" do
4368
- @ds.select_map([:c, :c]){[a(t__c).as(c), a(t__c).as(c)]}.must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
4680
+ @ds.select_map([:c, :c]){[a(t[c]).as(c), a(t[c]).as(c)]}.must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
4369
4681
  @ds.db.sqls.must_equal ['SELECT c, c, a(t.c) AS c, a(t.c) AS c FROM t']
4370
4682
  end
4371
4683
 
4372
4684
  it "should handle an array of columns" do
4373
4685
  @ds.select_map([:c, :c]).must_equal [[1, 1], [2, 2]]
4374
4686
  @ds.db.sqls.must_equal ['SELECT c, c FROM t']
4375
- @ds.select_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b), :a__c, :a__d___c]).must_equal [[1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2]]
4376
- @ds.db.sqls.must_equal ['SELECT d AS c, b.c, c, b.c, a.c, a.d AS c FROM t']
4687
+ @ds.select_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b)]).must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
4688
+ @ds.db.sqls.must_equal ['SELECT d AS c, b.c, c, b.c FROM t']
4689
+ end
4690
+
4691
+ with_symbol_splitting "should handle an array of columns with splittable symbols" do
4692
+ @ds.select_map([:a__c, :a__d___c]).must_equal [[1, 1], [2, 2]]
4693
+ @ds.db.sqls.must_equal ['SELECT a.c, a.d AS c FROM t']
4377
4694
  end
4378
4695
 
4379
4696
  it "should handle an array with a single element" do
@@ -4392,7 +4709,12 @@ describe "Sequel::Dataset#select_order_map" do
4392
4709
  @ds.db.sqls.must_equal ['SELECT a FROM t ORDER BY a']
4393
4710
  end
4394
4711
 
4395
- it "should handle implicit qualifiers in arguments" do
4712
+ it "should handle qualified identifiers in arguments" do
4713
+ @ds.select_order_map(Sequel[:a][:b]).must_equal [1, 2]
4714
+ @ds.db.sqls.must_equal ['SELECT a.b FROM t ORDER BY a.b']
4715
+ end
4716
+
4717
+ with_symbol_splitting "should handle implicit qualifiers in arguments" do
4396
4718
  @ds.select_order_map(:a__b).must_equal [1, 2]
4397
4719
  @ds.db.sqls.must_equal ['SELECT a.b FROM t ORDER BY a.b']
4398
4720
  end
@@ -4400,15 +4722,15 @@ describe "Sequel::Dataset#select_order_map" do
4400
4722
  it "should raise if multiple arguments and can't determine alias" do
4401
4723
  proc{@ds.select_order_map([Sequel.function(:a), :b])}.must_raise(Sequel::Error)
4402
4724
  proc{@ds.select_order_map(Sequel.function(:a)){b}}.must_raise(Sequel::Error)
4403
- proc{@ds.select_order_map{[a{}, b]}}.must_raise(Sequel::Error)
4725
+ proc{@ds.select_order_map{[a.function, b]}}.must_raise(Sequel::Error)
4404
4726
  end
4405
4727
 
4406
- it "should handle implicit aliases in arguments" do
4728
+ with_symbol_splitting "should handle implicit aliases in arguments" do
4407
4729
  @ds.select_order_map(:a___b).must_equal [1, 2]
4408
4730
  @ds.db.sqls.must_equal ['SELECT a AS b FROM t ORDER BY a']
4409
4731
  end
4410
4732
 
4411
- it "should handle implicit qualifiers and aliases in arguments" do
4733
+ with_symbol_splitting "should handle implicit qualifiers and aliases in arguments" do
4412
4734
  @ds.select_order_map(:t__a___b).must_equal [1, 2]
4413
4735
  @ds.db.sqls.must_equal ['SELECT t.a AS b FROM t ORDER BY t.a']
4414
4736
  end
@@ -4416,6 +4738,10 @@ describe "Sequel::Dataset#select_order_map" do
4416
4738
  it "should handle AliasedExpressions" do
4417
4739
  @ds.select_order_map(Sequel.lit("a").as(:b)).must_equal [1, 2]
4418
4740
  @ds.db.sqls.must_equal ['SELECT a AS b FROM t ORDER BY a']
4741
+ @ds.select_order_map(Sequel[:a].as(:b)).must_equal [1, 2]
4742
+ @ds.db.sqls.must_equal ['SELECT a AS b FROM t ORDER BY a']
4743
+ @ds.select_order_map(Sequel[:t][:a].as(:b)).must_equal [1, 2]
4744
+ @ds.db.sqls.must_equal ['SELECT t.a AS b FROM t ORDER BY t.a']
4419
4745
  end
4420
4746
 
4421
4747
  it "should handle OrderedExpressions" do
@@ -4424,35 +4750,43 @@ describe "Sequel::Dataset#select_order_map" do
4424
4750
  end
4425
4751
 
4426
4752
  it "should handle an expression without a determinable alias" do
4427
- @ds.select_order_map{a(t__c)}.must_equal [1, 2]
4753
+ @ds.select_order_map{a(t[c])}.must_equal [1, 2]
4428
4754
  @ds.db.sqls.must_equal ['SELECT a(t.c) AS v FROM t ORDER BY a(t.c)']
4429
4755
  end
4430
4756
 
4431
4757
  it "should accept a block" do
4432
- @ds.select_order_map{a(t__c).as(b)}.must_equal [1, 2]
4758
+ @ds.select_order_map{a(t[c]).as(b)}.must_equal [1, 2]
4433
4759
  @ds.db.sqls.must_equal ['SELECT a(t.c) AS b FROM t ORDER BY a(t.c)']
4434
4760
  end
4435
4761
 
4436
4762
  it "should accept a block with an array of columns" do
4437
- @ds.select_order_map{[c.desc, a(t__c).as(c)]}.must_equal [[1, 1], [2, 2]]
4763
+ @ds.select_order_map{[c.desc, a(t[c]).as(c)]}.must_equal [[1, 1], [2, 2]]
4438
4764
  @ds.db.sqls.must_equal ['SELECT c, a(t.c) AS c FROM t ORDER BY c DESC, a(t.c)']
4439
4765
  end
4440
4766
 
4441
4767
  it "should accept a block with a column" do
4442
- @ds.select_order_map(:c){a(t__c).as(c)}.must_equal [[1, 1], [2, 2]]
4768
+ @ds.select_order_map(:c){a(t[c]).as(c)}.must_equal [[1, 1], [2, 2]]
4443
4769
  @ds.db.sqls.must_equal ['SELECT c, a(t.c) AS c FROM t ORDER BY c, a(t.c)']
4444
4770
  end
4445
4771
 
4446
4772
  it "should accept a block and array of arguments" do
4447
- @ds.select_order_map([:c, :c]){[a(t__c).as(c), c.desc]}.must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
4773
+ @ds.select_order_map([:c, :c]){[a(t[c]).as(c), c.desc]}.must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
4448
4774
  @ds.db.sqls.must_equal ['SELECT c, c, a(t.c) AS c, c FROM t ORDER BY c, c, a(t.c), c DESC']
4449
4775
  end
4450
4776
 
4451
4777
  it "should handle an array of columns" do
4452
4778
  @ds.select_order_map([:c, :c]).must_equal [[1, 1], [2, 2]]
4453
4779
  @ds.db.sqls.must_equal ['SELECT c, c FROM t ORDER BY c, c']
4454
- @ds.select_order_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b), Sequel.identifier(:c).qualify(:b).desc, :a__c, Sequel.desc(:a__d___c), Sequel.desc(Sequel.expr(:a__d___c))]).must_equal [[1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2]]
4455
- @ds.db.sqls.must_equal ['SELECT d AS c, b.c, c, b.c, b.c, a.c, a.d AS c, a.d AS c FROM t ORDER BY d, b.c, c, b.c, b.c DESC, a.c, a.d DESC, a.d DESC']
4780
+ end
4781
+
4782
+ it "should handle an array of columns" do
4783
+ @ds.select_order_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b), Sequel.identifier(:c).qualify(:b).desc]).must_equal [[1, 1, 1, 1, 1], [2, 2, 2, 2, 2]]
4784
+ @ds.db.sqls.must_equal ['SELECT d AS c, b.c, c, b.c, b.c FROM t ORDER BY d, b.c, c, b.c, b.c DESC']
4785
+ end
4786
+
4787
+ with_symbol_splitting "should handle an array of columns with splittable symbols" do
4788
+ @ds.select_order_map([:a__c, Sequel.desc(:a__d___c), Sequel.desc(Sequel.expr(:a__d___c))]).must_equal [[1, 1, 1], [2, 2, 2]]
4789
+ @ds.db.sqls.must_equal ['SELECT a.c, a.d AS c, a.d AS c FROM t ORDER BY a.c, a.d DESC, a.d DESC']
4456
4790
  end
4457
4791
 
4458
4792
  it "should handle an array with a single element" do
@@ -4472,17 +4806,32 @@ describe "Sequel::Dataset#select_hash" do
4472
4806
  @ds.db.sqls.must_equal ['SELECT a, b FROM t']
4473
4807
  end
4474
4808
 
4475
- it "should handle implicit qualifiers in arguments" do
4809
+ it "should handle qualified identifiers in arguments" do
4810
+ @ds.select_hash(Sequel[:t][:a], Sequel[:t][:b]).must_equal(1=>2, 3=>4)
4811
+ @ds.db.sqls.must_equal ['SELECT t.a, t.b FROM t']
4812
+ end
4813
+
4814
+ with_symbol_splitting "should handle implicit qualifiers in arguments" do
4476
4815
  @ds.select_hash(:t__a, :t__b).must_equal(1=>2, 3=>4)
4477
4816
  @ds.db.sqls.must_equal ['SELECT t.a, t.b FROM t']
4478
4817
  end
4479
4818
 
4480
- it "should handle implicit aliases in arguments" do
4819
+ it "should handle aliased expresssions in arguments" do
4820
+ @ds.select_hash(Sequel[:c].as(:a), Sequel[:d].as(:b)).must_equal(1=>2, 3=>4)
4821
+ @ds.db.sqls.must_equal ['SELECT c AS a, d AS b FROM t']
4822
+ end
4823
+
4824
+ with_symbol_splitting "should handle implicit aliases in arguments" do
4481
4825
  @ds.select_hash(:c___a, :d___b).must_equal(1=>2, 3=>4)
4482
4826
  @ds.db.sqls.must_equal ['SELECT c AS a, d AS b FROM t']
4483
4827
  end
4484
4828
 
4485
- it "should handle implicit qualifiers and aliases in arguments" do
4829
+ it "should handle qualified identifiers and aliased expressions in arguments" do
4830
+ @ds.select_hash(Sequel[:t][:c].as(:a), Sequel[:t][:d].as(:b)).must_equal(1=>2, 3=>4)
4831
+ @ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
4832
+ end
4833
+
4834
+ with_symbol_splitting "should handle implicit qualifiers and aliases in arguments" do
4486
4835
  @ds.select_hash(:t__c___a, :t__d___b).must_equal(1=>2, 3=>4)
4487
4836
  @ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
4488
4837
  end
@@ -4528,17 +4877,17 @@ describe "Sequel::Dataset#select_hash_groups" do
4528
4877
  @ds.db.sqls.must_equal ['SELECT a, b FROM t']
4529
4878
  end
4530
4879
 
4531
- it "should handle implicit qualifiers in arguments" do
4880
+ with_symbol_splitting "should handle implicit qualifiers in arguments" do
4532
4881
  @ds.select_hash_groups(:t__a, :t__b).must_equal(1=>[2], 3=>[4])
4533
4882
  @ds.db.sqls.must_equal ['SELECT t.a, t.b FROM t']
4534
4883
  end
4535
4884
 
4536
- it "should handle implicit aliases in arguments" do
4885
+ with_symbol_splitting "should handle implicit aliases in arguments" do
4537
4886
  @ds.select_hash_groups(:c___a, :d___b).must_equal(1=>[2], 3=>[4])
4538
4887
  @ds.db.sqls.must_equal ['SELECT c AS a, d AS b FROM t']
4539
4888
  end
4540
4889
 
4541
- it "should handle implicit qualifiers and aliases in arguments" do
4890
+ with_symbol_splitting "should handle implicit qualifiers and aliases in arguments" do
4542
4891
  @ds.select_hash_groups(:t__c___a, :t__d___b).must_equal(1=>[2], 3=>[4])
4543
4892
  @ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
4544
4893
  end
@@ -4558,6 +4907,11 @@ describe "Sequel::Dataset#select_hash_groups" do
4558
4907
  @ds.db.sqls.must_equal ['SELECT c AS a, t AS b FROM t']
4559
4908
  end
4560
4909
 
4910
+ it "should handle SQL::QualifiedIdentifiers and SQL::AliasedExpressions in arguments" do
4911
+ @ds.select_hash_groups(Sequel[:t][:c].as(:a), Sequel[:t][:d].as(:b)).must_equal(1=>[2], 3=>[4])
4912
+ @ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
4913
+ end
4914
+
4561
4915
  it "should work with arrays of columns" do
4562
4916
  @db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
4563
4917
  @ds.select_hash_groups([:a, :c], :b).must_equal([1, 3]=>[2], [4, 6]=>[5])
@@ -4631,15 +4985,24 @@ describe "Dataset#skip_locked" do
4631
4985
  end
4632
4986
 
4633
4987
  describe "Custom ASTTransformer" do
4634
- it "should transform given objects" do
4635
- c = Class.new(Sequel::ASTTransformer) do
4988
+ before do
4989
+ @c = Class.new(Sequel::ASTTransformer) do
4636
4990
  def v(s)
4637
4991
  (s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
4638
4992
  end
4639
4993
  end.new
4994
+ end
4995
+
4996
+ it "should transform given objects" do
4997
+ ds = Sequel.mock.dataset.from(:t).cross_join(Sequel[:a].as(:g)).join(Sequel[:b].as(:h), [:c]).join(Sequel[:d].as(:i), :e=>:f)
4998
+ ds.sql.must_equal 'SELECT * FROM t CROSS JOIN a AS g INNER JOIN b AS h USING (c) INNER JOIN d AS i ON (i.e = h.f)'
4999
+ ds.clone(:from=>@c.transform(ds.opts[:from]), :join=>@c.transform(ds.opts[:join])).sql.must_equal 'SELECT * FROM tt CROSS JOIN aa AS g INNER JOIN bb AS h USING (cc) INNER JOIN dd AS i ON (ii.ee = hh.ff)'
5000
+ end
5001
+
5002
+ with_symbol_splitting "should transform given objects with splittable symbols" do
4640
5003
  ds = Sequel.mock.dataset.from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
4641
5004
  ds.sql.must_equal 'SELECT * FROM t CROSS JOIN a AS g INNER JOIN b AS h USING (c) INNER JOIN d AS i ON (i.e = h.f)'
4642
- ds.clone(:from=>c.transform(ds.opts[:from]), :join=>c.transform(ds.opts[:join])).sql.must_equal 'SELECT * FROM tt CROSS JOIN aa AS g INNER JOIN bb AS h USING (cc) INNER JOIN dd AS i ON (ii.ee = hh.ff)'
5005
+ ds.clone(:from=>@c.transform(ds.opts[:from]), :join=>@c.transform(ds.opts[:join])).sql.must_equal 'SELECT * FROM tt CROSS JOIN aa AS g INNER JOIN bb AS h USING (cc) INNER JOIN dd AS i ON (ii.ee = hh.ff)'
4643
5006
  end
4644
5007
  end
4645
5008
 
@@ -4795,7 +5158,7 @@ describe "Dataset#schema_and_table" do
4795
5158
  @ds = Sequel.mock[:test]
4796
5159
  end
4797
5160
 
4798
- it "should correctly handle symbols" do
5161
+ with_symbol_splitting "should correctly handle symbols" do
4799
5162
  @ds.schema_and_table(:s).must_equal [nil, 's']
4800
5163
  @ds.schema_and_table(:s___a).must_equal [nil, 's']
4801
5164
  @ds.schema_and_table(:t__s).must_equal ['t', 's']
@@ -4827,6 +5190,9 @@ describe "Dataset#split_qualifiers" do
4827
5190
 
4828
5191
  it "should correctly handle symbols" do
4829
5192
  @ds.split_qualifiers(:s).must_equal ['s']
5193
+ end
5194
+
5195
+ with_symbol_splitting "should correctly handle splittable symbols" do
4830
5196
  @ds.split_qualifiers(:s___a).must_equal ['s']
4831
5197
  @ds.split_qualifiers(:t__s).must_equal ['t', 's']
4832
5198
  @ds.split_qualifiers(:t__s___a).must_equal ['t', 's']
@@ -4844,12 +5210,15 @@ describe "Dataset#split_qualifiers" do
4844
5210
  @ds.split_qualifiers(Sequel.qualify(:t, :s)).must_equal ['t', 's']
4845
5211
  end
4846
5212
 
4847
- it "should correctly handle complex qualified identifiers" do
5213
+ with_symbol_splitting "should correctly handle complex qualified identifiers with splittable symbols" do
4848
5214
  @ds.split_qualifiers(Sequel.qualify(:d__t, :s)).must_equal ['d', 't', 's']
4849
- @ds.split_qualifiers(Sequel.qualify(Sequel.qualify(:d, :t), :s)).must_equal ['d', 't', 's']
4850
5215
  @ds.split_qualifiers(Sequel.qualify(:d, :t__s)).must_equal ['d', 't', 's']
4851
- @ds.split_qualifiers(Sequel.qualify(:d, Sequel.qualify(:t, :s))).must_equal ['d', 't', 's']
4852
5216
  @ds.split_qualifiers(Sequel.qualify(:d__t, :s__s2)).must_equal ['d', 't', 's', 's2']
5217
+ end
5218
+
5219
+ it "should correctly handle complex qualified identifiers" do
5220
+ @ds.split_qualifiers(Sequel.qualify(Sequel.qualify(:d, :t), :s)).must_equal ['d', 't', 's']
5221
+ @ds.split_qualifiers(Sequel.qualify(:d, Sequel.qualify(:t, :s))).must_equal ['d', 't', 's']
4853
5222
  @ds.split_qualifiers(Sequel.qualify(Sequel.qualify(:d, :t), Sequel.qualify(:s, :s2))).must_equal ['d', 't', 's', 's2']
4854
5223
  end
4855
5224
  end
@@ -5115,6 +5484,9 @@ describe "#unqualified_column_for" do
5115
5484
 
5116
5485
  it "should handle Symbols" do
5117
5486
  @ds.unqualified_column_for(:a).must_equal Sequel.identifier('a')
5487
+ end
5488
+
5489
+ with_symbol_splitting "should handle splittable symbols" do
5118
5490
  @ds.unqualified_column_for(:b__a).must_equal Sequel.identifier('a')
5119
5491
  @ds.unqualified_column_for(:a___c).must_equal Sequel.identifier('a').as('c')
5120
5492
  @ds.unqualified_column_for(:b__a___c).must_equal Sequel.identifier('a').as('c')