sequel 4.3.0 → 4.4.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +34 -0
  3. data/README.rdoc +7 -7
  4. data/Rakefile +2 -2
  5. data/doc/active_record.rdoc +2 -2
  6. data/doc/association_basics.rdoc +21 -7
  7. data/doc/bin_sequel.rdoc +2 -2
  8. data/doc/cheat_sheet.rdoc +2 -1
  9. data/doc/dataset_basics.rdoc +1 -1
  10. data/doc/dataset_filtering.rdoc +1 -1
  11. data/doc/migration.rdoc +2 -2
  12. data/doc/object_model.rdoc +2 -2
  13. data/doc/opening_databases.rdoc +13 -1
  14. data/doc/querying.rdoc +9 -4
  15. data/doc/release_notes/4.4.0.txt +92 -0
  16. data/doc/schema_modification.rdoc +1 -1
  17. data/doc/security.rdoc +2 -2
  18. data/doc/sql.rdoc +3 -3
  19. data/doc/thread_safety.rdoc +1 -1
  20. data/doc/validations.rdoc +1 -1
  21. data/doc/virtual_rows.rdoc +1 -1
  22. data/lib/sequel/adapters/jdbc.rb +85 -19
  23. data/lib/sequel/adapters/jdbc/db2.rb +1 -1
  24. data/lib/sequel/adapters/jdbc/derby.rb +1 -1
  25. data/lib/sequel/adapters/jdbc/h2.rb +2 -2
  26. data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
  27. data/lib/sequel/adapters/jdbc/jtds.rb +1 -1
  28. data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
  29. data/lib/sequel/adapters/jdbc/postgresql.rb +34 -3
  30. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +57 -0
  31. data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
  32. data/lib/sequel/adapters/oracle.rb +1 -1
  33. data/lib/sequel/adapters/shared/db2.rb +5 -0
  34. data/lib/sequel/adapters/shared/oracle.rb +41 -4
  35. data/lib/sequel/adapters/shared/sqlanywhere.rb +458 -0
  36. data/lib/sequel/adapters/sqlanywhere.rb +177 -0
  37. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +11 -3
  38. data/lib/sequel/core.rb +4 -4
  39. data/lib/sequel/database/connecting.rb +1 -1
  40. data/lib/sequel/database/query.rb +1 -1
  41. data/lib/sequel/database/schema_generator.rb +1 -1
  42. data/lib/sequel/database/schema_methods.rb +2 -2
  43. data/lib/sequel/dataset.rb +1 -1
  44. data/lib/sequel/dataset/actions.rb +2 -0
  45. data/lib/sequel/dataset/graph.rb +1 -1
  46. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  47. data/lib/sequel/dataset/query.rb +37 -16
  48. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  49. data/lib/sequel/extensions/date_arithmetic.rb +2 -2
  50. data/lib/sequel/extensions/migration.rb +1 -1
  51. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +5 -4
  52. data/lib/sequel/extensions/pg_array.rb +2 -2
  53. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  54. data/lib/sequel/extensions/pg_hstore.rb +2 -2
  55. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
  56. data/lib/sequel/extensions/pg_json.rb +2 -2
  57. data/lib/sequel/extensions/pg_json_ops.rb +2 -2
  58. data/lib/sequel/extensions/pg_range.rb +2 -2
  59. data/lib/sequel/extensions/pg_range_ops.rb +2 -2
  60. data/lib/sequel/extensions/pg_row.rb +2 -2
  61. data/lib/sequel/extensions/pg_row_ops.rb +3 -3
  62. data/lib/sequel/model.rb +1 -1
  63. data/lib/sequel/model/associations.rb +106 -17
  64. data/lib/sequel/model/base.rb +23 -19
  65. data/lib/sequel/plugins/json_serializer.rb +1 -1
  66. data/lib/sequel/plugins/many_through_many.rb +14 -6
  67. data/lib/sequel/plugins/pg_array_associations.rb +28 -0
  68. data/lib/sequel/plugins/rcte_tree.rb +1 -1
  69. data/lib/sequel/plugins/serialization.rb +11 -0
  70. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  71. data/lib/sequel/plugins/table_select.rb +41 -0
  72. data/lib/sequel/plugins/tree.rb +1 -1
  73. data/lib/sequel/sql.rb +2 -2
  74. data/lib/sequel/version.rb +1 -1
  75. data/spec/adapters/oracle_spec.rb +22 -1
  76. data/spec/adapters/postgres_spec.rb +31 -48
  77. data/spec/adapters/sqlanywhere_spec.rb +170 -0
  78. data/spec/core/dataset_spec.rb +109 -0
  79. data/spec/core/object_graph_spec.rb +7 -0
  80. data/spec/extensions/constraint_validations_spec.rb +7 -0
  81. data/spec/extensions/core_refinements_spec.rb +1 -1
  82. data/spec/extensions/many_through_many_spec.rb +65 -0
  83. data/spec/extensions/pg_array_associations_spec.rb +44 -0
  84. data/spec/extensions/rcte_tree_spec.rb +3 -3
  85. data/spec/extensions/spec_helper.rb +1 -1
  86. data/spec/extensions/table_select_spec.rb +71 -0
  87. data/spec/integration/associations_test.rb +279 -7
  88. data/spec/integration/dataset_test.rb +13 -4
  89. data/spec/integration/schema_test.rb +12 -14
  90. data/spec/model/associations_spec.rb +472 -3
  91. data/spec/model/class_dataset_methods_spec.rb +1 -0
  92. data/spec/model/model_spec.rb +10 -0
  93. metadata +10 -2
