sequel 5.8.0 → 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
@@ -0,0 +1,40 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "escaped_like extension" do
4
+ before do
5
+ Sequel.extension(:escaped_like)
6
+ @ds = Sequel.mock[:t]
7
+ @c = Sequel[:c]
8
+ end
9
+
10
+ it "escaped_like should support creating case sensitive pattern matches" do
11
+ @ds.where(@c.escaped_like('?', 'a')).sql.must_equal "SELECT * FROM t WHERE (c LIKE 'a' ESCAPE '\\')"
12
+ @ds.where(@c.escaped_like('?%', 'a')).sql.must_equal "SELECT * FROM t WHERE (c LIKE 'a%' ESCAPE '\\')"
13
+ @ds.where(@c.escaped_like('?', 'a%')).sql.must_equal "SELECT * FROM t WHERE (c LIKE 'a\\%' ESCAPE '\\')"
14
+ @ds.where(@c.escaped_like('?', ['a%'])).sql.must_equal "SELECT * FROM t WHERE (c LIKE 'a\\%' ESCAPE '\\')"
15
+ @ds.where(@c.escaped_like('??', ['a', '%'])).sql.must_equal "SELECT * FROM t WHERE (c LIKE 'a\\%' ESCAPE '\\')"
16
+ end
17
+
18
+ it "escaped_ilike should support creating case insensitive pattern matches" do
19
+ @ds.where(@c.escaped_ilike('?', 'a')).sql.must_equal "SELECT * FROM t WHERE (UPPER(c) LIKE UPPER('a') ESCAPE '\\')"
20
+ @ds.where(@c.escaped_ilike('?%', 'a')).sql.must_equal "SELECT * FROM t WHERE (UPPER(c) LIKE UPPER('a%') ESCAPE '\\')"
21
+ @ds.where(@c.escaped_ilike('?', 'a%')).sql.must_equal "SELECT * FROM t WHERE (UPPER(c) LIKE UPPER('a\\%') ESCAPE '\\')"
22
+ @ds.where(@c.escaped_ilike('?', ['a%'])).sql.must_equal "SELECT * FROM t WHERE (UPPER(c) LIKE UPPER('a\\%') ESCAPE '\\')"
23
+ @ds.where(@c.escaped_ilike('??', ['a', '%'])).sql.must_equal "SELECT * FROM t WHERE (UPPER(c) LIKE UPPER('a\\%') ESCAPE '\\')"
24
+ end
25
+
26
+ it "should raise an Error for a mismatched number of placeholders" do
27
+ proc{@ds.where(@c.escaped_like('?', [])).sql}.must_raise Sequel::Error
28
+ proc{@ds.where(@c.escaped_like('??', ['a'])).sql}.must_raise Sequel::Error
29
+ proc{@ds.where(@c.escaped_ilike('', ['a'])).sql}.must_raise Sequel::Error
30
+ proc{@ds.where(@c.escaped_ilike('?', ['a', 'a'])).sql}.must_raise Sequel::Error
31
+ end
32
+
33
+ it "escaped_like and escaped_ilike should return expressions" do
34
+ @ds.select(@c.escaped_like('?', 'a').as(:b)).sql.must_equal "SELECT (c LIKE 'a' ESCAPE '\\') AS b FROM t"
35
+ @ds.select(@c.escaped_like('?', 'a').cast(String)).sql.must_equal "SELECT CAST((c LIKE 'a' ESCAPE '\\') AS varchar(255)) FROM t"
36
+ @ds.order(@c.escaped_like('?', 'a').desc).sql.must_equal "SELECT * FROM t ORDER BY (c LIKE 'a' ESCAPE '\\') DESC"
37
+ @ds.where(@c.escaped_like('?', 'a') | @c.escaped_like('?', 'b')).sql.must_equal "SELECT * FROM t WHERE ((c LIKE 'a' ESCAPE '\\') OR (c LIKE 'b' ESCAPE '\\'))"
38
+ end
39
+ end
40
+
@@ -62,7 +62,7 @@ describe "eval_inspect extension" do
62
62
  Sequel::SQL::AliasedExpression.new(Time.local(2011, 9, 11, 10, 20, 30, 500000.125), :a),
