sequel 3.42.0 → 3.43.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/CHANGELOG +40 -0
  2. data/MIT-LICENSE +1 -1
  3. data/Rakefile +1 -1
  4. data/doc/opening_databases.rdoc +2 -2
  5. data/doc/prepared_statements.rdoc +7 -0
  6. data/doc/release_notes/3.43.0.txt +105 -0
  7. data/doc/schema_modification.rdoc +19 -0
  8. data/lib/sequel/adapters/do/mysql.rb +1 -1
  9. data/lib/sequel/adapters/jdbc.rb +13 -8
  10. data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
  11. data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
  12. data/lib/sequel/adapters/jdbc/oracle.rb +6 -0
  13. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -3
  14. data/lib/sequel/adapters/mysql.rb +1 -1
  15. data/lib/sequel/adapters/mysql2.rb +1 -1
  16. data/lib/sequel/adapters/oracle.rb +1 -1
  17. data/lib/sequel/adapters/postgres.rb +4 -2
  18. data/lib/sequel/adapters/shared/db2.rb +12 -0
  19. data/lib/sequel/adapters/shared/mssql.rb +9 -5
  20. data/lib/sequel/adapters/shared/postgres.rb +2 -0
  21. data/lib/sequel/adapters/swift/mysql.rb +1 -1
  22. data/lib/sequel/core.rb +2 -2
  23. data/lib/sequel/database.rb +0 -2
  24. data/lib/sequel/database/query.rb +20 -5
  25. data/lib/sequel/database/schema_generator.rb +5 -0
  26. data/lib/sequel/database/schema_methods.rb +5 -0
  27. data/lib/sequel/dataset.rb +0 -2
  28. data/lib/sequel/dataset/actions.rb +25 -2
  29. data/lib/sequel/dataset/misc.rb +1 -1
  30. data/lib/sequel/dataset/sql.rb +28 -6
  31. data/lib/sequel/extensions/core_refinements.rb +221 -0
  32. data/lib/sequel/extensions/date_arithmetic.rb +194 -0
  33. data/lib/sequel/extensions/meta_def.rb +30 -0
  34. data/lib/sequel/extensions/migration.rb +5 -0
  35. data/lib/sequel/extensions/null_dataset.rb +2 -0
  36. data/lib/sequel/extensions/pagination.rb +2 -0
  37. data/lib/sequel/extensions/pg_array.rb +12 -1
  38. data/lib/sequel/extensions/pg_array_ops.rb +10 -1
  39. data/lib/sequel/extensions/pg_hstore.rb +12 -1
  40. data/lib/sequel/extensions/pg_hstore_ops.rb +10 -1
  41. data/lib/sequel/extensions/pg_json.rb +18 -1
  42. data/lib/sequel/extensions/pg_range.rb +12 -1
  43. data/lib/sequel/extensions/pg_range_ops.rb +10 -1
  44. data/lib/sequel/extensions/pg_row.rb +18 -2
  45. data/lib/sequel/extensions/pg_row_ops.rb +10 -1
  46. data/lib/sequel/extensions/query.rb +2 -0
  47. data/lib/sequel/model/associations.rb +5 -13
  48. data/lib/sequel/model/base.rb +4 -6
  49. data/lib/sequel/plugins/boolean_readers.rb +4 -2
  50. data/lib/sequel/plugins/many_through_many.rb +23 -0
  51. data/lib/sequel/plugins/string_stripper.rb +53 -3
  52. data/lib/sequel/plugins/validation_class_methods.rb +5 -0
  53. data/lib/sequel/sql.rb +3 -3
  54. data/lib/sequel/version.rb +1 -1
  55. data/spec/adapters/db2_spec.rb +19 -8
  56. data/spec/adapters/mssql_spec.rb +1 -2
  57. data/spec/adapters/mysql_spec.rb +2 -2
  58. data/spec/adapters/postgres_spec.rb +29 -3
  59. data/spec/core/dataset_spec.rb +107 -0
  60. data/spec/core/expression_filters_spec.rb +5 -0
  61. data/spec/core/schema_spec.rb +14 -3
  62. data/spec/core/spec_helper.rb +2 -0
  63. data/spec/extensions/core_refinements_spec.rb +551 -0
  64. data/spec/extensions/date_arithmetic_spec.rb +150 -0
  65. data/spec/extensions/force_encoding_spec.rb +1 -1
  66. data/spec/extensions/meta_def_spec.rb +21 -0
  67. data/spec/extensions/spec_helper.rb +5 -0
  68. data/spec/extensions/string_stripper_spec.rb +44 -2
  69. data/spec/integration/associations_test.rb +2 -2
  70. data/spec/integration/plugin_test.rb +90 -0
  71. data/spec/integration/schema_test.rb +1 -1
  72. data/spec/model/association_reflection_spec.rb +4 -4
  73. data/spec/model/associations_spec.rb +2 -2
  74. data/spec/model/base_spec.rb +2 -2
  75. data/spec/model/eager_loading_spec.rb +5 -5
  76. data/spec/model/hooks_spec.rb +4 -4
  77. data/spec/model/model_spec.rb +9 -9
  78. data/spec/model/record_spec.rb +15 -18
  79. metadata +12 -5
  80. data/lib/sequel/metaprogramming.rb +0 -13