@@ -293,7 +293,7 @@ module Sequel
293
293
 
294
294
  module DatasetMethods
295
295
  # Return a JSON string representing an array of all objects in
296
- # this dataset. Takes the same options as the the instance
296
+ # this dataset. Takes the same options as the instance
297
297
  # method, and passes them to every instance. Additionally,
298
298
  # respects the following options:
299
299
  #
@@ -138,6 +138,13 @@ module Sequel
138
138
  h.each{|k, v| cached_set(k, v)}
139
139
  h
140
140
  end
141
+
142
+ def filter_by_associations_add_conditions_dataset_filter(ds)
143
+ reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias], :qualify=>:deep)}
144
+ ft = final_reverse_edge
145
+ ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])), :table_alias=>ft[:alias], :qualify=>:deep).
146
+ select(*qualify(ft[:alias], Array(self[:left_key])))
147
+ end
141
148
  end
142
149
 
143
150
  module ClassMethods
@@ -275,13 +282,14 @@ module Sequel
275
282
  ref.right_primary_key_methods
276
283
  end
277
284
 
278
- exp = association_filter_key_expression(ref.qualify(last_alias, Array(ref.final_edge[:left])), meths, obj)
279
- if exp == SQL::Constants::FALSE
280
- association_filter_handle_inversion(op, exp, Array(lpks))
281
- else
282
- ds = ds.where(exp).exclude(SQL::BooleanExpression.from_value_pairs(ds.opts[:select].zip([]), :OR))
283
- association_filter_handle_inversion(op, SQL::BooleanExpression.from_value_pairs(lpks=>ds), Array(lpks))
285
+ expr = association_filter_key_expression(ref.qualify(last_alias, Array(ref.final_edge[:left])), meths, obj)
286
+ unless expr == SQL::Constants::FALSE
287
+ ds = ds.where(expr).exclude(SQL::BooleanExpression.from_value_pairs(ds.opts[:select].zip([]), :OR))
288
+ expr = SQL::BooleanExpression.from_value_pairs(lpks=>ds)
289
+ expr = add_association_filter_conditions(ref, obj, expr)
284
290
  end
291
+
292
+ association_filter_handle_inversion(op, expr, Array(lpks))
285
293
  end
286
294
  end
287
295
  end
@@ -67,6 +67,9 @@ module Sequel
67
67
  # This plugin should work on all supported PostgreSQL versions, except
68
68
  # the remove_all modification method for many_to_pg_array associations, which
69
69
  # requires the array_remove method added in PostgreSQL 9.3.
70
+ #
71
+ # This plugin requires that the underlying database have the pg_array
72
+ # extension loaded.
70
73
  module PgArrayAssociations
71
74
  # The AssociationReflection subclass for many_to_pg_array associations.
72
75
  class ManyToPgArrayAssociationReflection < Sequel::Model::Associations::AssociationReflection
@@ -109,6 +112,15 @@ module Sequel
109
112
 
