sequel 4.48.0 → 4.49.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +56 -0
  3. data/doc/advanced_associations.rdoc +1 -1
  4. data/doc/opening_databases.rdoc +3 -2
  5. data/doc/release_notes/4.49.0.txt +222 -0
  6. data/lib/sequel/adapters/ibmdb.rb +6 -1
  7. data/lib/sequel/adapters/jdbc.rb +3 -1
  8. data/lib/sequel/adapters/jdbc/h2.rb +10 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
  10. data/lib/sequel/adapters/jdbc/sqlserver.rb +9 -2
  11. data/lib/sequel/adapters/mock.rb +3 -0
  12. data/lib/sequel/adapters/mysql2.rb +1 -1
  13. data/lib/sequel/adapters/postgres.rb +2 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +4 -1
  15. data/lib/sequel/adapters/shared/oracle.rb +26 -3
  16. data/lib/sequel/connection_pool.rb +9 -2
  17. data/lib/sequel/connection_pool/sharded_single.rb +1 -1
  18. data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
  19. data/lib/sequel/connection_pool/single.rb +2 -2
  20. data/lib/sequel/connection_pool/threaded.rb +2 -2
  21. data/lib/sequel/database/connecting.rb +3 -3
  22. data/lib/sequel/database/dataset_defaults.rb +14 -1
  23. data/lib/sequel/dataset.rb +1 -1
  24. data/lib/sequel/dataset/actions.rb +54 -0
  25. data/lib/sequel/dataset/dataset_module.rb +58 -0
  26. data/lib/sequel/dataset/query.rb +3 -3
  27. data/lib/sequel/exceptions.rb +8 -0
  28. data/lib/sequel/extensions/_model_pg_row.rb +5 -2
  29. data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -1
  30. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  31. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -2
  32. data/lib/sequel/extensions/migration.rb +5 -2
  33. data/lib/sequel/extensions/null_dataset.rb +1 -0
  34. data/lib/sequel/model/associations.rb +3 -0
  35. data/lib/sequel/model/base.rb +10 -55
  36. data/lib/sequel/model/dataset_module.rb +5 -43
  37. data/lib/sequel/model/errors.rb +2 -1
  38. data/lib/sequel/model/inflections.rb +17 -5
  39. data/lib/sequel/plugins/active_model.rb +2 -2
  40. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  41. data/lib/sequel/plugins/composition.rb +2 -2
  42. data/lib/sequel/plugins/dataset_associations.rb +25 -13
  43. data/lib/sequel/plugins/json_serializer.rb +2 -2
  44. data/lib/sequel/plugins/pg_row.rb +4 -2
  45. data/lib/sequel/plugins/serialization.rb +1 -0
  46. data/lib/sequel/plugins/single_table_inheritance.rb +6 -1
  47. data/lib/sequel/plugins/touch.rb +2 -1
  48. data/lib/sequel/plugins/validation_helpers.rb +10 -2
  49. data/lib/sequel/sql.rb +16 -7
  50. data/lib/sequel/version.rb +1 -1
  51. data/spec/adapters/mssql_spec.rb +4 -4
  52. data/spec/adapters/mysql_spec.rb +5 -1
  53. data/spec/adapters/oracle_spec.rb +4 -0
  54. data/spec/bin_spec.rb +7 -1
  55. data/spec/core/connection_pool_spec.rb +28 -14
  56. data/spec/core/database_spec.rb +149 -0
  57. data/spec/core/dataset_spec.rb +173 -0
  58. data/spec/extensions/class_table_inheritance_spec.rb +58 -17
  59. data/spec/extensions/composition_spec.rb +13 -0
  60. data/spec/extensions/dataset_associations_spec.rb +12 -0
  61. data/spec/extensions/many_through_many_spec.rb +4 -4
  62. data/spec/extensions/null_dataset_spec.rb +1 -1
  63. data/spec/extensions/serialization_spec.rb +1 -1
  64. data/spec/extensions/single_table_inheritance_spec.rb +16 -0
  65. data/spec/extensions/validation_helpers_spec.rb +1 -2
  66. data/spec/integration/associations_test.rb +8 -0
  67. data/spec/integration/plugin_test.rb +8 -3
  68. data/spec/model/association_reflection_spec.rb +1 -1
  69. data/spec/model/associations_spec.rb +29 -9
  70. data/spec/model/class_dataset_methods_spec.rb +6 -0
  71. data/spec/model/eager_loading_spec.rb +8 -8
  72. data/spec/model/plugins_spec.rb +34 -0
  73. data/spec/model/record_spec.rb +1 -1
  74. data/spec/spec_config.rb +2 -0
  75. metadata +5 -2