@@ -0,0 +1,194 @@
1
+ # The date_arithmetic extension adds the ability to perform database-independent
2
+ # addition/substraction of intervals to/from dates and timestamps.
3
+ #
4
+ # First, you need to load the extension into the database:
5
+ #
6
+ # DB.extension :date_arithmetic
7
+ #
8
+ # Then you can use the Sequel.date_add and Sequel.date_sub methods
9
+ # to return Sequel expressions:
10
+ #
11
+ # add = Sequel.date_add(:date_column, :years=>1, :months=>2, :days=>3)
12
+ # sub = Sequel.date_sub(:date_column, :hours=>1, :minutes=>2, :seconds=>3)
13
+ #
14
+ # In addition to specifying the interval as a hash, there is also
15
+ # support for specifying the interval as an ActiveSupport::Duration
16
+ # object:
17
+ #
18
+ # require 'active_support/all'
19
+ # add = Sequel.date_add(:date_column, 1.years + 2.months + 3.days)
20
+ # sub = Sequel.date_sub(:date_column, 1.hours + 2.minutes + 3.seconds)
21
+ #
22
+ # These expressions can be used in your datasets, or anywhere else that
23
+ # Sequel expressions are allowed:
24
+ #
25
+ # DB[:table].select(add.as(:d)).where(sub > Sequel::CURRENT_TIMESTAMP)
26
+
27
+ module Sequel
28
+ module SQL
29
+ module Builders
30
+ # Return a DateAdd expression, adding an interval to the date/timestamp expr.
31
+ def date_add(expr, interval)
32
+ DateAdd.new(expr, interval)
33
+ end
34
+
35
+ # Return a DateAdd expression, adding the negative of the interval to
36
+ # the date/timestamp expr.
37
+ def date_sub(expr, interval)
38
+ interval = if interval.is_a?(Hash)
39
+ h = {}
40
+ interval.each{|k,v| h[k] = -v unless v.nil?}
41
+ h
42
+ else
43
+ -interval
44
+ end
45
+ DateAdd.new(expr, interval)
46
+ end
47
+ end
48
+
49
+ # The DateAdd class represents the addition of an interval to a
50
+ # date/timestamp expression.
51
+ class DateAdd < GenericExpression
52
+ # These methods are added to datasets using the date_arithmetic
53
+ # extension, for the purposes of correctly literalizing DateAdd
54
+ # expressions for the appropriate database type.
55
+ module DatasetMethods
56
+ DURATION_UNITS = [:years, :months, :days, :hours, :minutes, :seconds].freeze
57
+ DEF_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| s.to_s.freeze}).freeze
58
+ MYSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s.upcase[0...-1]).freeze}).freeze
59
+ MSSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s[0...-1]).freeze}).freeze
60
+ H2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| s.to_s[0...-1].freeze}).freeze
61
+ DERBY_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit("SQL_TSI_#{s.to_s.upcase[0...-1]}").freeze}).freeze
62
+ ACCESS_DURATION_UNITS = DURATION_UNITS.zip(%w'yyyy m d h n s'.map{|s| s.freeze}).freeze
63
+ DB2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s).freeze}).freeze
64
+
65
+ # Return an SQL fragment for the literalized version of the
66
+ # DateAdd expression.
67
+ def date_add_sql(da)
68
+ sql = ''
69
+ date_arith_sql_append(sql, da)
70
+ sql
71
+ end
72
+
73
+ # Append the SQL fragment for the DateAdd expression to the SQL query.
74
+ def date_add_sql_append(sql, da)
75
+ h = da.interval
76
+ expr = da.expr
77
+ cast = case db_type = db.database_type
78
+ when :postgres
79
+ interval = ""
80
+ each_valid_interval_unit(h, DEF_DURATION_UNITS) do |value, sql_unit|
81
+ interval << "#{value} #{sql_unit} "
82
+ end
83
+ if interval.empty?
84
+ return literal_append(sql, Sequel.cast(expr, Time))
85
+ else
86
+ return complex_expression_sql_append(sql, :+, [Sequel.cast(expr, Time), Sequel.cast(interval, :interval)])
87
+ end
88
+ when :sqlite
89
+ args = [expr]
90
+ each_valid_interval_unit(h, DEF_DURATION_UNITS) do |value, sql_unit|
91
+ args << "#{value} #{sql_unit}"
92
+ end
93
+ return _function_sql_append(sql, :datetime, args)
94
+ when :mysql, :hsqldb, :cubrid
95
+ if db_type == :hsqldb
96
+ # HSQLDB requires 2.2.9+ for the DATE_ADD function
97
+ expr = Sequel.cast(expr, Time)
98
+ end
99
+ each_valid_interval_unit(h, MYSQL_DURATION_UNITS) do |value, sql_unit|
100
+ expr = Sequel.function(:DATE_ADD, expr, Sequel.lit(["INTERVAL ", " "], value, sql_unit))
101
+ end
102
+ when :mssql, :h2, :access
103
+ units = case db_type
104
+ when :mssql
105
+ MSSQL_DURATION_UNITS
106
+ when :h2
107
+ H2_DURATION_UNITS
108
+ when :access
109
+ ACCESS_DURATION_UNITS
110
+ end
111
+ each_valid_interval_unit(h, units) do |value, sql_unit|
112
+ expr = Sequel.function(:DATEADD, sql_unit, value, expr)
113
+ end
114
+ when :derby
115
+ if expr.is_a?(Date) && !expr.is_a?(DateTime)
116
+ # Work around for https://issues.apache.org/jira/browse/DERBY-896
117
+ expr = Sequel.cast_string(expr) + ' 00:00:00'
118
+ end
119
+ each_valid_interval_unit(h, DERBY_DURATION_UNITS) do |value, sql_unit|
120
+ expr = Sequel.lit(["{fn timestampadd(#{sql_unit}, ", ", timestamp(", "))}"], value, expr)
121
+ end
122
+ when :oracle
123
+ each_valid_interval_unit(h, MYSQL_DURATION_UNITS) do |value, sql_unit|
124
+ expr = Sequel.+(expr, Sequel.lit(["INTERVAL ", " "], value.to_s, sql_unit))
125
+ end
126
+ when :db2
127
+ expr = Sequel.cast(expr, Time)
128
+ each_valid_interval_unit(h, DB2_DURATION_UNITS) do |value, sql_unit|
129
+ expr = Sequel.+(expr, Sequel.lit(["", " "], value, sql_unit))
130
+ end
131
+ false
132
+ else
133
+ raise NotImplemented, "date arithmetic is not implemented on #{db.database_type}"
134
+ end
135
+
136
+ if cast
137
+ expr = Sequel.cast(expr, Time)
138
+ end
139
+
140
+ literal_append(sql, expr)
141
+ end
142
+
143
+ private
144
+
145
+ # Yield the value in the interval for each of the units
146
+ # present in the interval, along with the SQL fragment
147
+ # representing the unit name. Returns false if any
148
+ # values were yielded, true otherwise
149
+ def each_valid_interval_unit(interval, units)
150
+ cast = true
151
+ units.each do |unit, sql_unit|
152
+ if (value = interval[unit]) && value != 0
153
+ cast = false
154
+ yield value, sql_unit
155
+ end
156
+ end
157
+ cast
158
+ end
159
+ end
160
+
161
+ # The expression that the interval is being added to.
162
+ attr_reader :expr
163
+
164
+ # The interval added to the expression, as a hash with
165
+ # symbol keys.
166
+ attr_reader :interval
167
+
168
+ # Supports two types of intervals:
169
+ # Hash :: Used directly, but values cannot be plain strings.
170
+ # ActiveSupport::Duration :: Converted to a hash using the interval's parts.
171
+ def initialize(expr, interval)
172
+ @expr = expr
173
+ @interval = if interval.is_a?(Hash)
174
+ interval.each_value do |v|
175
+ # Attempt to prevent SQL injection by users who pass untrusted strings
176
+ # as interval values.
177
+ if v.is_a?(String) && !v.is_a?(LiteralString)
178
+ raise Sequel::InvalidValue, "cannot provide String value as interval part: #{v.inspect}"
179
+ end
180
+ end
181
+ interval
182
+ else
183
+ h = Hash.new(0)
184
+ interval.parts.each{|unit, value| h[unit] += value}
185
+ {}.merge(h)
186
+ end
187
+ end
188
+
189
+ to_s_method :date_add_sql
190
+ end
191
+ end
192
+
193
+ Dataset.register_extension(:date_arithmetic, SQL::DateAdd::DatasetMethods)
194
+ end
@@ -0,0 +1,30 @@
1
+ # The meta_def extension is designed for backwards compatibility
2
+ # with older Sequel code that uses the meta_def method on
3
+ # Database, Dataset, and Model classes and/or instances. It is
4
+ # not recommended for usage in new code. To load this extension:
5
+ #
6
+ # Sequel.extension :meta_def
7
+
8
+ module Sequel
9
+ # Contains meta_def method for adding methods to objects via blocks.
10
+ # Only recommended for backwards compatibility with existing code.
11
+ module Metaprogramming
12
+ # Define a method with the given name and block body on the receiver.
13
+ #
14
+ # ds = DB[:items]
15
+ # ds.meta_def(:x){42}
16
+ # ds.x # => 42
17
+ def meta_def(name, &block)
18
+ (class << self; self end).send(:define_method, name, &block)
19
+ end
20
+ end
21
+
22
+ Database.extend Metaprogramming
23
+ Database.send(:include, Metaprogramming)
24
+ Dataset.extend Metaprogramming
25
+ Dataset.send(:include, Metaprogramming)
26
+ if defined?(Model)
27
+ Model.extend Metaprogramming
28
+ Model.send(:include, Metaprogramming)
29
+ end
30
+ end
@@ -61,6 +61,11 @@ module Sequel
61
61
  @db.send(method_sym, *args, &block)
