sequel 5.8.0 → 5.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +30 -0
  3. data/doc/release_notes/5.9.0.txt +99 -0
  4. data/doc/testing.rdoc +10 -10
  5. data/lib/sequel/adapters/ado.rb +1 -1
  6. data/lib/sequel/adapters/amalgalite.rb +1 -1
  7. data/lib/sequel/adapters/jdbc.rb +19 -7
  8. data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -5
  10. data/lib/sequel/adapters/postgres.rb +3 -3
  11. data/lib/sequel/adapters/shared/access.rb +5 -6
  12. data/lib/sequel/adapters/shared/mysql.rb +28 -2
  13. data/lib/sequel/adapters/shared/postgres.rb +16 -6
  14. data/lib/sequel/adapters/shared/sqlite.rb +1 -1
  15. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  16. data/lib/sequel/adapters/sqlite.rb +2 -2
  17. data/lib/sequel/connection_pool.rb +2 -1
  18. data/lib/sequel/connection_pool/sharded_threaded.rb +12 -4
  19. data/lib/sequel/connection_pool/threaded.rb +19 -7
  20. data/lib/sequel/core.rb +1 -1
  21. data/lib/sequel/database/connecting.rb +6 -6
  22. data/lib/sequel/database/misc.rb +3 -3
  23. data/lib/sequel/database/query.rb +2 -2
  24. data/lib/sequel/database/schema_generator.rb +9 -3
  25. data/lib/sequel/database/schema_methods.rb +12 -5
  26. data/lib/sequel/dataset/features.rb +5 -0
  27. data/lib/sequel/dataset/misc.rb +1 -1
  28. data/lib/sequel/dataset/prepared_statements.rb +4 -4
  29. data/lib/sequel/dataset/query.rb +5 -0
  30. data/lib/sequel/dataset/sql.rb +8 -6
  31. data/lib/sequel/extensions/escaped_like.rb +100 -0
  32. data/lib/sequel/extensions/eval_inspect.rb +3 -1
  33. data/lib/sequel/extensions/looser_typecasting.rb +3 -3
  34. data/lib/sequel/extensions/pg_extended_date_support.rb +23 -10
  35. data/lib/sequel/model/associations.rb +18 -4
  36. data/lib/sequel/model/base.rb +9 -2
  37. data/lib/sequel/plugins/defaults_setter.rb +1 -1
  38. data/lib/sequel/plugins/many_through_many.rb +1 -1
  39. data/lib/sequel/plugins/nested_attributes.rb +2 -2
  40. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +2 -2
  41. data/lib/sequel/plugins/rcte_tree.rb +5 -7
  42. data/lib/sequel/plugins/sharding.rb +2 -2
  43. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  44. data/lib/sequel/plugins/tree.rb +2 -2
  45. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  46. data/lib/sequel/sql.rb +2 -2
  47. data/lib/sequel/version.rb +4 -1
  48. data/spec/adapters/mysql_spec.rb +24 -0
  49. data/spec/adapters/postgres_spec.rb +9 -9
  50. data/spec/adapters/sqlite_spec.rb +10 -10
  51. data/spec/core/connection_pool_spec.rb +22 -0
  52. data/spec/core/database_spec.rb +6 -6
  53. data/spec/core/dataset_spec.rb +16 -5
  54. data/spec/core/expression_filters_spec.rb +1 -1
  55. data/spec/core/schema_spec.rb +1 -1
  56. data/spec/core/version_spec.rb +7 -0
  57. data/spec/extensions/connection_expiration_spec.rb +20 -2
  58. data/spec/extensions/connection_validator_spec.rb +20 -3
  59. data/spec/extensions/escaped_like_spec.rb +40 -0
  60. data/spec/extensions/eval_inspect_spec.rb +1 -1
  61. data/spec/extensions/nested_attributes_spec.rb +6 -0
  62. data/spec/extensions/pg_array_spec.rb +13 -13
  63. data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -1
  64. data/spec/extensions/pg_range_spec.rb +1 -1
  65. data/spec/extensions/schema_dumper_spec.rb +2 -2
  66. data/spec/extensions/sql_expr_spec.rb +1 -1
  67. data/spec/extensions/string_agg_spec.rb +1 -1
  68. data/spec/extensions/timestamps_spec.rb +2 -2
  69. data/spec/extensions/validation_helpers_spec.rb +1 -1
  70. data/spec/integration/associations_test.rb +12 -0
  71. data/spec/integration/dataset_test.rb +21 -0
  72. data/spec/integration/type_test.rb +4 -4
  73. data/spec/model/base_spec.rb +9 -0
  74. data/spec/model/eager_loading_spec.rb +25 -0
  75. data/spec/model/record_spec.rb +1 -1
  76. metadata +6 -2