@@ -53,7 +53,9 @@ module Sequel
53
53
  # Address.load(:street=>'123 Foo St', :city=>'Bar Town', :zip=>'12345'))
54
54
  module PgRow
55
55
  ROW = 'ROW'.freeze
56
+ Sequel::Deprecation.deprecate_constant(self, :ROW)
56
57
  CAST = '::'.freeze
58
+ Sequel::Deprecation.deprecate_constant(self, :CAST)
57
59
 
58
60
  # When loading the extension, make sure the database has the pg_row extension
59
61
  # loaded, load the custom database extensions, and automatically register the
@@ -75,9 +77,9 @@ module Sequel
75
77
  module InstanceMethods
76
78
  # Literalize the model instance and append it to the sql.
77
79
  def sql_literal_append(ds, sql)
78
- sql << ROW
80
+ sql << 'ROW'
79
81
  ds.literal_append(sql, values.values_at(*columns))
80
- sql << CAST
82
+ sql << '::'
81
83
  ds.quote_schema_table_append(sql, model.dataset.first_source_table)
82
84
  end
83
85
  end
@@ -149,6 +149,7 @@ module Sequel
149
149
  # The columns that will be serialized. This is only for
150
150
  # backwards compatibility, use serialization_map in new code.
151
151
  def serialized_columns
152
+ Sequel::Deprecation.deprecate("#{self}.serialized_columns in the serialization plugin", "Use #{self}.serialization_map.keys instead")
152
153
  serialization_map.keys
153
154
  end
154
155
 
@@ -182,7 +182,12 @@ module Sequel
182
182
  # Return an instance of the class specified by sti_key,
183
183
  # used by the row_proc.
184
184
  def sti_load(r)
185
- sti_class(sti_model_map[r[sti_key]]).call(r)
185
+ sti_class_from_sti_key(r[sti_key]).call(r)
186
+ end
187
+
188
+ # Return the sti class based on one of the keys from sti_model_map.
189
+ def sti_class_from_sti_key(key)
190
+ sti_class(sti_model_map[key])
186
191
  end
187
192
 
188
193
  # Make sure that all subclasses of the parent class correctly include
@@ -31,6 +31,7 @@ module Sequel
31
31
  module Touch
32
32
  # The default column to update when touching
33
33
  TOUCH_COLUMN_DEFAULT = :updated_at
34
+ Sequel::Deprecation.deprecate_constant(self, :TOUCH_COLUMN_DEFAULT)
34
35
 
35
36
  def self.apply(model, opts=OPTS)
36
37
  model.instance_variable_set(:@touched_associations, {})
@@ -46,7 +47,7 @@ module Sequel
46
47
  # If a hash is used, the value is used as the column to update.
47
48
  # :column :: The column to modify when touching a model instance.
48
49
  def self.configure(model, opts=OPTS)
49
- model.touch_column = opts[:column] || TOUCH_COLUMN_DEFAULT if opts[:column] || !model.touch_column
50
+ model.touch_column = opts[:column] || :updated_at if opts[:column] || !model.touch_column
50
51
  model.touch_associations(opts[:associations]) if opts[:associations]
51
52
  end
52
53
 
@@ -90,6 +90,8 @@ module Sequel
90
90
  :presence=>{:message=>lambda{"is not present"}},
91
91
  :unique=>{:message=>lambda{'is already taken'}}
92
92
  }
93
+ DEFAULT__OPTIONS = DEFAULT_OPTIONS
94
+ Sequel::Deprecation.deprecate_constant(self, :DEFAULT_OPTIONS)
93
95
 