62
62
  end
63
63
 
64
+ # This object responds to all methods the database responds to.
65
+ def respond_to_missing?(meth, include_private)
66
+ @db.respond_to?(meth, include_private)
67
+ end
68
+
64
69
  # The default up action does nothing
65
70
  def up
66
71
  end
@@ -24,6 +24,8 @@
24
24
  # dataset and the dataset doesn't have an already cached
25
25
  # version of the columns, it will create a new dataset with
26
26
  # the same options to get the columns.
27
+ #
28
+ # This extension uses Object#extend at runtime, which can hurt performance.
27
29
 
28
30
  module Sequel
29
31
  class Dataset
@@ -5,6 +5,8 @@
5
5
  # To load the extension:
6
6
  #
7
7
  # Sequel.extension :pagination
8
+ #
9
+ # This extension uses Object#extend at runtime, which can hurt performance.
8
10
 
9
11
  module Sequel
10
12
  class Dataset
@@ -18,7 +18,8 @@
18
18
  # Sequel.pg_array(array)
19
19
  #
20
20
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
21
- # you can also use Array#pg_array:
21
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
22
+ # and have activated refinements for the file, you can also use Array#pg_array:
22
23
  #
23
24
  # array.pg_array
24
25
  #
@@ -537,3 +538,13 @@ if Sequel.core_extensions?
537
538
  end