110
113
  private
111
114
 
115
+ def filter_by_associations_add_conditions_dataset_filter(ds)
116
+ key = qualify(associated_class.table_name, self[:key])
117
+ ds.select{unnest(key)}.exclude(key=>nil)
118
+ end
119
+
120
+ def filter_by_associations_conditions_key
121
+ qualify(self[:model].table_name, primary_key)
122
+ end
123
+
112
124
  # Only consider an association as a reciprocal if it has matching keys
113
125
  # and primary keys.
114
126
  def reciprocal_association?(assoc_reflect)
@@ -162,8 +174,22 @@ module Sequel
162
174
  cached_fetch(:primary_key_method){primary_key}
163
175
  end
164
176
 
177
+ def filter_by_associations_conditions_expression(obj)
178
+ ds = filter_by_associations_conditions_dataset.where(filter_by_associations_conditions_subquery_conditions(obj))
179
+ Sequel.function(:coalesce, Sequel.pg_array(filter_by_associations_conditions_key).overlaps(ds), Sequel::SQL::Constants::FALSE)
180
+ end
181
+
165
182
  private
166
183
 
184
+ def filter_by_associations_add_conditions_dataset_filter(ds)
185
+ pk = qualify(associated_class.table_name, primary_key)
186
+ ds.select{array_agg(pk)}.exclude(pk=>nil)
187
+ end
188
+
189
+ def filter_by_associations_conditions_key
190
+ qualify(self[:model].table_name, self[:key])
191
+ end
192
+
167
193
  # Only consider an association as a reciprocal if it has matching keys
168
194
  # and primary keys.
169
195
  def reciprocal_association?(assoc_reflect)
@@ -426,6 +452,7 @@ module Sequel
426
452
  Sequel.expr(pk=>obj.select{Sequel.pg_array_op(ref.qualify(obj.model.table_name, ref[:key_column])).unnest})
427
453
  end
428
454
  expr = Sequel::SQL::Constants::FALSE unless expr
455
+ expr = add_association_filter_conditions(ref, obj, expr)
429
456
  association_filter_handle_inversion(op, expr, [pk])
430
457
  end
431
458
 
@@ -445,6 +472,7 @@ module Sequel
445
472
  Sequel.function(:coalesce, Sequel.pg_array_op(key).overlaps(obj.select{array_agg(ref.qualify(obj.model.table_name, ref.primary_key))}), Sequel::SQL::Constants::FALSE)
446
473
  end
447
474
  expr = Sequel::SQL::Constants::FALSE unless expr
475
+ expr = add_association_filter_conditions(ref, obj, expr)
448
476
  association_filter_handle_inversion(op, expr, [key])
449
477
  end
450
478
  end
@@ -304,7 +304,7 @@ module Sequel
304
304
  level = associations
305
305
  no_cache_level = level - 1
306
306
  associations = {}
307
- base_case = base_case.select_more(SQL::AliasedExpression.new(0, la))
307
+ base_case = base_case.select_more(SQL::AliasedExpression.new(Sequel.cast(0, Integer), la))
308
308
  recursive_case = recursive_case.select_more(SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(t, la) + 1, la)).filter(SQL::QualifiedIdentifier.new(t, la) < level - 1)
309
309
  end
310
310
  table_alias = model.dataset.schema_and_table(model.table_name)[1].to_sym
@@ -56,6 +56,17 @@ module Sequel
56
56
  # user = User.create
57
57
  # user.permissions = { :global => 'read-only' }
58
58
  # user.save
59
+ #
60
+ # Note that if you mutate serialized column values without reassigning them,
61
+ # those changes won't be picked up by <tt>Model#save_changes</tt> or
62
+ # <tt>Model#update</tt>. Example:
63
+ #
64
+ # user = User[1]
65
+ # user.permissions[:global] = 'foo'
66
+ # user.save_changes # Will not pick up changes to permissions
67
+ #
68
+ # You can use the +serialization_modification_detection+ plugin to pick
69
+ # up such changes.
59
70
  module Serialization
60
71
  # The default serializers supported by the serialization module.
61
72
  # Use register_format to add serializers to this hash.
@@ -126,7 +126,7 @@ module Sequel
126
126
  attr_reader :sti_key_array
127
127
 