94
96
  module InstanceMethods
95
97
  # Check that the attribute values are the given exact length.
@@ -129,7 +131,13 @@ module Sequel
129
131
  # Accepts a :nil_message option that is the error message to use when the
130
132
  # value is nil instead of being too long.
131
133
  def validates_max_length(max, atts, opts=OPTS)
132
- validatable_attributes_for_type(:max_length, atts, opts){|a,v,m| v ? validation_error_message(m, max) : validation_error_message(opts[:nil_message] || DEFAULT_OPTIONS[:max_length][:nil_message]) if v.nil? || v.length > max}
134
+ validatable_attributes_for_type(:max_length, atts, opts) do |a,v,m|
135
+ if v.nil?
136
+ validation_error_message(opts[:nil_message] || default_validation_helpers_options(:max_length)[:nil_message])
137
+ elsif v.length > max
138
+ validation_error_message(m, max)
139
+ end
140
+ end
133
141
  end
134
142
 
135
143
  # Check that the attribute values are not shorter than the given min length.
@@ -268,7 +276,7 @@ module Sequel
268
276
  # The hash return must include a :message option that is either a
269
277
  # proc or string.
270
278
  def default_validation_helpers_options(type)
271
- DEFAULT_OPTIONS[type]
279
+ DEFAULT__OPTIONS[type]
272
280
  end
273
281
 
274
282
  # Skip validating any attribute that matches one of the allow_* options.
@@ -1030,10 +1030,13 @@ module Sequel
1030
1030
  # The expression to alias
1031
1031
  attr_reader :expression
1032
1032
 
1033
- # The alias to use for the expression, not +alias+ since that is
1034
- # a keyword in ruby.
1035
- attr_reader :aliaz
1036
- alias_method :alias, :aliaz
1033
+ # The alias to use for the expression
1034
+ attr_reader :alias
1035
+
1036
+ def aliaz
1037
+ Sequel::Deprecation.deprecate("Sequel::SQL::AliasedExpression#aliaz", "Use #alias instead")
1038
+ self.alias
1039
+ end
1037
1040
 
1038
1041
  # The columns aliases to use, for when the aliased expression is
1039
1042
  # a record or set of records (such as a dataset).
@@ -1042,7 +1045,7 @@ module Sequel
1042
1045
  # Create an object with the given expression and alias.
1043
1046
  def initialize(expression, aliaz, columns=nil)
1044
1047
  @expression = expression
1045
- @aliaz = aliaz
1048
+ @alias = aliaz
1046
1049
  @columns = columns
1047
1050
  freeze
1048
1051
  end
@@ -1359,7 +1362,11 @@ module Sequel
1359
1362
 
1360
1363
  # The SQL function to call
1361
1364
  attr_reader :name
1362
- alias f name
1365
+
1366
+ def f
1367
+ Sequel::Deprecation.deprecate("Sequel::SQL::Function#f", "Use #name instead")
1368
+ name
1369
+ end
1363
1370
 
1364
1371
  # The array of arguments to pass to the function (may be blank)
1365
1372
  attr_reader :args
@@ -1917,7 +1924,9 @@ module Sequel
1917
1924
  # For a more detailed explanation, see the {Virtual Rows guide}[rdoc-ref:doc/virtual_rows.rdoc].
1918
1925
  class VirtualRow < BasicObject
1919
1926
  QUESTION_MARK = LiteralString.new('?').freeze
1927
+ Sequel::Deprecation.deprecate_constant(self, :QUESTION_MARK)
1920
1928
  DOUBLE_UNDERSCORE = '__'.freeze
1929
+ Sequel::Deprecation.deprecate_constant(self, :DOUBLE_UNDERSCORE)
1921
1930
 
1922
1931
  include OperatorBuilders
1923
1932
 
@@ -1972,7 +1981,7 @@ module Sequel
1972
1981
  end
1973
1982
  elsif args.empty?
1974
1983
  if split = Sequel.split_symbols?