538
539
  end
539
540
  end
541
+
542
+ if defined?(Sequel::CoreRefinements)
543
+ module Sequel::CoreRefinements
544
+ refine Array do
545
+ def pg_array(type=nil)
546
+ Sequel::Postgres::PGArray.new(self, type)
547
+ end
548
+ end
549
+ end
550
+ end
@@ -20,7 +20,8 @@
20
20
  # ia = Sequel.expr(:int_array_column).pg_array
21
21
  #
22
22
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
23
- # you can also call Symbol#pg_array:
23
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
24
+ # and have activated refinements for the file, you can also use Symbol#pg_array:
24
25
  #
25
26
  # ia = :int_array_column.pg_array
26
27
  #
@@ -261,3 +262,11 @@ if Sequel.core_extensions?
261
262
  include Sequel::Postgres::ArrayOpMethods
262
263
  end
263
264
  end
265
+
266
+ if defined?(Sequel::CoreRefinements)
267
+ module Sequel::CoreRefinements
268
+ refine Symbol do
269
+ include Sequel::Postgres::ArrayOpMethods
270
+ end
271
+ end
272
+ end
@@ -20,7 +20,8 @@
20
20
  # Sequel.hstore(hash)
21
21
  #
22
22
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
23
- # you can also use Hash#hstore:
23
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
24
+ # and have activated refinements for the file, you can also use Hash#hstore:
24
25
  #
