sequel 4.3.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
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