1975
- table, column = m.to_s.split(DOUBLE_UNDERSCORE, 2)
1984
+ table, column = m.to_s.split('__', 2)
1976
1985
  if column && split == :deprecated
1977
1986
  Sequel::Deprecation.deprecate("Splitting virtual row method names", "Either set Sequel.split_symbols = true, or change #{m.inspect} to #{table}[:#{column}]")
1978
1987
  end
@@ -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 = 48
8
+ MINOR = 49
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
@@ -17,13 +17,13 @@ describe "A MSSQL database" do
17
17
  end
18
18
 
19
19
  it "should be able to read fractional part of timestamp" do
20
- rs = @db["select getutcdate() as full_date, cast(datepart(millisecond, getutcdate()) as int) as milliseconds"].first
21
- rs[:milliseconds].must_equal rs[:full_date].usec/1000
20
+ rs = @db["select getutcdate() as full_date, cast(round(datepart(millisecond, getutcdate()), 0) as int) as milliseconds"].first
21
+ rs[:milliseconds].must_be_close_to(rs[:full_date].usec/1000, 2)
22
22
  end
23
23
 
24
24
  it "should be able to write fractional part of timestamp" do
25
- t = Time.utc(2001, 12, 31, 23, 59, 59, 997000)
26
- (t.usec/1000).must_equal @db["select cast(datepart(millisecond, ?) as int) as milliseconds", t].get
25
+ t = Time.utc(2001, 12, 31, 23, 59, 59, 996000)
26
+ (t.usec/1000).must_equal @db["select cast(round(datepart(millisecond, ?), 0) as int) as milliseconds", t].get
27
27
  end
28
28
 
29
29
  it "should not raise an error when getting the server version" do
@@ -318,7 +318,7 @@ describe "MySQL join expressions" do
318
318
  it "should support cross joins" do
319
319
  @ds.join_table(:cross, :nodes).sql.must_equal 'SELECT * FROM `nodes` CROSS JOIN `nodes`'
320
320
  end
321
- it "should support cross joins as inner joins if conditions are used" do
321
+ deprecated "should support cross joins as inner joins if conditions are used" do
322
322
  @ds.join_table(:cross, :nodes, :id=>:id).sql.must_equal 'SELECT * FROM `nodes` INNER JOIN `nodes` ON (`nodes`.`id` = `nodes`.`id`)'
323
323
  end
324
324
  it "should support straight joins (force left table to be read before right)" do
@@ -1367,6 +1367,10 @@ if DB.adapter_scheme == :mysql2
1367
1367
  it "should correctly handle early returning when streaming results" do
1368
1368
  3.times{@ds.each{|r| break r[:a]}.must_equal 0}
1369
1369
  end
1370
+
1371
+ it "#paged_each should bypass streaming when :stream => false passed in" do
1372
+ DB[:a].order(:a).paged_each(:stream => false){|x| DB[:a].first; break}
1373
+ end
1370
1374
  end
1371
1375
  end
1372
1376
 
@@ -2,6 +2,10 @@ SEQUEL_ADAPTER_TEST = :oracle
2
2
 
3
3
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
4
4
 
5
+ unless DB.opts[:autosequence]
6
+ warn "Running oracle adapter specs without :autosequence Database option results in many errors, use the :autosequence Database option when testing"
7
+ end
8
+
5
9
  describe "An Oracle database" do
6
10
  before(:all) do
7
11
  DB.create_table!(:items) do
@@ -40,7 +40,13 @@ describe "bin/sequel" do
40
40
  DB2.disconnect
41
41
  File.delete(BIN_SPEC_DB) if File.file?(BIN_SPEC_DB)
42
42
  File.delete(BIN_SPEC_DB2) if File.file?(BIN_SPEC_DB2)
43
- File.delete(TMP_FILE) if File.file?(TMP_FILE)
43
+ if File.file?(TMP_FILE)
44
+ begin
45
+ File.delete(TMP_FILE)
46
+ rescue Errno::ENOENT
47
+ nil
48
+ end
49
+ end
44
50
  File.delete(OUTPUT) if File.file?(OUTPUT)
45
51
  end
46
52
 