63
63
  Sequel::SQL::AliasedExpression.new(Time.utc(2011, 9, 11, 10, 20, 30), :a),
64
64
  Sequel::SQL::AliasedExpression.new(Time.utc(2011, 9, 11, 10, 20, 30, 500000.125), :a),
65
- Sequel::SQL::AliasedExpression.new(BigDecimal.new('1.000000000000000000000000000000000000000000000001'), :a),
65
+ Sequel::SQL::AliasedExpression.new(BigDecimal('1.000000000000000000000000000000000000000000000001'), :a),
66
66
  Sequel::SQL::AliasedExpression.new(Sequel::CURRENT_DATE, :a),
67
67
  Sequel::SQL::AliasedExpression.new(Sequel::CURRENT_TIMESTAMP, :a),
68
68
  ].each do |o|
@@ -49,6 +49,12 @@ describe "NestedAttributes plugin" do
49
49
  @db.sqls
50
50
  end
51
51
 
52
+ it "should not modify options hash when loading plugin" do
53
+ h = {}
54
+ @Concert.nested_attributes :albums, h
55
+ h.must_equal({})
56
+ end
57
+
52
58
  it "should support creating new many_to_one objects" do
53
59
  a = @Album.new({:name=>'Al', :artist_attributes=>{:name=>'Ar'}})
54
60
  @db.sqls.must_equal []
@@ -92,30 +92,30 @@ describe "pg_array extension" do
92
92
  it "should parse single dimensional decimal arrays" do
93
93
  c = @converter[1231]
94
94
  c.call("{}").to_a.must_equal []
95
- c.call("{1.5}").to_a.must_equal [BigDecimal.new('1.5')]
96
- c.call('{2.5,3.5}').to_a.must_equal [BigDecimal.new('2.5'), BigDecimal.new('3.5')]
97
- c.call('{3.5,4.5,5.5}').to_a.must_equal [BigDecimal.new('3.5'), BigDecimal.new('4.5'), BigDecimal.new('5.5')]
95
+ c.call("{1.5}").to_a.must_equal [BigDecimal('1.5')]
96
+ c.call('{2.5,3.5}').to_a.must_equal [BigDecimal('2.5'), BigDecimal('3.5')]
97
+ c.call('{3.5,4.5,5.5}').to_a.must_equal [BigDecimal('3.5'), BigDecimal('4.5'), BigDecimal('5.5')]
98
98
  end
99
99
 
100
100
  it "should parse multiple dimensional decimal arrays" do
101
101
  c = @converter[1231]
102
102
  c.call("{{}}").to_a.must_equal [[]]
103
- c.call("{{1.5}}").to_a.must_equal [[BigDecimal.new('1.5')]]
104
- c.call('{{2.5},{3.5}}').to_a.must_equal [[BigDecimal.new('2.5')], [BigDecimal.new('3.5')]]
105
- c.call('{{{1.5,2.5},{3.5,4.5}},{{5.5,6.5},{7.5,8.5}}}').to_a.must_equal [[[BigDecimal.new('1.5'), BigDecimal.new('2.5')], [BigDecimal.new('3.5'), BigDecimal.new('4.5')]], [[BigDecimal.new('5.5'), BigDecimal.new('6.5')], [BigDecimal.new('7.5'), BigDecimal.new('8.5')]]]
103
+ c.call("{{1.5}}").to_a.must_equal [[BigDecimal('1.5')]]
104
+ c.call('{{2.5},{3.5}}').to_a.must_equal [[BigDecimal('2.5')], [BigDecimal('3.5')]]
105
+ c.call('{{{1.5,2.5},{3.5,4.5}},{{5.5,6.5},{7.5,8.5}}}').to_a.must_equal [[[BigDecimal('1.5'), BigDecimal('2.5')], [BigDecimal('3.5'), BigDecimal('4.5')]], [[BigDecimal('5.5'), BigDecimal('6.5')], [BigDecimal('7.5'), BigDecimal('8.5')]]]
106
106
  end
107
107
 
108
108
  it "should parse decimal values with arbitrary precision" do