@@ -96,7 +96,7 @@ module Sequel
96
96
  name = opts[:name]
97
97
  if (!associations.include?(name) || dynamic_opts[:eager_reload]) && opts[:allow_eager] != false && retrieved_by && !frozen? && !dynamic_opts[:callback] && !dynamic_opts[:reload]
98
98
  begin
99
- retrieved_by.send(:eager_load, retrieved_with.reject(&:frozen?), name=>dynamic_opts[:eager] || {})
99
+ retrieved_by.send(:eager_load, retrieved_with.reject(&:frozen?), name=>dynamic_opts[:eager] || OPTS)
100
100
  rescue Sequel::UndefinedAssociation
101
101
  # This can happen if class table inheritance is used and the association
102
102
  # is only defined in a subclass. This particular instance can use the
@@ -38,10 +38,10 @@ module Sequel
38
38
  @tree_order = opts[:order]
39
39
  end
40
40
 
41
- par = opts.merge(opts.fetch(:parent, {}))
41
+ par = opts.merge(opts.fetch(:parent, OPTS))
42
42
  parent = par.fetch(:name, :parent)
43
43
 
44
- chi = opts.merge(opts.fetch(:children, {}))
44
+ chi = opts.merge(opts.fetch(:children, OPTS))
45
45
  children = chi.fetch(:name, :children)
46
46
 
47
47
  par[:reciprocal] = children
@@ -419,7 +419,7 @@ module Sequel
419
419
  # an empty hash is returned This method is useful when writing methods that
420
420
  # take an options hash as the last parameter.
421
421
  def extract_options!(array)
422
- array.last.is_a?(Hash) ? array.pop : {}
422
+ array.last.is_a?(Hash) ? array.pop : OPTS
423
423
  end
424
424
 
425
425
  # Add the validation reflection to the class's validations.
@@ -1366,7 +1366,7 @@ module Sequel
1366
1366
  end
1367
1367
 
1368
1368
  # Return a new function with an OVER clause (making it a window function).
1369
- # See {SQL::Window} for the list of options +over+ can receive.
1369
+ # See Sequel::SQL::Window for the list of options +over+ can receive.
1370
1370
  #
1371
1371
  # Sequel.function(:row_number).over(partition: :col) # row_number() OVER (PARTITION BY col)
1372
1372
  def over(window=OPTS)
@@ -1703,7 +1703,7 @@ module Sequel
1703
1703
  # StringExpression.like(:a, 'a%', /^a/i) # (("a" LIKE 'a%' ESCAPE '\') OR ("a" ~* '^a'))
1704
1704
  def self.like(l, *ces)
1705
1705
  l, lre, lci = like_element(l)
1706
- lci = (ces.last.is_a?(Hash) ? ces.pop : {})[:case_insensitive] ? true : lci
1706
+ lci = (ces.last.is_a?(Hash) ? ces.pop : OPTS)[:case_insensitive] ? true : lci
1707
1707
  ces.map! do |ce|
1708
1708
  r, rre, rci = like_element(ce)
1709
1709
  BooleanExpression.new(LIKE_MAP[[lre||rre, lci||rci]], l, r)
@@ -5,13 +5,16 @@ module Sequel
5
5
  MAJOR = 5
6
6
  # The minor version of Sequel. Bumped for every non-patch level
7
7
  # release, generally around once a month.
8
- MINOR = 8
8
+ MINOR = 9
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
12
12
 
13
13
  # The version of Sequel you are using, as a string (e.g. "2.11.0")
14
14
  VERSION = [MAJOR, MINOR, TINY].join('.').freeze