@@ -18,6 +18,16 @@ describe "An empty ConnectionPool" do
18
18
  @cpool = Sequel::ConnectionPool.get_pool(mock_db.call, CONNECTION_POOL_DEFAULTS)
19
19
  end
20
20
 
21
+ deprecated "should support :pool_class option with string" do
22
+ begin
23
+ c = Class.new(Sequel::ConnectionPool)
24
+ Sequel::ConnectionPool::CONNECTION_POOL__MAP[:foo] = c
25
+ Sequel::ConnectionPool.get_pool(mock_db.call, :pool_class=>:foo).must_be_instance_of c
26
+ ensure
27
+ Sequel::ConnectionPool::CONNECTION_POOL__MAP.delete(c)
28
+ end
29
+ end
30
+
21
31
  it "should have no available connections" do
22
32
  @cpool.available_connections.must_equal []
23
33
  end
@@ -26,9 +36,13 @@ describe "An empty ConnectionPool" do
26
36
  @cpool.allocated.must_equal({})
27
37
  end
28
38
 
29
- it "should have a created_count of zero" do
39
+ deprecated "should have a created_count of zero" do
30
40
  @cpool.created_count.must_equal 0
31
41
  end
42
+
43
+ it "should have a size of zero" do
44
+ @cpool.size.must_equal 0
45
+ end
32
46
  end
33
47
 
34
48
  describe "ConnectionPool options" do
@@ -54,11 +68,11 @@ describe "A connection pool handling connections" do
54
68
  @cpool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| msp.call}){:got_connection}, CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size))
55
69
  end
56
70
 
57
- it "#hold should increment #created_count" do
71
+ it "#hold should increment #size" do
58
72
  @cpool.hold do
59
- @cpool.created_count.must_equal 1
60
- @cpool.hold {@cpool.hold {@cpool.created_count.must_equal 1}}
61
- Thread.new{@cpool.hold {_(@cpool.created_count).must_equal 2}}.join
73
+ @cpool.size.must_equal 1
74
+ @cpool.hold {@cpool.hold {@cpool.size.must_equal 1}}
75
+ Thread.new{@cpool.hold {_(@cpool.size).must_equal 2}}.join
62
76
  end
63
77
  end
64
78
 
@@ -100,7 +114,7 @@ describe "A connection pool handling connections" do
100
114
  q = Queue.new
101
115
  50.times{Thread.new{@cpool.hold{q.pop}}}
102
116
  50.times{q.push nil}
103
- @cpool.created_count.must_be :<=, @max_size
117
+ @cpool.size.must_be :<=, @max_size
104
118
  end
105
119
 
106
120
  it "database's disconnect connection method should be called when a disconnect is detected" do
@@ -110,16 +124,16 @@ describe "A connection pool handling connections" do
110
124
  end
111
125
 
112
126
  it "#hold should remove the connection if a DatabaseDisconnectError is raised" do
113
- @cpool.created_count.must_equal 0
127
+ @cpool.size.must_equal 0
114
128
  q, q1 = Queue.new, Queue.new
115
129
  @cpool.hold{Thread.new{@cpool.hold{q1.pop; q.push nil}; q1.pop; q.push nil}; q1.push nil; q.pop; q1.push nil; q.pop}
116
- @cpool.created_count.must_equal 2
130
+ @cpool.size.must_equal 2
117
131
  proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
118
- @cpool.created_count.must_equal 1
132
+ @cpool.size.must_equal 1
119
133
  proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
120
- @cpool.created_count.must_equal 0
134
+ @cpool.size.must_equal 0
121
135
  proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
122
- @cpool.created_count.must_equal 0
136
+ @cpool.size.must_equal 0
123
137
  end
124
138
  end
125
139
 
@@ -127,13 +141,13 @@ describe "A connection pool handling connection errors" do
127
141
  it "#hold should raise a Sequel::DatabaseConnectionError if an exception is raised by the connection_proc" do
128
142
  cpool = Sequel::ConnectionPool.get_pool(mock_db.call{raise Interrupt}, CONNECTION_POOL_DEFAULTS)