128
128
  # A hash/proc with class keys and column value values, mapping
129
- # the the class to a particular value given to the sti_key column.
129
+ # the class to a particular value given to the sti_key column.
130
130
  # Used to set the column value when creating objects, and for the
131
131
  # filter when retrieving objects in subclasses.
132
132
  attr_reader :sti_key_map
@@ -0,0 +1,41 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The table_select plugin changes the default selection for a
4
+ # model dataset from <tt>*</tt> to <tt>table.*</tt>.
5
+ # This makes it so that if you join the model's dataset to
6
+ # other tables, columns in the other tables do not appear
7
+ # in the result sets (and possibly overwrite columns in the
8
+ # current model with the same name).
9
+ #
10
+ # Usage:
11
+ #
12
+ # # Make all model subclasses select table.*
13
+ # Sequel::Model.plugin :table_select
14
+ #
15
+ # # Make the Album class select albums.*
16
+ # Album.plugin :table_select
17
+ module TableSelect
18
+ # Modify the current model's dataset selection, if the model
19
+ # has a dataset.
20
+ def self.configure(model)
21
+ model.instance_eval do
22
+ self.dataset = dataset if @dataset
23
+ end
24
+ end
25
+
26
+ module ClassMethods
27
+ private
28
+
29
+ # If the underlying dataset selects from a single table and
30
+ # has no explicit selection, select table.* from that table.
31
+ def convert_input_dataset(ds)
32
+ ds = super
33
+ if !ds.opts[:select] && (from = ds.opts[:from]) && from.length == 1 && !ds.opts[:join]
34
+ ds = ds.select_all(ds.first_source)
35
+ end
36
+ ds
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -93,7 +93,7 @@ module Sequel
93
93
  # subchild1.ancestors # => [child1, root]
94
94
  def descendants
95
95
  nodes = children.dup
96
- nodes.each{|child| nodes.concat(child.descendants)}
96
+ children.each{|child| nodes.concat(child.descendants)}
97
97
  nodes
98
98
  end
99
99
 
@@ -1477,7 +1477,7 @@ module Sequel
1477
1477
  end
1478
1478
 
1479
1479
  # Create a new +Subscript+ appending the given subscript(s)
1480
- # the the current array of subscripts.
1480
+ # to the current array of subscripts.
1481
1481
  #
1482
1482
  # :a.sql_subscript(2) # a[2]
1483
1483
  # :a.sql_subscript(2) | 1 # a[2, 1]
@@ -1582,7 +1582,7 @@ module Sequel
1582
1582
  # # Literal Strings
1583
1583
  # ds.filter{{a=>`some SQL`}} # SELECT * FROM t WHERE (a = some SQL)
1584
1584
  #
1585
- # For a more detailed explanation, see the {Virtual Rows guide}[link:files/doc/virtual_rows_rdoc.html].
1585
+ # For a more detailed explanation, see the {Virtual Rows guide}[rdoc-ref:doc/virtual_rows.rdoc].
1586
1586
  class VirtualRow < BasicObject
1587
1587
  WILDCARD = LiteralString.new('*').freeze
1588
1588
  QUESTION_MARK = LiteralString.new('?').freeze
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 4
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 3
6
+ MINOR = 4
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
9
  TINY = 0
@@ -21,13 +21,34 @@ describe "An Oracle database" do
21
21
  Integer :id
22
22
  String :cat_name, :size => 50
23
23
  end
24
+
25
+ DB.create_table!(:notes) do
26
+ Integer :id
27
+ String :title, :size => 50
28
+ String :content, :text => true
29
+ end
24
30
  @d = DB[:items]
25
31
  end
26
32
  after do
27
33
  @d.delete
28
34
  end
29
35
  after(:all) do
30
- DB.drop_table?(:items, :books, :categories)
36
+ DB.drop_table?(:items, :books, :categories, :notes)
37
+ end
38
+
39
+ specify "should allow limit and offset with clob columns" do
40
+ notes = []
41
+ notes << {:id => 1, :title => 'abc', :content => 'zyx'}
42
+ notes << {:id => 2, :title => 'def', :content => 'wvu'}
43
+ notes << {:id => 3, :title => 'ghi', :content => 'tsr'}
44
+ notes << {:id => 4, :title => 'jkl', :content => 'qpo'}
45
+ notes << {:id => 5, :title => 'mno', :content => 'nml'}
46
+ DB[:notes].multi_insert(notes)
47
+
48
+ DB[:notes].sort_by{|x| x[:id]}.should == notes
49
+ rows = DB[:notes].limit(3, 0).all
50
+ rows.length.should == 3
51
+ rows.all?{|v| notes.should include(v)}
31
52
  end