25
26
  # hash.hstore
26
27
  #
@@ -332,3 +333,13 @@ if Sequel.core_extensions?
332
333
  end
333
334
  end
334
335
  end
336
+
337
+ if defined?(Sequel::CoreRefinements)
338
+ module Sequel::CoreRefinements
339
+ refine Hash do
340
+ def hstore
341
+ Sequel::Postgres::HStore.new(self)
342
+ end
343
+ end
344
+ end
345
+ end
@@ -21,7 +21,8 @@
21
21
  # h = Sequel.expr(:hstore_column).hstore
22
22
  #
23
23
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
24
- # you can also call Symbol#hstore:
24
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
25
+ # and have activated refinements for the file, you can also use Symbol#hstore:
25
26
  #
26
27
  # h = :hstore_column.hstore
27
28
  #
@@ -291,3 +292,11 @@ if Sequel.core_extensions?
291
292
  include Sequel::Postgres::HStoreOpMethods
292
293
  end
293
294
  end
295
+
296
+ if defined?(Sequel::CoreRefinements)
297
+ module Sequel::CoreRefinements
298
+ refine Symbol do
299
+ include Sequel::Postgres::HStoreOpMethods
300
+ end
301
+ end
302
+ end
@@ -24,7 +24,8 @@
24
24
  # Sequel.pg_json(hash)
25
25
  #