129
143
  proc{cpool.hold{:block_return}}.must_raise(Sequel::DatabaseConnectionError)
130
- cpool.created_count.must_equal 0
144
+ cpool.size.must_equal 0
131
145
  end
132
146
 
133
147
  it "#hold should raise a Sequel::DatabaseConnectionError if nil is returned by the connection_proc" do
134
148
  cpool = Sequel::ConnectionPool.get_pool(mock_db.call{nil}, CONNECTION_POOL_DEFAULTS)
135
149
  proc{cpool.hold{:block_return}}.must_raise(Sequel::DatabaseConnectionError)
136
- cpool.created_count.must_equal 0
150
+ cpool.size.must_equal 0
137
151
  end
138
152
  end
139
153
 
@@ -1100,7 +1114,7 @@ AllConnectionPoolClassesSpecs = shared_description do
1100
1114
  end
1101
1115
  end
1102
1116
 
1103
- Sequel::ConnectionPool::CONNECTION_POOL_MAP.keys.each do |k, v|
1117
+ Sequel::ConnectionPool::CONNECTION_POOL__MAP.keys.each do |k, v|
1104
1118
  opts = {:single_threaded=>k, :servers=>(v ? {} : nil)}
1105
1119
  describe "Connection pool with #{opts.inspect}" do
1106
1120
  before(:all) do
@@ -517,6 +517,130 @@ describe "Database#extend_datasets" do
517
517
  end
518
518
  end
519
519
 