15
+
16
+ # The version of Sequel you are using, as a number (2.11.0 -> 20110)
17
+ VERSION_NUMBER = MAJOR*10000 + MINOR*10 + TINY
15
18
 
16
19
  # The version of Sequel you are using, as a string (e.g. "2.11.0")
17
20
  def self.version
@@ -69,6 +69,12 @@ describe "MySQL", '#create_table' do
69
69
  @db.set_column_type :dolls, :a, Integer, :auto_increment=>true
70
70
  @db.schema(:dolls).first.last[:auto_increment].must_equal true
71
71
  end
72
+
73
+ it "should create generated column" do
74
+ skip("generated columns not supported, skipping test") unless @db.supports_generated_columns?
75
+ @db.create_table(:dolls){String :a; String :b, generated_always_as: Sequel.function(:CONCAT, :a, 'plus')}
76
+ @db.schema(:dolls)[1][1][:generated].must_equal true
77
+ end
72
78
  end
73
79
 
74
80
  if [:mysql, :mysql2].include?(DB.adapter_scheme)
@@ -203,6 +209,13 @@ describe "A MySQL dataset" do
203
209
  ps.call(:v => 1, :n => 'b')
204
210
  ds.all.must_equal [{:value=>1, :name=>'b'}]
205
211
  end
212
+
213
+ it "should support generated columns" do
214
+ skip("generated columns not supported, skipping test") unless DB.supports_generated_columns?
215
+ DB.alter_table(:items) {add_column :b, String, :generated_always_as => Sequel.function(:CONCAT, :name, 'plus')}
216
+ @d.insert(name: 'hello')
217
+ @d.first[:b].must_equal 'helloplus'
218
+ end
206
219
  end
207
220
 
208
221
  describe "Dataset#distinct" do
@@ -219,6 +232,8 @@ describe "Dataset#distinct" do
219
232
  end
220
233
 
221
234
  it "#distinct with arguments should return results distinct on those arguments" do
235
+ skip("ONLY_FULL_GROUP_BY sql_mode set, skipping DISTINCT ON emulation test") if @db.get(Sequel.lit '@@sql_mode').include?('ONLY_FULL_GROUP_BY')
236
+
222
237
  @ds.insert(20, 10)
223
238
  @ds.insert(30, 10)
224
239
  @ds.order(:b, :a).distinct.map(:a).must_equal [20, 30]
@@ -501,6 +516,15 @@ describe "A MySQL database" do
501
516
  @db << 'DELETE FROM items'
502
517
  @db[:items].first.must_be_nil
503
518
  end
519
+
520
+ it "should have schema handle generated columns" do
521
+ skip("generated columns not supported, skipping test") unless @db.supports_generated_columns?
522
+ @db.create_table(:items) {String :a}
523
+ @db.alter_table(:items){add_column :b, String, :generated_always_as=>Sequel.function(:CONCAT, :a, 'plus'), :generated_type=>:stored, :unique=>true}
524
+ @db.schema(:items)[1][1][:generated].must_equal true
525
+ @db.alter_table(:items){add_column :c, String, :generated_always_as=>Sequel.function(:CONCAT, :a, 'minus'), :generated_type=>:virtual}
526
+ @db.schema(:items)[2][1][:generated].must_equal true
527
+ end
504
528
  end
505
529
 
506
530
  # Socket tests should only be run if the MySQL server is on localhost
@@ -2186,10 +2186,10 @@ describe 'PostgreSQL array handling' do
2186
2186
  column :n, 'numeric[]'
2187
2187
  end
2188
2188
  @tp.call.must_equal [:decimal_array]