32
53
 
33
54
  specify "should provide disconnect functionality" do
@@ -1763,8 +1763,7 @@ describe 'PostgreSQL array handling' do
1763
1763
  @db = DB
1764
1764
  @db.extension :pg_array
1765
1765
  @ds = @db[:items]
1766
- @native = DB.adapter_scheme == :postgres
1767
- @jdbc = DB.adapter_scheme == :jdbc
1766
+ @native = DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
1768
1767
  @tp = lambda{@db.schema(:items).map{|a| a.last[:type]}}
1769
1768
  end
1770
1769
  after do
@@ -1783,10 +1782,8 @@ describe 'PostgreSQL array handling' do
1783
1782
  @ds.insert(Sequel.pg_array([1], :int2), Sequel.pg_array([nil, 2], :int4), Sequel.pg_array([3, nil], :int8), Sequel.pg_array([4, nil, 4.5], :real), Sequel.pg_array([5, nil, 5.5], "double precision"))
1784
1783
  @ds.count.should == 1
1785
1784
  rs = @ds.all
1786
- if @jdbc || @native
1787
- rs.should == [{:i2=>[1], :i4=>[nil, 2], :i8=>[3, nil], :r=>[4.0, nil, 4.5], :dp=>[5.0, nil, 5.5]}]
1788
- end
1789
1785
  if @native
1786
+ rs.should == [{:i2=>[1], :i4=>[nil, 2], :i8=>[3, nil], :r=>[4.0, nil, 4.5], :dp=>[5.0, nil, 5.5]}]
1790
1787
  rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
1791
1788
  rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
1792
1789
  @ds.delete
@@ -1798,10 +1795,8 @@ describe 'PostgreSQL array handling' do
1798
1795
  @ds.insert(Sequel.pg_array([[1], [2]], :int2), Sequel.pg_array([[nil, 2], [3, 4]], :int4), Sequel.pg_array([[3, nil], [nil, nil]], :int8), Sequel.pg_array([[4, nil], [nil, 4.5]], :real), Sequel.pg_array([[5, nil], [nil, 5.5]], "double precision"))
1799
1796
 
1800
1797
  rs = @ds.all
1801
- if @jdbc || @native
1802
- rs.should == [{:i2=>[[1], [2]], :i4=>[[nil, 2], [3, 4]], :i8=>[[3, nil], [nil, nil]], :r=>[[4, nil], [nil, 4.5]], :dp=>[[5, nil], [nil, 5.5]]}]
1803
- end
1804
1798
  if @native
1799
+ rs.should == [{:i2=>[[1], [2]], :i4=>[[nil, 2], [3, 4]], :i8=>[[3, nil], [nil, nil]], :r=>[[4, nil], [nil, 4.5]], :dp=>[[5, nil], [nil, 5.5]]}]
1805
1800
  rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
1806
1801
  rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
1807
1802
  @ds.delete