520
+ describe "Database#extend_datasets custom methods" do
521
+ before do
522
+ @db = Sequel.mock
523
+ end
524
+
525
+ def ds
526
+ @db[:items]
527
+ end
528
+
529
+ it "should have dataset_module support a where method" do
530
+ @db.extend_datasets{where :released, :released}
531
+ ds.released.sql.must_equal 'SELECT * FROM items WHERE released'
532
+ ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND released)'
533
+ end
534
+
535
+ it "should have dataset_module support a having method" do
536
+ @db.extend_datasets{having(:released){released}}
537
+ ds.released.sql.must_equal 'SELECT * FROM items HAVING released'
538
+ ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING released'
539
+ end
540
+
541
+ it "should have dataset_module support an exclude method" do
542
+ @db.extend_datasets{exclude :released, :released}
543
+ ds.released.sql.must_equal 'SELECT * FROM items WHERE NOT released'
544
+ ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND NOT released)'
545
+ end
546
+
547
+ it "should have dataset_module support an exclude_having method" do
548
+ @db.extend_datasets{exclude_having :released, :released}
549
+ ds.released.sql.must_equal 'SELECT * FROM items HAVING NOT released'
550
+ ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING NOT released'
551
+ end
552
+
553
+ it "should have dataset_module support a distinct method" do
554
+ @db.extend_datasets{def supports_distinct_on?; true end; distinct :foo, :baz}
555
+ ds.foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items'
556
+ ds.where(:bar).foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items WHERE bar'
557
+ end
558
+
559
+ it "should have dataset_module support a grep method" do
560
+ @db.extend_datasets{grep :foo, :baz, 'quux%'}
561
+ ds.foo.sql.must_equal 'SELECT * FROM items WHERE ((baz LIKE \'quux%\' ESCAPE \'\\\'))'
562
+ ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE (bar AND ((baz LIKE \'quux%\' ESCAPE \'\\\')))'
563
+ end
564
+
565
+ it "should have dataset_module support a group method" do
566
+ @db.extend_datasets{group :foo, :baz}
567
+ ds.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
568
+ ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar GROUP BY baz'
569
+ end
570
+
571
+ it "should have dataset_module support a group_and_count method" do
572
+ @db.extend_datasets{group_and_count :foo, :baz}
573
+ ds.foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items GROUP BY baz'
574
+ ds.where(:bar).foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items WHERE bar GROUP BY baz'
575
+ end
576
+
577
+ it "should have dataset_module support a group_append method" do
578
+ @db.extend_datasets{group_append :foo, :baz}
579
+ ds.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
580
+ ds.group(:bar).foo.sql.must_equal 'SELECT * FROM items GROUP BY bar, baz'
581
+ end
582
+
583
+ it "should have dataset_module support a limit method" do
584
+ @db.extend_datasets{limit :foo, 1}
585
+ ds.foo.sql.must_equal 'SELECT * FROM items LIMIT 1'
586
+ ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar LIMIT 1'
587
+ end
588
+
589
+ it "should have dataset_module support a offset method" do
590
+ @db.extend_datasets{offset :foo, 1}
591
+ ds.foo.sql.must_equal 'SELECT * FROM items OFFSET 1'
592
+ ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar OFFSET 1'
593
+ end
594
+
595
+ it "should have dataset_module support a order method" do
596
+ @db.extend_datasets{order(:foo){:baz}}
597
+ ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
598
+ ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz'
599
+ end
600
+
601
+ it "should have dataset_module support a order_append method" do
602
+ @db.extend_datasets{order_append :foo, :baz}
603
+ ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
604
+ ds.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY bar, baz'
605
+ end
606
+
607
+ it "should have dataset_module support a order_prepend method" do
608
+ @db.extend_datasets{order_prepend :foo, :baz}
609
+ ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
610
+ ds.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY baz, bar'
611
+ end
612
+
613
+ it "should have dataset_module support a select method" do
614
+ @db.extend_datasets{select :foo, :baz}
615
+ ds.foo.sql.must_equal 'SELECT baz FROM items'
616
+ ds.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar'
617
+ end
618
+
619
+ it "should have dataset_module support a select_all method" do
620
+ @db.extend_datasets{select_all :foo, :baz}
621
+ ds.foo.sql.must_equal 'SELECT baz.* FROM items'
622
+ ds.where(:bar).foo.sql.must_equal 'SELECT baz.* FROM items WHERE bar'
623
+ end
624
+
625
+ it "should have dataset_module support a select_append method" do
626
+ @db.extend_datasets{select_append :foo, :baz}
627
+ ds.foo.sql.must_equal 'SELECT *, baz FROM items'
628
+ ds.where(:bar).foo.sql.must_equal 'SELECT *, baz FROM items WHERE bar'
629
+ end
630
+
631
+ it "should have dataset_module support a select_group method" do
632
+ @db.extend_datasets{select_group :foo, :baz}
633
+ ds.foo.sql.must_equal 'SELECT baz FROM items GROUP BY baz'
634
+ ds.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar GROUP BY baz'
635
+ end
636
+
637
+ it "should have dataset_module support a server method" do
638
+ @db.extend_datasets{server :foo, :baz}
639
+ ds.foo.opts[:server].must_equal :baz
640
+ ds.where(:bar).foo.opts[:server].must_equal :baz
641
+ end
642
+ end
643
+
520
644
  describe "Database#disconnect_connection" do
521
645
  it "should call close on the connection" do
522
646
  o = Object.new
@@ -2257,6 +2381,31 @@ describe "Database#typecast_value" do
2257
2381
  end
2258
2382
  end
2259
2383
 
2384
+ it "should have an underlying exception class available at cause" do
2385
+ begin
2386
+ @db.typecast_value(:date, 'a')
2387
+ true.must_equal false
2388
+ rescue Sequel::InvalidValue => e
2389
+ e.cause.must_be_kind_of(ArgumentError)
2390
+ end
2391
+ end if RUBY_VERSION >= '2.1'
2392
+
2393
+ it "should have an underlying exception class available at cause when using nested exceptions" do
2394
+ begin
2395
+ begin
2396
+ raise ArgumentError
2397
+ rescue => e1
2398
+ begin
2399
+ raise RuntimeError
2400
+ rescue => e2
2401
+ @db.send(:raise_error, e1)
2402
+ end
2403
+ end
2404
+ rescue Sequel::DatabaseError => e
2405
+ e.cause.must_be_kind_of(ArgumentError)
2406
+ end
2407
+ end if RUBY_VERSION >= '2.1'
2408
+
2260
2409
  it "should include underlying exception class in #inspect" do
2261
2410
  begin
2262
2411
  @db.typecast_value(:date, 'a')