26
26
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
27
- # you can also use Array#pg_json and Hash#pg_json:
27
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
28
+ # and have activated refinements for the file, you can also use Array#pg_json and Hash#pg_json:
28
29
  #
29
30
  # array.pg_json
30
31
  # hash.pg_json
@@ -210,3 +211,19 @@ if Sequel.core_extensions?
210
211
  end
211
212
  end
212
213
  end
214
+
215
+ if defined?(Sequel::CoreRefinements)
216
+ module Sequel::CoreRefinements
217
+ refine Array do
218
+ def pg_json
219
+ Sequel::Postgres::JSONArray.new(self)
220
+ end
221
+ end
222
+
223
+ refine Hash do
224
+ def pg_json
225
+ Sequel::Postgres::JSONHash.new(self)
226
+ end
227
+ end
228
+ end
229
+ end
@@ -25,7 +25,8 @@
25
25
  # Sequel.pg_range(range)
26
26
  #
27
27
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
28
- # you can also use Range#pg_range:
28
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
29
+ # and have activated refinements for the file, you can also use Range#pg_range:
29
30
  #
30
31
  # range.pg_range
31
32
  #
@@ -511,3 +512,13 @@ if Sequel.core_extensions?
511
512
  end
512
513
  end
513
514
  end
515
+
516
+ if defined?(Sequel::CoreRefinements)
517
+ module Sequel::CoreRefinements
518
+ refine Range do
519
+ def pg_range(db_type=nil)
520
+ Sequel::Postgres::PGRange.from_range(self, db_type)
521
+ end
522
+ end
523
+ end
524
+ end
@@ -20,7 +20,8 @@
20
20
  # r = Sequel.expr(:range).pg_range
21
21
  #
22
22
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
23
- # you can also call Symbol#pg_range:
23
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
24
+ # and have activated refinements for the file, you can also use Symbol#pg_range:
24
25
  #
25
26
  # r = :range.pg_range
26
27
  #
@@ -148,3 +149,11 @@ if Sequel.core_extensions?
148
149
  include Sequel::Postgres::RangeOpMethods
149
150
  end
150
151
  end
152
+
153
+ if defined?(Sequel::CoreRefinements)
154
+ module Sequel::CoreRefinements
155
+ refine Symbol do
156
+ include Sequel::Postgres::RangeOpMethods
157
+ end
158
+ end
159
+ end
@@ -28,7 +28,8 @@
28
28
  # Sequel.pg_row(array)
29
29
  #
30
30
  # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
31
- # you can also use Array#pg_row:
31
+ # or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
32
+ # and have activated refinements for the file, you can also use Array#pg_row:
32
33
  #
33
34
  # array.pg_row
34
35
  #
@@ -460,7 +461,12 @@ module Sequel
460
461
  @conversion_procs[parser.oid] = parser
461
462
 
462
463
  if defined?(PGArray) && PGArray.respond_to?(:register) && array_oid && array_oid > 0
463
- PGArray.register(db_type, :oid=>array_oid, :converter=>parser, :type_procs=>@conversion_procs, :scalar_typecast=>schema_type_symbol)
464
+ array_type_name = if type_schema
465
+ "#{type_schema}.#{type_name}"
466
+ else
467
+ type_name
468
+ end
469
+ PGArray.register(array_type_name, :oid=>array_oid, :converter=>parser, :type_procs=>@conversion_procs, :scalar_typecast=>schema_type_symbol)
464
470
  end
465
471
 
466
472
  @row_types[db_type] = opts.merge(:parser=>parser)
@@ -574,3 +580,13 @@ if Sequel.core_extensions?
574
580
  end
575
581
  end
576
582
  end
583
+
584
+ if defined?(Sequel::CoreRefinements)
585
+ module Sequel::CoreRefinements
586
+ refine Array do
587
+ def pg_row
588
+ Sequel::Postgres::PGRow::ArrayRow.new(self)
589
+ end
590
+ end
591
+ end
592
+ end