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
@@ -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