2189
- @ds.insert(Sequel.pg_array([BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')], :numeric))
2189
+ @ds.insert(Sequel.pg_array([BigDecimal('1.000000000000000000001'), nil, BigDecimal('1')], :numeric))
2190
2190
  @ds.count.must_equal 1
2191
2191
  rs = @ds.all
2192
- rs.must_equal [{:n=>[BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')]}]
2192
+ rs.must_equal [{:n=>[BigDecimal('1.000000000000000000001'), nil, BigDecimal('1')]}]
2193
2193
  rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
2194
2194
  rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
2195
2195
  @ds.delete
@@ -2197,9 +2197,9 @@ describe 'PostgreSQL array handling' do
2197
2197
  @ds.all.must_equal rs
2198
2198
 
2199
2199
  @ds.delete
2200
- @ds.insert(Sequel.pg_array([[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]], :numeric))
2200
+ @ds.insert(Sequel.pg_array([[BigDecimal('1.0000000000000000000000000000001'), nil], [nil, BigDecimal('1')]], :numeric))
2201
2201
  rs = @ds.all
2202
- rs.must_equal [{:n=>[[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]]}]
2202
+ rs.must_equal [{:n=>[[BigDecimal('1.0000000000000000000000000000001'), nil], [nil, BigDecimal('1')]]}]
2203
2203
  rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
2204
2204
  rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
2205
2205
  @ds.delete
@@ -2469,11 +2469,11 @@ describe 'PostgreSQL array handling' do
2469
2469
  column :t, 'text[]'
2470
2470
  end
2471
2471
  c = Class.new(Sequel::Model(@db[:items]))
2472
- h = {:i=>[1,2, nil], :f=>[[1, 2.5], [3, 4.5]], :d=>[1, BigDecimal.new('1.000000000000000000001')], :t=>[%w'a b c', ['NULL', nil, '1']]}
2472
+ h = {:i=>[1,2, nil], :f=>[[1, 2.5], [3, 4.5]], :d=>[1, BigDecimal('1.000000000000000000001')], :t=>[%w'a b c', ['NULL', nil, '1']]}
2473
2473
  o = c.create(h)
2474
2474
  o.i.must_equal [1, 2, nil]
2475
2475
  o.f.must_equal [[1, 2.5], [3, 4.5]]
2476
- o.d.must_equal [BigDecimal.new('1'), BigDecimal.new('1.000000000000000000001')]
2476
+ o.d.must_equal [BigDecimal('1'), BigDecimal('1.000000000000000000001')]
2477
2477
  o.t.must_equal [%w'a b c', ['NULL', nil, '1']]
2478
2478
  c.where(:i=>o.i, :f=>o.f, :d=>o.d, :t=>o.t).all.must_equal [o]
2479
2479
  o2 = c.new(h)
@@ -2487,10 +2487,10 @@ describe 'PostgreSQL array handling' do
2487
2487
  column :t, 'varchar[]'
2488
2488
  end
2489
2489
  c = Class.new(Sequel::Model(@db[:items]))
2490
- o = c.create(:i=>[1,2, nil], :f=>[[1, 2.5], [3, 4.5]], :d=>[1, BigDecimal.new('1.000000000000000000001')], :t=>[%w'a b c', ['NULL', nil, '1']])
2490
+ o = c.create(:i=>[1,2, nil], :f=>[[1, 2.5], [3, 4.5]], :d=>[1, BigDecimal('1.000000000000000000001')], :t=>[%w'a b c', ['NULL', nil, '1']])
2491
2491
  o.i.must_equal [1, 2, nil]
2492
2492
  o.f.must_equal [[1, 2.5], [3, 4.5]]
2493
- o.d.must_equal [BigDecimal.new('1'), BigDecimal.new('1.000000000000000000001')]
2493
+ o.d.must_equal [BigDecimal('1'), BigDecimal('1.000000000000000000001')]
2494
2494
  o.t.must_equal [%w'a b c', ['NULL', nil, '1']]
2495
2495
  c.where(:i=>o.i, :f=>o.f, :d=>o.d, :t=>o.t).all.must_equal [o]
2496
2496
  o2 = c.new(h)
@@ -3225,7 +3225,7 @@ describe 'PostgreSQL range types' do
3225
3225
  @db = DB
3226
3226
  @ds = @db[:items]
3227
3227
  @map = {:i4=>'int4range', :i8=>'int8range', :n=>'numrange', :d=>'daterange', :t=>'tsrange', :tz=>'tstzrange'}
3228
- @r = {:i4=>1...2, :i8=>2...3, :n=>BigDecimal.new('1.0')..BigDecimal.new('2.0'), :d=>Date.today...(Date.today+1), :t=>Time.local(2011, 1)..Time.local(2011, 2), :tz=>Time.local(2011, 1)..Time.local(2011, 2)}
3228
+ @r = {:i4=>1...2, :i8=>2...3, :n=>BigDecimal('1.0')..BigDecimal('2.0'), :d=>Date.today...(Date.today+1), :t=>Time.local(2011, 1)..Time.local(2011, 2), :tz=>Time.local(2011, 1)..Time.local(2011, 2)}
3229
3229
  @ra = {}
3230
3230
  @pgr = {}
3231
3231
  @pgra = {}
@@ -77,12 +77,12 @@ describe "An SQLite database" do
77
77
  it "should handle and return BigDecimal values for numeric columns" do
78
78
  DB.create_table!(:fk){numeric :d}
79
79
  d = DB[:fk]
80
- d.insert(:d=>BigDecimal.new('80.0'))
81
- d.insert(:d=>BigDecimal.new('NaN'))
82
- d.insert(:d=>BigDecimal.new('Infinity'))
83
- d.insert(:d=>BigDecimal.new('-Infinity'))
80
+ d.insert(:d=>BigDecimal('80.0'))
81
+ d.insert(:d=>BigDecimal('NaN'))
82
+ d.insert(:d=>BigDecimal('Infinity'))
83
+ d.insert(:d=>BigDecimal('-Infinity'))
84
84
  ds = d.all
85
- ds.shift.must_equal(:d=>BigDecimal.new('80.0'))
85
+ ds.shift.must_equal(:d=>BigDecimal('80.0'))
86
86
  ds.map{|x| x[:d].to_s}.must_equal %w'NaN Infinity -Infinity'
87
87
  DB
88
88
  end
@@ -153,19 +153,19 @@ describe "SQLite type conversion" do
153
153
  it "should handle integers/floats/strings/decimals in numeric/decimal columns" do
154
154
  @db.create_table(:items){Numeric :a}
155
155
  @db[:items].insert(100)
156
- @db[:items].select_map(:a).must_equal [BigDecimal.new('100')]
156
+ @db[:items].select_map(:a).must_equal [BigDecimal('100')]
157
157
  @db[:items].get(:a).must_be_kind_of(BigDecimal)
158
158
 
159
159
  @db[:items].update(:a=>100.1)
160
- @db[:items].select_map(:a).must_equal [BigDecimal.new('100.1')]
160
+ @db[:items].select_map(:a).must_equal [BigDecimal('100.1')]
161
161
  @db[:items].get(:a).must_be_kind_of(BigDecimal)
162
162
 
163
163
  @db[:items].update(:a=>'100.1')
164
- @db[:items].select_map(:a).must_equal [BigDecimal.new('100.1')]
164
+ @db[:items].select_map(:a).must_equal [BigDecimal('100.1')]
165
165
  @db[:items].get(:a).must_be_kind_of(BigDecimal)
166
166
 
167
- @db[:items].update(:a=>BigDecimal.new('100.1'))
168
- @db[:items].select_map(:a).must_equal [BigDecimal.new('100.1')]
167
+ @db[:items].update(:a=>BigDecimal('100.1'))
168
+ @db[:items].select_map(:a).must_equal [BigDecimal('100.1')]
169
169
  @db[:items].get(:a).must_be_kind_of(BigDecimal)
170
170
  end
171
171
 
@@ -549,6 +549,28 @@ ThreadedConnectionPoolSpecs = shared_description do
549
549
  @pool.size.must_equal 0
550
550
  d.must_equal [2, 1, 3, 4]
551
551
  end
552
+
553
+
554
+ it "should handle dead threads with checked out connections" do
555
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>1))
556
+
557
+ skip = true
558
+ # Leave allocated connection to emulate dead thread with checked out connection
559
+ pool.define_singleton_method(:release){|*a| return if skip; super(*a)}
560
+ Thread.new{pool.hold{Thread.current.kill}}.join
561
+ skip = false
562
+
563
+ pool.allocated.wont_be :empty?
564
+ pool.available_connections.must_be :empty?
565
+
566
+ pool.hold{|c1| c1}
567
+ pool.allocated.must_be :empty?
568
+ pool.available_connections.wont_be :empty?
569
+
570
+ pool.disconnect
571
+ pool.allocated.must_be :empty?
572
+ pool.available_connections.must_be :empty?
573
+ end
552
574
  end
553
575
 
554
576
  describe "Threaded Unsharded Connection Pool" do
@@ -2167,7 +2167,7 @@ describe "Database#typecast_value" do
2167
2167
  [1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
2168
2168
  v = @db.typecast_value(:decimal, i)
2169
2169
  v.must_be_kind_of(BigDecimal)
2170
- v.must_equal BigDecimal.new('1.0')
2170
+ v.must_equal BigDecimal('1.0')
2171
2171
  end
2172
2172
  end
2173
2173
 
@@ -2426,8 +2426,8 @@ describe "Database#column_schema_to_ruby_default" do
2426
2426
  p[1.0, :float].must_equal 1.0
2427
2427
  p['1.0', :float].must_equal 1.0
2428
2428
  p['-1.0', :float].must_equal(-1.0)
2429
- p['1.0', :decimal].must_equal BigDecimal.new('1.0')
2430
- p['-1.0', :decimal].must_equal BigDecimal.new('-1.0')
2429
+ p['1.0', :decimal].must_equal BigDecimal('1.0')
2430
+ p['-1.0', :decimal].must_equal BigDecimal('-1.0')
2431
2431
  p[true, :boolean].must_equal true
2432
2432
  p[false, :boolean].must_equal false
2433
2433
  p['1', :boolean].must_equal true
@@ -2463,7 +2463,7 @@ describe "Database#column_schema_to_ruby_default" do
2463
2463
  p["'a'::bpchar", :string].must_equal "a"
2464
2464
  p["(-1)", :integer].must_equal(-1)
2465
2465
  p["(-1.0)", :float].must_equal(-1.0)
2466
- p['(-1.0)', :decimal].must_equal BigDecimal.new('-1.0')
2466
+ p['(-1.0)', :decimal].must_equal BigDecimal('-1.0')
2467
2467
  p["'a'::bytea", :blob].must_equal Sequel.blob('a')
2468
2468
  p["'a'::bytea", :blob].must_be_kind_of(Sequel::SQL::Blob)
2469
2469
  p["'2009-10-29'::date", :date].must_equal Date.new(2009,10,29)
@@ -2475,7 +2475,7 @@ describe "Database#column_schema_to_ruby_default" do
2475
2475
  p["a", :string].must_equal "a"
2476
2476
  p["NULL", :string].must_equal "NULL"
2477
2477
  p["-1", :float].must_equal(-1.0)
2478
- p['-1', :decimal].must_equal BigDecimal.new('-1.0')
2478
+ p['-1', :decimal].must_equal BigDecimal('-1.0')
2479
2479
  p["2009-10-29", :date].must_equal Date.new(2009,10,29)
2480
2480
  p["2009-10-29 10:20:30", :datetime].must_equal DateTime.parse('2009-10-29 10:20:30')
2481
2481
  p["10:20:30", :time].must_equal Time.parse('10:20:30')
@@ -2486,7 +2486,7 @@ describe "Database#column_schema_to_ruby_default" do
2486
2486
  p["(N'a')", :string].must_equal "a"
2487
2487
  p["((-12))", :integer].must_equal(-12)
2488
2488
  p["((12.1))", :float].must_equal 12.1
2489
- p["((-12.1))", :decimal].must_equal BigDecimal.new('-12.1')
2489
+ p["((-12.1))", :decimal].must_equal BigDecimal('-12.1')
2490
2490
  end
2491
2491
  end
2492
2492
 
@@ -623,7 +623,7 @@ describe "Dataset#where" do
623
623
  it "should raise an error if an numeric is used" do
624
624
  proc{@dataset.filter(1)}.must_raise(Sequel::Error)
625
625
  proc{@dataset.filter(1.0)}.must_raise(Sequel::Error)
626
- proc{@dataset.filter(BigDecimal.new('1.0'))}.must_raise(Sequel::Error)
626
+ proc{@dataset.filter(BigDecimal('1.0'))}.must_raise(Sequel::Error)
627
627
  end
628
628
 
629
629
  it "should raise an error if a NumericExpression or StringExpression is used" do
@@ -1082,10 +1082,10 @@ describe "Dataset#literal" do
1082
1082
  end
1083
1083
 
1084
1084
  it "should literalize BigDecimal instances correctly" do
1085
- @dataset.literal(BigDecimal.new("80")).must_equal "80.0"
1086
- @dataset.literal(BigDecimal.new("NaN")).must_equal "'NaN'"
1087
- @dataset.literal(BigDecimal.new("Infinity")).must_equal "'Infinity'"
1088
- @dataset.literal(BigDecimal.new("-Infinity")).must_equal "'-Infinity'"
1085
+ @dataset.literal(BigDecimal("80")).must_equal "80.0"
1086
+ @dataset.literal(BigDecimal("NaN")).must_equal "'NaN'"
1087
+ @dataset.literal(BigDecimal("Infinity")).must_equal "'Infinity'"
1088
+ @dataset.literal(BigDecimal("-Infinity")).must_equal "'-Infinity'"
1089
1089
  end
1090
1090
 
1091
1091
  it "should literalize PlaceholderLiteralStrings correctly" do
@@ -3799,6 +3799,17 @@ describe "Dataset#with_sql_*" do
3799
3799
  @ds.with_sql_single_value('SELECT * FROM foo')
3800
3800
  @ds.columns.must_equal [:x]
3801
3801
  end
3802
+
3803
+ it "#_with_sql_dataset (private) should return a clone that doesn't use separate dataset for columns" do
3804
+ @ds = @ds.with_extend{def fetch_rows(sql) self.columns = [:id]; super end}
3805
+ @ds.send(:cache_set, :_columns, [:foo])
3806
+ ds = @ds.send(:_with_sql_dataset)
3807
+ ds.must_be_same_as ds.send(:_with_sql_dataset)
3808
+ ds.with_sql_first('SELECT * FROM foo').must_equal(:id=>1)
3809
+ ds.columns.must_equal [:id]
3810
+ @ds.with_sql_first('SELECT * FROM foo').must_equal(:id=>1)
3811
+ @ds.columns.must_equal [:foo]
3812
+ end
3802
3813
  end
3803
3814
 
3804
3815
  describe "Dataset prepared statements and bound variables " do
@@ -186,7 +186,7 @@ describe "Blockless Ruby Filters" do
186
186
  @d.lit(1 + Sequel.expr(:x)).must_equal '(1 + x)'
187
187
  @d.lit(2**65 - Sequel.+(:x, 1)).must_equal "(#{2**65} - (x + 1))"
188
188
  @d.lit(1.0 / Sequel.function(:x)).must_equal '(1.0 / x())'
189
- @d.lit(BigDecimal.new('1.0') * Sequel[:a][:y]).must_equal '(1.0 * a.y)'
189
+ @d.lit(BigDecimal('1.0') * Sequel[:a][:y]).must_equal '(1.0 * a.y)'
190
190
  @d.lit(2 ** Sequel.cast(:x, Integer)).must_equal 'power(2, CAST(x AS integer))'
191
191
  @d.lit(1 + Sequel.lit('x')).must_equal '(1 + x)'
192
192
  @d.lit(1 + Sequel.lit('?', :x)).must_equal '(1 + x)'
@@ -1679,7 +1679,7 @@ describe "Schema Parser" do
1679
1679
  sch = @db.schema(:x)
1680
1680
  sch.must_equal [[:a, {:db_type=>"x", :ruby_default=>nil}], [:b, {:db_type=>"x", :ruby_default=>nil}]]
1681
1681
  sch[0][1][:db_type].must_be_same_as(sch[1][1][:db_type])
1682
- end if RUBY_VERSION >= '2.5'
1682
+ end if RUBY_VERSION >= '2.5' && !defined?(JRUBY_VERSION)
1683
1683
 
1684
1684
  it "should set :auto_increment to true by default if unset and a single integer primary key is used" do
1685
1685
  @db.define_singleton_method(:schema_parse_table){|*| [[:a, {:primary_key=>true, :db_type=>'integer'}]]}
@@ -4,4 +4,11 @@ describe "Sequel.version" do
4
4
  it "should be in the form X.Y.Z with all being numbers" do
5
5
  Sequel.version.must_match(/\A\d+\.\d+\.\d+\z/)
6
6
  end
7
+
8
+ it "MAJOR/MINOR/TINY/VERSION_NUMBER should be integers" do
9
+ Sequel::MAJOR.must_be_kind_of(Integer)
10
+ Sequel::MINOR.must_be_kind_of(Integer)
11
+ Sequel::TINY.must_be_kind_of(Integer)
12
+ Sequel::VERSION_NUMBER.must_be_kind_of(Integer)
13
+ end
7
14
  end
@@ -3,11 +3,12 @@ require_relative "spec_helper"
3
3
  connection_expiration_specs = shared_description do
4
4
  describe "connection expiration" do
5
5
  before do
6
- @db.extend(Module.new do
6
+ @m = Module.new do
7
7
  def disconnect_connection(conn)
8
8
  @sqls << 'disconnect'
9
9
  end
10
- end)
10
+ end
11
+ @db.extend @m
11
12
  @db.extension(:connection_expiration)
12
13
  @db.pool.connection_expiration_timeout = 2
13
14
  end
@@ -21,6 +22,23 @@ connection_expiration_specs = shared_description do
21
22
  @db.pool.connection_expiration_timeout.must_equal 2
22
23
  end
23
24
 
25
+ it "should handle Database#disconnect calls while the connection is checked out" do
26
+ @db.synchronize{|c| @db.disconnect}
27
+ end
28
+
29
+ it "should handle disconnected connections" do
30
+ proc{@db.synchronize{|c| raise Sequel::DatabaseDisconnectError}}.must_raise Sequel::DatabaseDisconnectError
31
+ @db.sqls.must_equal ['disconnect']
32
+ end
33
+
34
+ it "should handle :connection_handling => :disconnect setting" do
35
+ @db = Sequel.mock(@db.opts.merge(:connection_handling => :disconnect))
36
+ @db.extend @m
37
+ @db.extension(:connection_expiration)
38
+ @db.synchronize{}
39
+ @db.sqls.must_equal ['disconnect']
40
+ end
41
+
24
42
  it "should only expire if older than timeout" do
25
43
  c1 = @db.synchronize{|c| c}
26
44
  @db.sqls.must_equal []
@@ -3,7 +3,7 @@ require_relative "spec_helper"
3
3
  connection_validator_specs = shared_description do
4
4
  describe "connection validator" do
5
5
  before do
6
- @db.extend(Module.new do
6
+ @m = Module.new do
7
7
  def disconnect_connection(conn)
8
8
  @sqls << 'disconnect'
9
9
  end
@@ -19,7 +19,8 @@ connection_validator_specs = shared_description do
19
19
  conn.valid = true
20
20
  conn
21
21
  end
22
- end)
22
+ end
23
+ @db.extend @m
23
24
  @db.extension(:connection_validator)
24
25
  end
25
26
 
@@ -52,6 +53,23 @@ connection_validator_specs = shared_description do
52
53
  c2.wont_be_same_as(c1)
53
54
  end
54
55
 
56
+ it "should handle Database#disconnect calls while the connection is checked out" do
57
+ @db.synchronize{|c| @db.disconnect}
58
+ end
59
+
60
+ it "should handle disconnected connections" do
61
+ proc{@db.synchronize{|c| raise Sequel::DatabaseDisconnectError}}.must_raise Sequel::DatabaseDisconnectError
62
+ @db.sqls.must_equal ['disconnect']
63
+ end
64
+
65
+ it "should handle :connection_handling => :disconnect setting" do
66
+ @db = Sequel.mock(@db.opts.merge(:connection_handling => :disconnect))
67
+ @db.extend @m
68
+ @db.extension(:connection_validator)
69
+ @db.synchronize{}
70
+ @db.sqls.must_equal ['disconnect']
71
+ end
72
+
55
73
  it "should disconnect multiple connections repeatedly if they are not valid" do
56
74
  q, q1 = Queue.new, Queue.new
57
75
  c1 = nil
@@ -124,4 +142,3 @@ describe "Sequel::ConnectionValidator with sharded threaded pool" do
124
142
  end
125
143
  include connection_validator_specs
126
144
  end
127
-