109
109
  c = @converter[1231]
110
- c.call("{1.000000000000000000005}").to_a.must_equal [BigDecimal.new('1.000000000000000000005')]
111
- c.call("{{1.000000000000000000005,2.000000000000000000005},{3.000000000000000000005,4.000000000000000000005}}").to_a.must_equal [[BigDecimal.new('1.000000000000000000005'), BigDecimal.new('2.000000000000000000005')], [BigDecimal.new('3.000000000000000000005'), BigDecimal.new('4.000000000000000000005')]]
110
+ c.call("{1.000000000000000000005}").to_a.must_equal [BigDecimal('1.000000000000000000005')]
111
+ c.call("{{1.000000000000000000005,2.000000000000000000005},{3.000000000000000000005,4.000000000000000000005}}").to_a.must_equal [[BigDecimal('1.000000000000000000005'), BigDecimal('2.000000000000000000005')], [BigDecimal('3.000000000000000000005'), BigDecimal('4.000000000000000000005')]]
112
112
  end
113
113
 
114
114
  it "should parse integers in decimal arrays as BigDecimals" do
115
115
  c = @converter[1231]
116
116
  c.call("{1}").to_a.first.must_be_kind_of(BigDecimal)
117
- c.call("{1}").to_a.must_equal [BigDecimal.new('1')]
118
- c.call('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.must_equal [[[BigDecimal.new('1'), BigDecimal.new('2')], [BigDecimal.new('3'), BigDecimal.new('4')]], [[BigDecimal.new('5'), BigDecimal.new('6')], [BigDecimal.new('7'), BigDecimal.new('8')]]]
117
+ c.call("{1}").to_a.must_equal [BigDecimal('1')]
118
+ c.call('{{{1,2},{3,4}},{{5,6},{7,8}}}').to_a.must_equal [[[BigDecimal('1'), BigDecimal('2')], [BigDecimal('3'), BigDecimal('4')]], [[BigDecimal('5'), BigDecimal('6')], [BigDecimal('7'), BigDecimal('8')]]]
119
119
  end
120
120
 
121
121
  it "should parse arrays with NULL values" do
@@ -149,7 +149,7 @@ describe "pg_array extension" do
149
149
  @db.literal(@m::PGArray.new([nil])).must_equal 'ARRAY[NULL]'
150
150
  @db.literal(@m::PGArray.new([nil, 1])).must_equal 'ARRAY[NULL,1]'
151
151
  @db.literal(@m::PGArray.new([1.0, 2.5])).must_equal 'ARRAY[1.0,2.5]'
152
- @db.literal(@m::PGArray.new([BigDecimal.new('1'), BigDecimal.new('2.000000000000000000005')])).must_equal 'ARRAY[1.0,2.000000000000000000005]'
152
+ @db.literal(@m::PGArray.new([BigDecimal('1'), BigDecimal('2.000000000000000000005')])).must_equal 'ARRAY[1.0,2.000000000000000000005]'
153
153
  @db.literal(@m::PGArray.new([nil, "NULL"])).must_equal "ARRAY[NULL,'NULL']"
154
154
  @db.literal(@m::PGArray.new([nil, "{},[]'\""])).must_equal "ARRAY[NULL,'{},[]''\"']"
155
155
  end
@@ -169,7 +169,7 @@ describe "pg_array extension" do
169
169
  @db.literal(@m::PGArray.new([nil], :text)).must_equal 'ARRAY[NULL]::text[]'
170
170
  @db.literal(@m::PGArray.new([nil, 1], :int8)).must_equal 'ARRAY[NULL,1]::int8[]'
171
171
  @db.literal(@m::PGArray.new([1.0, 2.5], :real)).must_equal 'ARRAY[1.0,2.5]::real[]'
172
- @db.literal(@m::PGArray.new([BigDecimal.new('1'), BigDecimal.new('2.000000000000000000005')], :decimal)).must_equal 'ARRAY[1.0,2.000000000000000000005]::decimal[]'
172
+ @db.literal(@m::PGArray.new([BigDecimal('1'), BigDecimal('2.000000000000000000005')], :decimal)).must_equal 'ARRAY[1.0,2.000000000000000000005]::decimal[]'
173
173
  @db.literal(@m::PGArray.new([nil, "NULL"], :varchar)).must_equal "ARRAY[NULL,'NULL']::varchar[]"
174
174
  @db.literal(@m::PGArray.new([nil, "{},[]'\""], :"varchar(255)")).must_equal "ARRAY[NULL,'{},[]''\"']::varchar(255)[]"
175
175
  end
@@ -224,7 +224,7 @@ describe "pg_array extension" do
224
224
  {
225
225
  :integer=>{:class=>Integer, :convert=>['1', 1, '1']},
226
226
  :float=>{:db_type=>'double precision', :class=>Float, :convert=>['1.1', 1.1, '1.1']},
227
- :decimal=>{:db_type=>'numeric', :class=>BigDecimal, :convert=>['1.00000000000000000000000001', BigDecimal.new('1.00000000000000000000000001'), '1.00000000000000000000000001']},
227
+ :decimal=>{:db_type=>'numeric', :class=>BigDecimal, :convert=>['1.00000000000000000000000001', BigDecimal('1.00000000000000000000000001'), '1.00000000000000000000000001']},
228
228
  :string=>{:db_type=>'text', :class=>String, :convert=>[1, '1', "'1'"]},
229
229
  :bigint=>{:class=>Integer, :convert=>['1', 1, '1']},
230
230
  :boolean=>{:class=>TrueClass, :convert=>['t', true, 'true']},
@@ -12,7 +12,6 @@ describe "pg_auto_constraint_validations plugin" do
12
12
 
13
13
  before do
14
14
  info = @info = {:schema=>'public', :table=>'items'}
15
- error = @error = []
16
15
  @db = Sequel.mock(:host=>'postgres')
17
16
  def @db.schema(*) [[:i, {}], [:id, {}]] end
18
17
  @set_error = lambda{|ec, ei| @db.fetch = @db.autoid = @db.numrows = ec; info.merge!(ei)}
@@ -43,7 +43,7 @@ describe "pg_range extension" do
43
43
  @db.literal(DateTime.new(2011, 1, 2, 10, 20, 30)...DateTime.new(2011, 2, 3, 10, 20, 30)).must_equal "'[2011-01-02 10:20:30,2011-02-03 10:20:30)'"
44
44
  @db.literal(1..2).must_equal "'[1,2]'"
45
45
  @db.literal(1.0..2.0).must_equal "'[1.0,2.0]'"
46
- @db.literal(BigDecimal.new('1.0')..BigDecimal.new('2.0')).must_equal "'[1.0,2.0]'"
46
+ @db.literal(BigDecimal('1.0')..BigDecimal('2.0')).must_equal "'[1.0,2.0]'"
47
47
  @db.literal(Sequel.lit('a')..Sequel.lit('z')).must_equal "'[a,z]'"
48
48
  @db.literal(''..'()[]",\\2').must_equal "'[\"\",\\(\\)\\[\\]\\\"\\,\\\\2]'"
49
49
  end
@@ -673,8 +673,8 @@ END_MIG
673
673
  s
674
674
  end
675
675
  e = RUBY_VERSION >= '2.4' ? 'e' : 'E'
676
- @d.dump_table_schema(:t4).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal "create_table(:t4) do\n TrueClass :c1, :default=>false\n String :c2, :default=>\"blah\"\n Integer :c3, :default=>-1\n Float :c4, :default=>1.0\n BigDecimal :c5, :default=>BigDecimal.new(\"0.1005#{e}3\")\n File :c6, :default=>Sequel::SQL::Blob.new(\"blah\")\n Date :c7, :default=>Date.new(2008, 10, 29)\n DateTime :c8, :default=>DateTime.parse(\"2008-10-29T10:20:30.0\")\n Time :c9, :default=>Sequel::SQLTime.parse(\"10:20:30.0\"), :only_time=>true\n String :c10\n Date :c11, :default=>Sequel::CURRENT_DATE\n DateTime :c12, :default=>Sequel::CURRENT_TIMESTAMP\nend"
677
- @d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal "create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>BigDecimal.new(\"0.1005#{e}3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.new(2008, 10, 29)\n column :c8, \"datetime\", :default=>DateTime.parse(\"2008-10-29T10:20:30.0\")\n column :c9, \"time\", :default=>Sequel::SQLTime.parse(\"10:20:30.0\")\n column :c10, \"foo\", :default=>Sequel::LiteralString.new(\"'6 weeks'\")\n column :c11, \"date\", :default=>Sequel::CURRENT_DATE\n column :c12, \"timestamp\", :default=>Sequel::CURRENT_TIMESTAMP\nend"
676
+ @d.dump_table_schema(:t4).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal "create_table(:t4) do\n TrueClass :c1, :default=>false\n String :c2, :default=>\"blah\"\n Integer :c3, :default=>-1\n Float :c4, :default=>1.0\n BigDecimal :c5, :default=>BigDecimal(\"0.1005#{e}3\")\n File :c6, :default=>Sequel::SQL::Blob.new(\"blah\")\n Date :c7, :default=>Date.new(2008, 10, 29)\n DateTime :c8, :default=>DateTime.parse(\"2008-10-29T10:20:30.0\")\n Time :c9, :default=>Sequel::SQLTime.parse(\"10:20:30.0\"), :only_time=>true\n String :c10\n Date :c11, :default=>Sequel::CURRENT_DATE\n DateTime :c12, :default=>Sequel::CURRENT_TIMESTAMP\nend"
677
+ @d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal "create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>BigDecimal(\"0.1005#{e}3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.new(2008, 10, 29)\n column :c8, \"datetime\", :default=>DateTime.parse(\"2008-10-29T10:20:30.0\")\n column :c9, \"time\", :default=>Sequel::SQLTime.parse(\"10:20:30.0\")\n column :c10, \"foo\", :default=>Sequel::LiteralString.new(\"'6 weeks'\")\n column :c11, \"date\", :default=>Sequel::CURRENT_DATE\n column :c12, \"timestamp\", :default=>Sequel::CURRENT_TIMESTAMP\nend"
678
678
  end
679
679
 
680
680
  it "should not use a literal string as a fallback if using MySQL with the :same_db option" do
@@ -24,7 +24,7 @@ describe "Sequel sql_expr extension" do
24
24
  end
25
25
 
26
26
  it "Numeric#sql_expr should wrap the object in a NumericExpression" do
27
- [1, 2.0, 2^70, BigDecimal.new('1.0')].each do |o|
27
+ [1, 2.0, 2^70, BigDecimal('1.0')].each do |o|
28
28
  @ds.literal(o.sql_expr).must_equal @ds.literal(o)
29
29
  @ds.literal(o.sql_expr + 1).must_equal "(#{@ds.literal(o)} + 1)"
30
30
  end
@@ -79,7 +79,7 @@ describe "string_agg extension" do
79
79
  it "should handle operations on object" do
80
80
  ds = dbf.call(:postgres).dataset.with_quote_identifiers(false)
81
81
  ds.literal(@sa1 + 'b').must_equal "(string_agg(c, ',') || 'b')"
82
- ds.literal(@sa1.like('b')).must_equal "(string_agg(c, ',') LIKE 'b' ESCAPE '\\')"
82
+ ds.literal(@sa1.like('b')).must_equal "(string_agg(c, ',') LIKE 'b')"
83
83
  ds.literal(@sa1 < 'b').must_equal "(string_agg(c, ',') < 'b')"
84
84
  ds.literal(@sa1.as(:b)).must_equal "string_agg(c, ',') AS b"
85
85
  ds.literal(@sa1.cast(:b)).must_equal "CAST(string_agg(c, ',') AS b)"
@@ -63,9 +63,9 @@ describe "Sequel::Plugins::Timestamps" do
63
63
  it "should work with current_datetime_timestamp extension" do
64
64
  Sequel.datetime_class = Time
65
65
  @c.dataset = @c.dataset.extension(:current_datetime_timestamp)
66
- o = @c.create
66
+ @c.create
67
67
  @c.db.sqls.must_equal ["INSERT INTO t (created_at) VALUES (CURRENT_TIMESTAMP)"]
68
- o = @c.load(:id=>1).save
68
+ @c.load(:id=>1).save
69
69
  @c.db.sqls.must_equal ["UPDATE t SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)"]
70
70
  end
71
71
 
@@ -293,7 +293,7 @@ describe "Sequel::Plugins::ValidationHelpers" do
293
293
  @m.must_be :valid?
294
294
  @m.value = 1.0
295
295
  @m.must_be :valid?
296
- @m.value = BigDecimal.new('1.0')
296
+ @m.value = BigDecimal('1.0')
297
297
  @m.wont_be :valid?
298
298
  @m.errors.full_messages.must_equal ['value is not a valid integer or float']
299
299
  end
@@ -2059,6 +2059,18 @@ describe "Sequel::Model Simple Associations" do
2059
2059
  artist.albums.first.tags.must_equal [tag2]
2060
2060
  end
2061
2061
 
2062
+ it "should not produce duplicates when eager graphing many_to_one=>one_to_many association" do
2063
+ @pr.call
2064
+ @album.update(:artist => @artist)
2065
+ album2 = Album.last
2066
+ album2.update(:artist => @artist)
2067
+
2068
+ a = Album.eager_graph(:artist=>:albums).order{[albums[:id], albums_0[:id]]}.all
2069
+ a.must_equal [@album, album2]
2070
+ a.map(&:artist).must_equal [@artist, @artist]
2071
+ a.map(&:artist).map(&:albums).must_equal [[@album, album2], [@album, album2]]
2072
+ end
2073
+
2062
2074
  it "should have remove method raise an error for one_to_many records if the object isn't already associated" do
2063
2075
  proc{@artist.remove_album(@album.id)}.must_raise(Sequel::Error)
2064
2076
  proc{@artist.remove_album(@album)}.must_raise(Sequel::Error)
@@ -1698,6 +1698,27 @@ describe "Dataset string methods" do
1698
1698
  @ds.filter(Sequel.expr(:b).ilike(@ds.escape_like('[Bar%]'))).select_order_map(:b).must_equal ['[bar%]']
1699
1699
  @ds.filter(Sequel.expr(:b).ilike("#{@ds.escape_like('Bar%')}_")).select_order_map(:b).must_equal ['bar%.']
1700
1700
  @ds.filter(Sequel.expr(:b).ilike("#{@ds.escape_like('Bar%')}%")).select_order_map(:b).must_equal ['bar%', 'bar%.', 'bar%..']
1701
+
1702
+ Sequel.extension(:escaped_like)
1703
+ @ds.filter(Sequel.expr(:a).escaped_like('?', 'Foo_')).select_order_map(:a).must_equal []
1704
+ @ds.filter(Sequel.expr(:a).escaped_like('?', 'foo_')).select_order_map(:a).must_equal ['foo_']
1705
+ @ds.filter(Sequel.expr(:b).escaped_like('?', ['bar%'])).select_order_map(:b).must_equal ['bar%']
1706
+ @ds.filter(Sequel.expr(:a).escaped_like('??', ['fo', 'o\\_'])).select_order_map(:a).must_equal ['foo\\_']
1707
+ @ds.filter(Sequel.expr(:b).escaped_like('?', 'bar\\%')).select_order_map(:b).must_equal ['bar\\%']
1708
+ @ds.filter(Sequel.expr(:a).escaped_like('?', '[f#*?oo_]')).select_order_map(:a).must_equal ['[f#*?oo_]']
1709
+ @ds.filter(Sequel.expr(:b).escaped_like('?', '[bar%]')).select_order_map(:b).must_equal ['[bar%]']
1710
+ @ds.filter(Sequel.expr(:b).escaped_like('?_', 'bar%')).select_order_map(:b).must_equal ['bar%.']
1711
+ @ds.filter(Sequel.expr(:b).escaped_like('?%', 'bar%')).select_order_map(:b).must_equal ['bar%', 'bar%.', 'bar%..']
1712
+
1713
+ @ds.filter(Sequel.expr(:a).escaped_ilike('?', 'Foo_')).select_order_map(:a).must_equal ['foo_']
1714
+ @ds.filter(Sequel.expr(:a).escaped_ilike('?', 'Foo_')).select_order_map(:a).must_equal ['foo_']
1715
+ @ds.filter(Sequel.expr(:b).escaped_ilike('?', ['Bar%'])).select_order_map(:b).must_equal ['bar%']
1716
+ @ds.filter(Sequel.expr(:a).escaped_ilike('??', ['Fo', 'o\\_'])).select_order_map(:a).must_equal ['foo\\_']
1717
+ @ds.filter(Sequel.expr(:b).escaped_ilike('?', 'Bar\\%')).select_order_map(:b).must_equal ['bar\\%']
1718
+ @ds.filter(Sequel.expr(:a).escaped_ilike('?', '[F#*?oo_]')).select_order_map(:a).must_equal ['[f#*?oo_]']
1719
+ @ds.filter(Sequel.expr(:b).escaped_ilike('?', '[Bar%]')).select_order_map(:b).must_equal ['[bar%]']
1720
+ @ds.filter(Sequel.expr(:b).escaped_ilike('?_', 'Bar%')).select_order_map(:b).must_equal ['bar%.']
1721
+ @ds.filter(Sequel.expr(:b).escaped_ilike('?%', 'Bar%')).select_order_map(:b).must_equal ['bar%', 'bar%.', 'bar%..']
1701
1722
  end
1702
1723
 
1703
1724
  if DB.dataset.supports_regexp?
@@ -45,11 +45,11 @@ describe "Supported types" do
45
45
 
46
46
  cspecify "should support generic numeric type", [:odbc, :mssql] do
47
47
  ds = create_items_table_with_column(:number, Numeric, :size=>[15, 10])
48
- ds.insert(:number => BigDecimal.new('2.123456789'))
49
- ds.all.must_equal [{:number=>BigDecimal.new('2.123456789')}]
48
+ ds.insert(:number => BigDecimal('2.123456789'))
49
+ ds.all.must_equal [{:number=>BigDecimal('2.123456789')}]
50
50
  ds = create_items_table_with_column(:number, BigDecimal, :size=>[15, 10])
51
- ds.insert(:number => BigDecimal.new('2.123456789'))
52
- ds.all.must_equal [{:number=>BigDecimal.new('2.123456789')}]
51
+ ds.insert(:number => BigDecimal('2.123456789'))
52
+ ds.all.must_equal [{:number=>BigDecimal('2.123456789')}]
53
53
  end
54
54
 
55
55
  it "should support generic string type" do
@@ -100,6 +100,15 @@ describe Sequel::Model, "dataset" do
100
100
  end
101
101
  end
102
102
 
103
+ describe Sequel::Model, "has_dataset?" do
104
+ it "should return whether the model has a dataset" do
105
+ c = Class.new(Sequel::Model)
106
+ c.has_dataset?.must_equal false
107
+ c.dataset = c.db[:table]
108
+ c.has_dataset?.must_equal true
109
+ end
110
+ end
111
+
103
112
  describe Sequel::Model, "implicit table names" do
104
113
  after do
105
114
  Object.send(:remove_const, :BlahBlah)
@@ -2168,6 +2168,21 @@ describe Sequel::Model, "#eager_graph" do
2168
2168
  a.al_genre.must_equal GraphGenre.load(:id=>12)
2169
2169
  end
2170
2170
 
2171
+ it "should not include duplicate objects when eager graphing many_to_one=>one_to_many" do
2172
+ ds = GraphAlbum.eager_graph(:band=>:albums)
2173
+ ds.sql.must_equal "SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, albums_0.id AS albums_0_id, albums_0.band_id AS albums_0_band_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.band_id = band.id)"
2174
+ a = ds.with_fetch([
2175
+ {:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>1, :albums_0_band_id=>2},
2176
+ {:id=>2, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>1, :albums_0_band_id=>2},
2177
+ {:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>2, :albums_0_band_id=>2},
2178
+ {:id=>2, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>2, :albums_0_band_id=>2}
2179
+ ]).all
2180
+ albums = [GraphAlbum.load(:id => 1, :band_id => 2), GraphAlbum.load(:id => 2, :band_id => 2)]
2181
+ a.must_equal albums
2182
+ a.map(&:band).must_equal [GraphBand.load(:id=>2, :vocalist_id=>1), GraphBand.load(:id=>2, :vocalist_id=>1)]
2183
+ a.map(&:band).map(&:albums).must_equal [albums, albums]
2184
+ end
2185
+
2171
2186
  it "should eagerly load a many_to_one association with a custom callback" do
2172
2187
  ds = GraphAlbum.eager_graph(:band => proc {|ds1| ds1.select(:id).columns(:id)})
2173
2188
  ds.sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0 FROM albums LEFT OUTER JOIN (SELECT id FROM bands) AS band ON (band.id = albums.band_id)'
@@ -2229,6 +2244,16 @@ describe Sequel::Model, "#eager_graph" do
2229
2244
  a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
2230
2245
  a.album.tracks.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2231
2246
  end
2247
+
2248
+ it "should have frozen internal data structures" do
2249
+ ds = GraphAlbum.eager_graph(:band)
2250
+ ds.opts[:eager_graph].must_be :frozen?
2251
+ ds.opts[:eager_graph].each_value{|v| v.must_be :frozen? if v.is_a?(Hash)}
2252
+
2253
+ ds = ds.eager_graph(:tracks)
2254
+ ds.opts[:eager_graph].must_be :frozen?
2255
+ ds.opts[:eager_graph].each_value{|v| v.must_be :frozen? if v.is_a?(Hash)}
2256
+ end
2232
2257
  end
2233
2258
 
2234
2259
  describe "Sequel::Models with double underscores in table names" do
@@ -1835,7 +1835,7 @@ describe Sequel::Model, "typecasting" do
1835
1835
  it "should convert to BigDecimal for a decimal field" do
1836
1836
  @c.db_schema = {:x=>{:type=>:decimal}}
1837
1837
  m = @c.new
1838
- bd = BigDecimal.new('1.0')
1838
+ bd = BigDecimal('1.0')
1839
1839
  m.x = '1.0'
1840
1840
  m.x.must_equal bd
1841
1841
  m.x = 1.0
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.8.0
4
+ version: 5.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-01 00:00:00.000000000 Z
11
+ date: 2018-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -192,6 +192,7 @@ extra_rdoc_files:
192
192
  - doc/release_notes/5.4.0.txt
193
193
  - doc/release_notes/5.8.0.txt
194
194
  - doc/release_notes/5.7.0.txt
195
+ - doc/release_notes/5.9.0.txt
195
196
  files:
196
197
  - CHANGELOG
197
198
  - MIT-LICENSE
@@ -278,6 +279,7 @@ files:
278
279
  - doc/release_notes/5.6.0.txt
279
280
  - doc/release_notes/5.7.0.txt
280
281
  - doc/release_notes/5.8.0.txt
282
+ - doc/release_notes/5.9.0.txt
281
283
  - doc/schema_modification.rdoc
282
284
  - doc/security.rdoc
283
285
  - doc/sharding.rdoc
@@ -385,6 +387,7 @@ files:
385
387
  - lib/sequel/extensions/duplicate_columns_handler.rb
386
388
  - lib/sequel/extensions/empty_array_consider_nulls.rb
387
389
  - lib/sequel/extensions/error_sql.rb
390
+ - lib/sequel/extensions/escaped_like.rb
388
391
  - lib/sequel/extensions/eval_inspect.rb
389
392
  - lib/sequel/extensions/freeze_datasets.rb
390
393
  - lib/sequel/extensions/from_block.rb
@@ -596,6 +599,7 @@ files:
596
599
  - spec/extensions/empty_array_consider_nulls_spec.rb
597
600
  - spec/extensions/error_splitter_spec.rb
598
601
  - spec/extensions/error_sql_spec.rb
602
+ - spec/extensions/escaped_like_spec.rb
599
603
  - spec/extensions/eval_inspect_spec.rb
600
604
  - spec/extensions/finder_spec.rb
601
605
  - spec/extensions/force_encoding_spec.rb