@@ -1818,10 +1813,8 @@ describe 'PostgreSQL array handling' do
1818
1813
  @ds.insert(Sequel.pg_array([BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')], :numeric))
1819
1814
  @ds.count.should == 1
1820
1815
  rs = @ds.all
1821
- if @jdbc || @native
1822
- rs.should == [{:n=>[BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')]}]
1823
- end
1824
1816
  if @native
1817
+ rs.should == [{:n=>[BigDecimal.new('1.000000000000000000001'), nil, BigDecimal.new('1')]}]
1825
1818
  rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
1826
1819
  rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
1827
1820
  @ds.delete
@@ -1832,10 +1825,8 @@ describe 'PostgreSQL array handling' do
1832
1825
  @ds.delete
1833
1826
  @ds.insert(Sequel.pg_array([[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]], :numeric))
1834
1827
  rs = @ds.all
1835
- if @jdbc || @native
1836
- rs.should == [{:n=>[[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]]}]
1837
- end
1838
1828
  if @native
1829
+ rs.should == [{:n=>[[BigDecimal.new('1.0000000000000000000000000000001'), nil], [nil, BigDecimal.new('1')]]}]
1839
1830
  rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
1840
1831
  rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
1841
1832
  @ds.delete
@@ -1854,10 +1845,8 @@ describe 'PostgreSQL array handling' do
1854
1845
  @ds.insert(Sequel.pg_array(['a', nil, 'NULL', 'b"\'c'], 'char(4)'), Sequel.pg_array(['a', nil, 'NULL', 'b"\'c'], :varchar), Sequel.pg_array(['a', nil, 'NULL', 'b"\'c'], :text))
1855
1846
  @ds.count.should == 1
1856
1847
  rs = @ds.all
1857
- if @jdbc || @native
1858
- rs.should == [{:c=>['a ', nil, 'NULL', 'b"\'c'], :vc=>['a', nil, 'NULL', 'b"\'c'], :t=>['a', nil, 'NULL', 'b"\'c']}]
1859
- end
1860
1848
  if @native
1849
+ rs.should == [{:c=>['a ', nil, 'NULL', 'b"\'c'], :vc=>['a', nil, 'NULL', 'b"\'c'], :t=>['a', nil, 'NULL', 'b"\'c']}]
1861
1850
  rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
1862
1851
  rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
1863
1852
  @ds.delete
@@ -1868,10 +1857,8 @@ describe 'PostgreSQL array handling' do
1868
1857
  @ds.delete
1869
1858
  @ds.insert(Sequel.pg_array([[['a'], [nil]], [['NULL'], ['b"\'c']]], 'char(4)'), Sequel.pg_array([[['a'], ['']], [['NULL'], ['b"\'c']]], :varchar), Sequel.pg_array([[['a'], [nil]], [['NULL'], ['b"\'c']]], :text))
1870
1859
  rs = @ds.all
1871
- if @jdbc || @native
1872
- rs.should == [{:c=>[[['a '], [nil]], [['NULL'], ['b"\'c']]], :vc=>[[['a'], ['']], [['NULL'], ['b"\'c']]], :t=>[[['a'], [nil]], [['NULL'], ['b"\'c']]]}]
1873
- end
1874
1860
  if @native
1861
+ rs.should == [{:c=>[[['a '], [nil]], [['NULL'], ['b"\'c']]], :vc=>[[['a'], ['']], [['NULL'], ['b"\'c']]], :t=>[[['a'], [nil]], [['NULL'], ['b"\'c']]]}]
1875
1862
  rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
1876
1863
  rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
1877
1864
  @ds.delete
@@ -1897,10 +1884,8 @@ describe 'PostgreSQL array handling' do
1897
1884
  @ds.insert(Sequel.pg_array([true, false], :bool), Sequel.pg_array([d, nil], :date), Sequel.pg_array([t, nil], :time), Sequel.pg_array([ts, nil], :timestamp), Sequel.pg_array([ts, nil], :timestamptz))
1898
1885
  @ds.count.should == 1
1899
1886
  rs = @ds.all
1900
- if @jdbc || @native
1901
- rs.should == [{:b=>[true, false], :d=>[d, nil], :t=>[t, nil], :ts=>[ts, nil], :tstz=>[ts, nil]}]
1902
- end
1903
1887
  if @native
1888
+ rs.should == [{:b=>[true, false], :d=>[d, nil], :t=>[t, nil], :ts=>[ts, nil], :tstz=>[ts, nil]}]
1904
1889
  rs.first.values.each{|v| v.should_not be_a_kind_of(Array)}
1905
1890
  rs.first.values.each{|v| v.to_a.should be_a_kind_of(Array)}
1906
1891
  @ds.delete
@@ -1978,7 +1963,7 @@ describe 'PostgreSQL array handling' do
1978
1963
  @ds.insert(rs.first)
1979
1964
  @ds.all.should == rs
1980
1965
  end
1981
- end unless DB.adapter_scheme == :jdbc
1966
+ end
1982
1967
 
1983
1968
  specify 'use arrays in bound variables' do
1984
1969
  @db.create_table!(:items) do
@@ -2137,7 +2122,7 @@ describe 'PostgreSQL hstore handling' do
2137
2122
  @db.extension :pg_array, :pg_hstore
2138
2123
  @ds = @db[:items]
2139
2124
  @h = {'a'=>'b', 'c'=>nil, 'd'=>'NULL', 'e'=>'\\\\" \\\' ,=>'}
2140
- @native = DB.adapter_scheme == :postgres
2125
+ @native = DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
2141
2126
  end
2142
2127
  after do
2143
2128
  @db.drop_table?(:items)
@@ -2152,6 +2137,7 @@ describe 'PostgreSQL hstore handling' do
2152
2137
  if @native
2153
2138
  rs = @ds.all
2154
2139
  v = rs.first[:h]
2140
+ v.should == @h
2155
2141
  v.should_not be_a_kind_of(Hash)
2156
2142
  v.to_hash.should be_a_kind_of(Hash)
2157
2143
  v.to_hash.should == @h
@@ -2387,7 +2373,7 @@ describe 'PostgreSQL json type' do
2387
2373
  @ds = @db[:items]
2388
2374
  @a = [1, 2, {'a'=>'b'}, 3.0]
2389
2375
  @h = {'a'=>'b', '1'=>[3, 4, 5]}
2390
- @native = DB.adapter_scheme == :postgres
2376
+ @native = DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
2391
2377
  end
2392
2378
  after do
2393
2379
  @db.drop_table?(:items)
@@ -2519,7 +2505,7 @@ describe 'PostgreSQL json type' do
2519
2505
  j = Sequel.pg_json([{'a'=>1, 'b'=>'c'}, {'a'=>2, 'b'=>'d'}]).op
2520
2506
  @db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:a).should == [1, 2]
2521
2507
  @db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:b).should == %w'c d'
2522
- end if DB.server_version >= 90300 && DB.adapter_scheme == :postgres
2508
+ end if DB.server_version >= 90300 && (DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc)
2523
2509
  end if DB.server_version >= 90200
2524
2510
 
2525
2511
  describe 'PostgreSQL inet/cidr types' do
@@ -2539,7 +2525,7 @@ describe 'PostgreSQL inet/cidr types' do
2539
2525
  @ipv6 = IPAddr.new(@v6)
2540
2526
  @ipv6nm = IPAddr.new(@v6nm)
2541
2527
  end
2542
- @native = DB.adapter_scheme == :postgres
2528
+ @native = DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
2543
2529
  end
2544
2530
  after do
2545
2531
  @db.drop_table?(:items)
@@ -2650,7 +2636,7 @@ describe 'PostgreSQL range types' do
2650
2636
  @r.each{|k, v| @ra[k] = Sequel.pg_array([v], @map[k])}
2651
2637
  @r.each{|k, v| @pgr[k] = Sequel.pg_range(v)}
2652
2638
  @r.each{|k, v| @pgra[k] = Sequel.pg_array([Sequel.pg_range(v)], @map[k])}
2653
- @native = DB.adapter_scheme == :postgres
2639
+ @native = DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
2654
2640
  end
2655
2641
  after do
2656
2642
  @db.drop_table?(:items)
@@ -2732,14 +2718,12 @@ describe 'PostgreSQL range types' do
2732
2718
  v.delete(:id)
2733
2719
  v.should == @r
2734
2720
 
2735
- unless @db.adapter_scheme == :jdbc
2736
- @db.create_table!(:items){primary_key :id; column :i4, 'int4range[]'; column :i8, 'int8range[]'; column :n, 'numrange[]'; column :d, 'daterange[]'; column :t, 'tsrange[]'; column :tz, 'tstzrange[]'}
2737
- c = Class.new(Sequel::Model(@db[:items]))
2738
- c.plugin :pg_typecast_on_load, :i4, :i8, :n, :d, :t, :tz unless @native
2739
- v = c.create(@ra).values
2740
- v.delete(:id)
2741
- v.each{|k,v1| v1.should == @ra[k].to_a}
2742
- end
2721
+ @db.create_table!(:items){primary_key :id; column :i4, 'int4range[]'; column :i8, 'int8range[]'; column :n, 'numrange[]'; column :d, 'daterange[]'; column :t, 'tsrange[]'; column :tz, 'tstzrange[]'}
2722
+ c = Class.new(Sequel::Model(@db[:items]))
2723
+ c.plugin :pg_typecast_on_load, :i4, :i8, :n, :d, :t, :tz unless @native
2724
+ v = c.create(@ra).values
2725
+ v.delete(:id)
2726
+ v.each{|k,v1| v1.should == @ra[k].to_a}
2743
2727
  end
2744
2728
 
2745
2729
  specify 'operations/functions with pg_range_ops' do
@@ -2817,7 +2801,7 @@ describe 'PostgreSQL interval types' do
2817
2801
  @db = DB
2818
2802
  @db.extension :pg_array, :pg_interval
2819
2803
  @ds = @db[:items]
2820
- @native = DB.adapter_scheme == :postgres
2804
+ @native = DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
2821
2805
  end
2822
2806
  after(:all) do
2823
2807
  Sequel::Postgres::PG_TYPES.delete(1186)
@@ -2829,7 +2813,8 @@ describe 'PostgreSQL interval types' do
2829
2813
  specify 'insert and retrieve interval values' do
2830
2814
  @db.create_table!(:items){interval :i}
2831
2815
  [
2832
- ['0', '00:00:00', 0, [[:seconds, 0]]],
2816
+ ['0', '00:00:00', 0, []],
2817
+ ['1', '00:00:01', 1, [[:seconds, 1]]],
2833
2818
  ['1 microsecond', '00:00:00.000001', 0.000001, [[:seconds, 0.000001]]],
2834
2819
  ['1 millisecond', '00:00:00.001', 0.001, [[:seconds, 0.001]]],
2835
2820
  ['1 second', '00:00:01', 1, [[:seconds, 1]]],
@@ -2853,7 +2838,7 @@ describe 'PostgreSQL interval types' do
2853
2838
  rs = @ds.all
2854
2839
  rs.first[:i].is_a?(ActiveSupport::Duration).should be_true
2855
2840
  rs.first[:i].should == ActiveSupport::Duration.new(value, parts)
2856
- rs.first[:i].parts.sort_by{|k,v| k.to_s}.should == parts.sort_by{|k,v| k.to_s}
2841
+ rs.first[:i].parts.sort_by{|k,v| k.to_s}.reject{|k,v| v == 0}.should == parts.sort_by{|k,v| k.to_s}
2857
2842
  @ds.delete
2858
2843
  @ds.insert(rs.first)
2859
2844
  @ds.all.should == rs
@@ -2935,7 +2920,7 @@ describe 'PostgreSQL row-valued/composite types' do
2935
2920
  @db.register_row_type(Sequel.qualify(:public, :person))
2936
2921
  @db.register_row_type(:public__company)
2937
2922
 
2938
- @native = DB.adapter_scheme == :postgres
2923
+ @native = DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
2939
2924
  end
2940
2925
  after(:all) do
2941
2926
  @db.drop_table?(:company, :person, :address)
@@ -2980,7 +2965,7 @@ describe 'PostgreSQL row-valued/composite types' do
2980
2965
  @db.drop_table(:domain_check)
2981
2966
  @db << "DROP DOMAIN positive_integer"
2982
2967
  end
2983
- end if DB.adapter_scheme == :postgres
2968
+ end if DB.adapter_scheme == :postgres || DB.adapter_scheme == :jdbc
2984
2969
 
2985
2970
  specify 'insert and retrieve arrays of row types' do
2986
2971
  @ds = @db[:company]
@@ -3170,12 +3155,10 @@ describe 'PostgreSQL row-valued/composite types' do
3170
3155
 
3171
3156
  Company.plugin :pg_typecast_on_load, :employees unless @native
3172
3157
  e = Person.new(:id=>1, :address=>a)
3173
- unless @db.adapter_scheme == :jdbc
3174
- o = Company.create(:id=>1, :employees=>[{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}])
3175
- o.employees.should == [e]
3176
- o = Company.create(:id=>1, :employees=>[e])
3177
- o.employees.should == [e]
3178
- end
3158
+ o = Company.create(:id=>1, :employees=>[{:id=>1, :address=>{:street=>'123 Sesame St', :city=>'Somewhere', :zip=>'12345'}}])
3159
+ o.employees.should == [e]
3160
+ o = Company.create(:id=>1, :employees=>[e])
3161
+ o.employees.should == [e]
3179
3162
  end
3180
3163
  end
3181
3164
  end