sequel 3.37.0 → 3.38.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/README.rdoc +82 -58
- data/Rakefile +6 -5
- data/bin/sequel +1 -1
- data/doc/active_record.rdoc +67 -52
- data/doc/advanced_associations.rdoc +33 -48
- data/doc/association_basics.rdoc +41 -51
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +47 -43
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +4 -5
- data/doc/model_hooks.rdoc +3 -3
- data/doc/object_model.rdoc +31 -25
- data/doc/opening_databases.rdoc +19 -5
- data/doc/prepared_statements.rdoc +2 -2
- data/doc/querying.rdoc +109 -52
- data/doc/reflection.rdoc +6 -6
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/schema_modification.rdoc +22 -13
- data/doc/sharding.rdoc +8 -9
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +47 -7
- data/doc/thread_safety.rdoc +1 -1
- data/doc/transactions.rdoc +1 -1
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +29 -43
- data/lib/sequel/adapters/do/postgres.rb +1 -4
- data/lib/sequel/adapters/jdbc.rb +14 -3
- data/lib/sequel/adapters/jdbc/db2.rb +9 -0
- data/lib/sequel/adapters/jdbc/derby.rb +41 -4
- data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
- data/lib/sequel/adapters/mock.rb +10 -4
- data/lib/sequel/adapters/postgres.rb +1 -28
- data/lib/sequel/adapters/shared/mssql.rb +23 -13
- data/lib/sequel/adapters/shared/postgres.rb +46 -0
- data/lib/sequel/adapters/swift.rb +21 -13
- data/lib/sequel/adapters/swift/mysql.rb +1 -0
- data/lib/sequel/adapters/swift/postgres.rb +4 -5
- data/lib/sequel/adapters/swift/sqlite.rb +2 -1
- data/lib/sequel/adapters/tinytds.rb +14 -2
- data/lib/sequel/adapters/utils/pg_types.rb +5 -0
- data/lib/sequel/core.rb +29 -17
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +3 -0
- data/lib/sequel/dataset/actions.rb +5 -6
- data/lib/sequel/dataset/query.rb +7 -7
- data/lib/sequel/dataset/sql.rb +5 -18
- data/lib/sequel/extensions/core_extensions.rb +8 -12
- data/lib/sequel/extensions/pg_array.rb +59 -33
- data/lib/sequel/extensions/pg_array_ops.rb +32 -4
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +32 -17
- data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
- data/lib/sequel/extensions/pg_inet.rb +1 -2
- data/lib/sequel/extensions/pg_interval.rb +0 -1
- data/lib/sequel/extensions/pg_json.rb +41 -23
- data/lib/sequel/extensions/pg_range.rb +36 -11
- data/lib/sequel/extensions/pg_range_ops.rb +32 -4
- data/lib/sequel/extensions/pg_row.rb +572 -0
- data/lib/sequel/extensions/pg_row_ops.rb +164 -0
- data/lib/sequel/extensions/query.rb +3 -3
- data/lib/sequel/extensions/schema_dumper.rb +7 -8
- data/lib/sequel/extensions/select_remove.rb +1 -1
- data/lib/sequel/model/base.rb +1 -0
- data/lib/sequel/no_core_ext.rb +1 -1
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/validation_helpers.rb +31 -0
- data/lib/sequel/sql.rb +64 -44
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +37 -12
- data/spec/adapters/mysql_spec.rb +39 -75
- data/spec/adapters/oracle_spec.rb +11 -11
- data/spec/adapters/postgres_spec.rb +414 -237
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +14 -14
- data/spec/core/database_spec.rb +6 -6
- data/spec/core/dataset_spec.rb +169 -205
- data/spec/core/expression_filters_spec.rb +182 -295
- data/spec/core/object_graph_spec.rb +6 -6
- data/spec/core/schema_spec.rb +14 -14
- data/spec/core/spec_helper.rb +1 -0
- data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
- data/spec/extensions/columns_introspection_spec.rb +5 -5
- data/spec/extensions/hook_class_methods_spec.rb +28 -36
- data/spec/extensions/many_through_many_spec.rb +4 -4
- data/spec/extensions/pg_array_ops_spec.rb +15 -7
- data/spec/extensions/pg_array_spec.rb +81 -48
- data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
- data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
- data/spec/extensions/pg_hstore_spec.rb +66 -65
- data/spec/extensions/pg_inet_spec.rb +2 -4
- data/spec/extensions/pg_interval_spec.rb +2 -3
- data/spec/extensions/pg_json_spec.rb +20 -18
- data/spec/extensions/pg_range_ops_spec.rb +11 -4
- data/spec/extensions/pg_range_spec.rb +30 -7
- data/spec/extensions/pg_row_ops_spec.rb +48 -0
- data/spec/extensions/pg_row_plugin_spec.rb +45 -0
- data/spec/extensions/pg_row_spec.rb +323 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/query_literals_spec.rb +11 -11
- data/spec/extensions/query_spec.rb +3 -3
- data/spec/extensions/schema_dumper_spec.rb +20 -4
- data/spec/extensions/schema_spec.rb +18 -41
- data/spec/extensions/select_remove_spec.rb +4 -4
- data/spec/extensions/spec_helper.rb +4 -8
- data/spec/extensions/to_dot_spec.rb +5 -5
- data/spec/extensions/validation_class_methods_spec.rb +28 -16
- data/spec/integration/associations_test.rb +20 -20
- data/spec/integration/dataset_test.rb +98 -98
- data/spec/integration/eager_loader_test.rb +13 -27
- data/spec/integration/plugin_test.rb +5 -5
- data/spec/integration/prepared_statement_test.rb +22 -13
- data/spec/integration/schema_test.rb +28 -18
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/integration/timezone_test.rb +2 -2
- data/spec/integration/type_test.rb +15 -6
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +4 -4
- data/spec/model/base_spec.rb +5 -5
- data/spec/model/eager_loading_spec.rb +15 -15
- data/spec/model/model_spec.rb +32 -32
- data/spec/model/record_spec.rb +16 -0
- data/spec/model/spec_helper.rb +2 -6
- data/spec/model/validations_spec.rb +1 -1
- metadata +16 -4
@@ -39,6 +39,11 @@ module Sequel
|
|
39
39
|
end
|
40
40
|
end.new
|
41
41
|
|
42
|
+
# Type OIDs for string types used by PostgreSQL. These types don't
|
43
|
+
# have conversion procs associated with them (since the data is
|
44
|
+
# already in the form of a string).
|
45
|
+
STRING_TYPES = [18, 19, 25, 1042, 1043]
|
46
|
+
|
42
47
|
# Hash with type name strings/symbols and callable values for converting PostgreSQL types.
|
43
48
|
# Non-builtin types that don't have fixed numbers should use this to register
|
44
49
|
# conversion procs.
|
data/lib/sequel/core.rb
CHANGED
@@ -147,23 +147,11 @@ module Sequel
|
|
147
147
|
Database.connect(*args, &block)
|
148
148
|
end
|
149
149
|
|
150
|
-
if
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
def self.core_extensions?
|
155
|
-
# We override this method to return true inside the core_extensions.rb file,
|
156
|
-
# but we also set it here because that file is not loaded until most of Sequel
|
157
|
-
# is finished loading, and parts of Sequel check whether the core extensions
|
158
|
-
# are loaded.
|
159
|
-
true
|
160
|
-
end
|
161
|
-
else
|
162
|
-
def self.core_extensions?
|
163
|
-
false
|
164
|
-
end
|
150
|
+
# Assume the core extensions are not loaded by default, if the core_extensions
|
151
|
+
# extension is loaded, this will be overridden.
|
152
|
+
def self.core_extensions?
|
153
|
+
false
|
165
154
|
end
|
166
|
-
|
167
155
|
|
168
156
|
# Convert the +exception+ to the given class. The given class should be
|
169
157
|
# <tt>Sequel::Error</tt> or a subclass. Returns an instance of +klass+ with
|
@@ -262,6 +250,28 @@ module Sequel
|
|
262
250
|
Database.single_threaded = value
|
263
251
|
end
|
264
252
|
|
253
|
+
COLUMN_REF_RE1 = /\A((?:(?!__).)+)__((?:(?!___).)+)___(.+)\z/.freeze
|
254
|
+
COLUMN_REF_RE2 = /\A((?:(?!___).)+)___(.+)\z/.freeze
|
255
|
+
COLUMN_REF_RE3 = /\A((?:(?!__).)+)__(.+)\z/.freeze
|
256
|
+
|
257
|
+
# Splits the symbol into three parts. Each part will
|
258
|
+
# either be a string or nil.
|
259
|
+
#
|
260
|
+
# For columns, these parts are the table, column, and alias.
|
261
|
+
# For tables, these parts are the schema, table, and alias.
|
262
|
+
def self.split_symbol(sym)
|
263
|
+
case s = sym.to_s
|
264
|
+
when COLUMN_REF_RE1
|
265
|
+
[$1, $2, $3]
|
266
|
+
when COLUMN_REF_RE2
|
267
|
+
[nil, $1, $2]
|
268
|
+
when COLUMN_REF_RE3
|
269
|
+
[$1, $2, nil]
|
270
|
+
else
|
271
|
+
[nil, s, nil]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
265
275
|
# Converts the given +string+ into a +Date+ object.
|
266
276
|
#
|
267
277
|
# Sequel.string_to_date('2010-09-10') # Date.civil(2010, 09, 10)
|
@@ -413,7 +423,9 @@ module Sequel
|
|
413
423
|
private_class_method :adapter_method, :def_adapter_method
|
414
424
|
|
415
425
|
require(%w"metaprogramming sql connection_pool exceptions dataset database timezones ast_transformer version")
|
416
|
-
|
426
|
+
if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
|
427
|
+
extension(:core_extensions)
|
428
|
+
end
|
417
429
|
|
418
430
|
# Add the database adapter class methods to Sequel via metaprogramming
|
419
431
|
def_adapter_method(*Database::ADAPTERS)
|
@@ -582,7 +582,7 @@ module Sequel
|
|
582
582
|
:time
|
583
583
|
when /\A(bool(ean)?)\z/io
|
584
584
|
:boolean
|
585
|
-
when /\A(real|float|double( precision)?)\z/io
|
585
|
+
when /\A(real|float|double( precision)?|double\(\d+,\d+\)( unsigned)?)\z/io
|
586
586
|
:float
|
587
587
|
when /\A(?:(?:(?:num(?:ber|eric)?|decimal)(?:\(\d+,\s*(\d+|false|true)\))?)|(?:small)?money)\z/io
|
588
588
|
$1 && ['0', 'false'].include?($1) ? :integer : :decimal
|
@@ -98,6 +98,8 @@ module Sequel
|
|
98
98
|
# (:restrict, :cascade, :set_null, :set_default, :no_action).
|
99
99
|
# :primary_key :: Make the column as a single primary key column. This should only
|
100
100
|
# be used if you have a single, nonautoincrementing primary key column.
|
101
|
+
# :type :: Overrides the type given as the argument. Generally not used by column
|
102
|
+
# itself, but can be passed as an option to other methods that call column.
|
101
103
|
# :unique :: Mark the column as unique, generally has the same effect as
|
102
104
|
# creating a unique index on the column.
|
103
105
|
def column(name, type, opts = {})
|
@@ -122,6 +124,7 @@ module Sequel
|
|
122
124
|
# foreign_key(:artist_id) # artist_id INTEGER
|
123
125
|
# foreign_key(:artist_id, :artists) # artist_id INTEGER REFERENCES artists
|
124
126
|
# foreign_key(:artist_id, :artists, :key=>:id) # artist_id INTEGER REFERENCES artists(id)
|
127
|
+
# foreign_key(:artist_id, :artists, :type=>String) # artist_id varchar(255) REFERENCES artists(id)
|
125
128
|
#
|
126
129
|
# If you want a foreign key constraint without adding a column (usually because it is a
|
127
130
|
# composite foreign key), you can provide an array of columns as the first argument, and
|
@@ -340,7 +340,7 @@ module Sequel
|
|
340
340
|
# DB[:table].order(:id).last # SELECT * FROM table ORDER BY id DESC LIMIT 1
|
341
341
|
# # => {:id=>10}
|
342
342
|
#
|
343
|
-
# DB[:table].order(:id
|
343
|
+
# DB[:table].order(Sequel.desc(:id)).last(2) # SELECT * FROM table ORDER BY id ASC LIMIT 2
|
344
344
|
# # => [{:id=>1}, {:id=>2}]
|
345
345
|
def last(*args, &block)
|
346
346
|
raise(Error, 'No order specified') unless @opts[:order]
|
@@ -768,7 +768,7 @@ module Sequel
|
|
768
768
|
when Symbol
|
769
769
|
_, c, a = split_symbol(s)
|
770
770
|
(a || c).to_sym
|
771
|
-
when SQL::Identifier
|
771
|
+
when SQL::Identifier, SQL::Wrapper
|
772
772
|
hash_key_symbol(s.value)
|
773
773
|
when SQL::QualifiedIdentifier
|
774
774
|
hash_key_symbol(s.column)
|
@@ -820,10 +820,9 @@ module Sequel
|
|
820
820
|
when SQL::AliasedExpression
|
821
821
|
c.expression
|
822
822
|
when SQL::OrderedExpression
|
823
|
-
expr = c.expression
|
824
|
-
|
825
|
-
|
826
|
-
SQL::OrderedExpression.new(unaliased_identifier(c.expression), c.descending, :nulls=>c.nulls)
|
823
|
+
case expr = c.expression
|
824
|
+
when Symbol, SQL::AliasedExpression
|
825
|
+
SQL::OrderedExpression.new(unaliased_identifier(expr), c.descending, :nulls=>c.nulls)
|
827
826
|
else
|
828
827
|
c
|
829
828
|
end
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -500,7 +500,7 @@ module Sequel
|
|
500
500
|
# # SELECT * FROM a LEFT JOIN b AS c USING (d)
|
501
501
|
#
|
502
502
|
# DB[:a].natural_join(:b).join_table(:inner, :c) do |ta, jta, js|
|
503
|
-
# (
|
503
|
+
# (Sequel.qualify(ta, :d) > Sequel.qualify(jta, :e)) & {Sequel.qualify(ta, :f)=>DB.from(js.first.table).select(:g)}
|
504
504
|
# end
|
505
505
|
# # SELECT * FROM a NATURAL JOIN b INNER JOIN c
|
506
506
|
# # ON ((c.d > b.e) AND (c.f IN (SELECT g FROM b)))
|
@@ -657,10 +657,10 @@ module Sequel
|
|
657
657
|
#
|
658
658
|
# DB[:items].order(:name) # SELECT * FROM items ORDER BY name
|
659
659
|
# DB[:items].order(:a, :b) # SELECT * FROM items ORDER BY a, b
|
660
|
-
# DB[:items].order('a + b'
|
660
|
+
# DB[:items].order(Sequel.lit('a + b')) # SELECT * FROM items ORDER BY a + b
|
661
661
|
# DB[:items].order(:a + :b) # SELECT * FROM items ORDER BY (a + b)
|
662
|
-
# DB[:items].order(:name
|
663
|
-
# DB[:items].order(
|
662
|
+
# DB[:items].order(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name DESC
|
663
|
+
# DB[:items].order(Sequel.asc(:name, :nulls=>:last)) # SELECT * FROM items ORDER BY name ASC NULLS LAST
|
664
664
|
# DB[:items].order{sum(name).desc} # SELECT * FROM items ORDER BY sum(name) DESC
|
665
665
|
# DB[:items].order(nil) # SELECT * FROM items
|
666
666
|
def order(*columns, &block)
|
@@ -756,7 +756,7 @@ module Sequel
|
|
756
756
|
#
|
757
757
|
# DB[:items].reverse(:id) # SELECT * FROM items ORDER BY id DESC
|
758
758
|
# DB[:items].order(:id).reverse # SELECT * FROM items ORDER BY id DESC
|
759
|
-
# DB[:items].order(:id).reverse(:name
|
759
|
+
# DB[:items].order(:id).reverse(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name ASC
|
760
760
|
def reverse(*order)
|
761
761
|
order(*invert_order(order.empty? ? @opts[:order] : order))
|
762
762
|
end
|
@@ -1119,8 +1119,8 @@ module Sequel
|
|
1119
1119
|
# Inverts the given order by breaking it into a list of column references
|
1120
1120
|
# and inverting them.
|
1121
1121
|
#
|
1122
|
-
# DB[:items].invert_order([:id
|
1123
|
-
# DB[:items].invert_order(:category, :price
|
1122
|
+
# DB[:items].invert_order([Sequel.desc(:id)]]) #=> [Sequel.asc(:id)]
|
1123
|
+
# DB[:items].invert_order([:category, Sequel.desc(:price)]) #=> [Sequel.desc(:category), Sequel.asc(:price)]
|
1124
1124
|
def invert_order(order)
|
1125
1125
|
return nil unless order
|
1126
1126
|
new_order = []
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -200,9 +200,9 @@ module Sequel
|
|
200
200
|
CASE_THEN = " THEN ".freeze
|
201
201
|
CASE_WHEN = " WHEN ".freeze
|
202
202
|
CAST_OPEN = 'CAST('.freeze
|
203
|
-
COLUMN_REF_RE1 =
|
204
|
-
COLUMN_REF_RE2 =
|
205
|
-
COLUMN_REF_RE3 =
|
203
|
+
COLUMN_REF_RE1 = Sequel::COLUMN_REF_RE1
|
204
|
+
COLUMN_REF_RE2 = Sequel::COLUMN_REF_RE2
|
205
|
+
COLUMN_REF_RE3 = Sequel::COLUMN_REF_RE3
|
206
206
|
COMMA = ', '.freeze
|
207
207
|
COMMA_SEPARATOR = COMMA
|
208
208
|
CONDITION_FALSE = '(1 = 0)'.freeze
|
@@ -1320,22 +1320,9 @@ module Sequel
|
|
1320
1320
|
end
|
1321
1321
|
end
|
1322
1322
|
|
1323
|
-
#
|
1324
|
-
# either be a string or nil.
|
1325
|
-
#
|
1326
|
-
# For columns, these parts are the table, column, and alias.
|
1327
|
-
# For tables, these parts are the schema, table, and alias.
|
1323
|
+
# Delegate to Sequel.split_symbol.
|
1328
1324
|
def split_symbol(sym)
|
1329
|
-
|
1330
|
-
when COLUMN_REF_RE1
|
1331
|
-
[$1, $2, $3]
|
1332
|
-
when COLUMN_REF_RE2
|
1333
|
-
[nil, $1, $2]
|
1334
|
-
when COLUMN_REF_RE3
|
1335
|
-
[$1, $2, nil]
|
1336
|
-
else
|
1337
|
-
[nil, s, nil]
|
1338
|
-
end
|
1325
|
+
Sequel.split_symbol(sym)
|
1339
1326
|
end
|
1340
1327
|
|
1341
1328
|
# The string that is appended to to create the SQL query, the empty
|
@@ -199,28 +199,24 @@ end
|
|
199
199
|
|
200
200
|
# Sequel extends +Symbol+ to add methods to implement the SQL DSL.
|
201
201
|
class Symbol
|
202
|
-
include Sequel::SQL::QualifyingMethods
|
203
|
-
include Sequel::SQL::IdentifierMethods
|
204
202
|
include Sequel::SQL::AliasMethods
|
205
203
|
include Sequel::SQL::CastMethods
|
206
204
|
include Sequel::SQL::OrderMethods
|
207
205
|
include Sequel::SQL::BooleanMethods
|
208
206
|
include Sequel::SQL::NumericMethods
|
207
|
+
include Sequel::SQL::QualifyingMethods
|
209
208
|
include Sequel::SQL::StringMethods
|
210
209
|
include Sequel::SQL::SubscriptMethods
|
211
210
|
include Sequel::SQL::ComplexExpressionMethods
|
212
211
|
include Sequel::SQL::InequalityMethods if RUBY_VERSION < '1.9.0'
|
213
212
|
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
|
220
|
-
|
221
|
-
def *(ce=(arg=false;nil))
|
222
|
-
return super(ce) unless arg == false
|
223
|
-
Sequel::SQL::ColumnAll.new(self);
|
213
|
+
# Returns receiver wrapped in an <tt>Sequel::SQL::Identifier</tt>. Usually used to
|
214
|
+
# prevent splitting the symbol.
|
215
|
+
#
|
216
|
+
# :a__b # SQL: "a"."b"
|
217
|
+
# :a__b.identifier # SQL: "a__b"
|
218
|
+
def identifier
|
219
|
+
Sequel::SQL::Identifier.new(self)
|
224
220
|
end
|
225
221
|
|
226
222
|
# Returns a <tt>Sequel::SQL::Function</tt> with this as the function name,
|
@@ -15,15 +15,21 @@
|
|
15
15
|
#
|
16
16
|
# To turn an existing Array into a PGArray:
|
17
17
|
#
|
18
|
+
# Sequel.pg_array(array)
|
19
|
+
#
|
20
|
+
# If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
|
21
|
+
# you can also use Array#pg_array:
|
22
|
+
#
|
18
23
|
# array.pg_array
|
19
24
|
#
|
20
25
|
# You can also provide a type, though it many cases it isn't necessary:
|
21
26
|
#
|
27
|
+
# Sequel.pg_array(array, :varchar) # or :integer, :"double precision", etc.
|
22
28
|
# array.pg_array(:varchar) # or :integer, :"double precision", etc.
|
23
29
|
#
|
24
30
|
# So if you want to insert an array into an integer[] database column:
|
25
31
|
#
|
26
|
-
# DB[:table].insert(:column=>[1, 2, 3]
|
32
|
+
# DB[:table].insert(:column=>Sequel.pg_array([1, 2, 3]))
|
27
33
|
#
|
28
34
|
# If you would like to use PostgreSQL arrays in your model objects, you
|
29
35
|
# probably want to modify the schema parsing/typecasting so that it
|
@@ -135,6 +141,8 @@ module Sequel
|
|
135
141
|
# typecast method. For example, for an array of integers, this could be set to
|
136
142
|
# :integer, so that the typecast_value_integer method is called on all of the
|
137
143
|
# array elements. Defaults to :type_symbol option.
|
144
|
+
# :type_procs :: A hash mapping oids to conversion procs, used for looking up the :scalar_oid and
|
145
|
+
# value and setting the :oid value. Defaults to the global Sequel::Postgres::PG_TYPES.
|
138
146
|
# :type_symbol :: The base of the schema type symbol for this type. For example, if you provide
|
139
147
|
# :integer, Sequel will recognize this type as :integer_array during schema parsing.
|
140
148
|
# Defaults to the db_type argument.
|
@@ -142,12 +150,16 @@ module Sequel
|
|
142
150
|
# typecasting method to be created in the database. This should only be used
|
143
151
|
# to alias existing array types. For example, if there is an array type that can be
|
144
152
|
# treated just like an integer array, you can do :typecast_method=>:integer.
|
153
|
+
# :typecast_methods_module :: If given, a module object to add the typecasting method to. Defaults
|
154
|
+
# to DatabaseMethods.
|
145
155
|
#
|
146
156
|
# If a block is given, it is treated as the :converter option.
|
147
157
|
def self.register(db_type, opts={}, &block)
|
148
158
|
db_type = db_type.to_s
|
149
159
|
typecast_method = opts[:typecast_method]
|
150
160
|
type = (typecast_method || opts[:type_symbol] || db_type).to_sym
|
161
|
+
type_procs = opts[:type_procs] || PG_TYPES
|
162
|
+
mod = opts[:typecast_methods_module] || DatabaseMethods
|
151
163
|
|
152
164
|
if converter = opts[:converter]
|
153
165
|
raise Error, "can't provide both a block and :converter option to register" if block
|
@@ -157,7 +169,7 @@ module Sequel
|
|
157
169
|
|
158
170
|
if soid = opts[:scalar_oid]
|
159
171
|
raise Error, "can't provide both a converter and :scalar_oid option to register" if converter
|
160
|
-
raise Error, "no conversion proc for :scalar_oid=>#{soid.inspect}
|
172
|
+
raise Error, "no conversion proc for :scalar_oid=>#{soid.inspect}" unless converter = type_procs[soid]
|
161
173
|
end
|
162
174
|
|
163
175
|
array_type = (opts[:array_type] || db_type).to_s.dup.freeze
|
@@ -165,15 +177,27 @@ module Sequel
|
|
165
177
|
|
166
178
|
ARRAY_TYPES[db_type] = :"#{type}_array"
|
167
179
|
|
168
|
-
|
180
|
+
define_array_typecast_method(mod, type, creator, opts.fetch(:scalar_typecast, type)) unless typecast_method
|
169
181
|
|
170
182
|
if oid = opts[:oid]
|
171
|
-
|
183
|
+
type_procs[oid] = creator
|
172
184
|
end
|
173
185
|
|
174
186
|
nil
|
175
187
|
end
|
176
188
|
|
189
|
+
# Define a private array typecasting method in the given module for the given type that uses
|
190
|
+
# the creator argument to do the type conversion.
|
191
|
+
def self.define_array_typecast_method(mod, type, creator, scalar_typecast)
|
192
|
+
mod.class_eval do
|
193
|
+
meth = :"typecast_value_#{type}_array"
|
194
|
+
scalar_typecast_method = :"typecast_value_#{scalar_typecast}"
|
195
|
+
define_method(meth){|v| typecast_value_pg_array(v, creator, scalar_typecast_method)}
|
196
|
+
private meth
|
197
|
+
end
|
198
|
+
end
|
199
|
+
private_class_method :define_array_typecast_method
|
200
|
+
|
177
201
|
module DatabaseMethods
|
178
202
|
APOS = "'".freeze
|
179
203
|
DOUBLE_APOS = "''".freeze
|
@@ -181,22 +205,6 @@ module Sequel
|
|
181
205
|
ESCAPE_REPLACEMENT = '\\\\\1'.freeze
|
182
206
|
BLOB_RANGE = 1...-1
|
183
207
|
|
184
|
-
# Reset the conversion procs when extending the Database object, so
|
185
|
-
# it will pick up the array convertors. This is only done for the native
|
186
|
-
# postgres adapter.
|
187
|
-
def self.extended(db)
|
188
|
-
db.reset_conversion_procs if db.respond_to?(:reset_conversion_procs)
|
189
|
-
end
|
190
|
-
|
191
|
-
# Define a private array typecasting method for the given type that uses
|
192
|
-
# the creator argument to do the type conversion.
|
193
|
-
def self.define_array_typecast_method(type, creator, scalar_typecast)
|
194
|
-
meth = :"typecast_value_#{type}_array"
|
195
|
-
scalar_typecast_method = :"typecast_value_#{scalar_typecast}"
|
196
|
-
define_method(meth){|v| typecast_value_pg_array(v, creator, scalar_typecast_method)}
|
197
|
-
private meth
|
198
|
-
end
|
199
|
-
|
200
208
|
# Handle arrays in bound variables
|
201
209
|
def bound_variable_arg(arg, conn)
|
202
210
|
case arg
|
@@ -239,12 +247,11 @@ module Sequel
|
|
239
247
|
# Manually override the typecasting for timestamp array types so that
|
240
248
|
# they use the database's timezone instead of the global Sequel
|
241
249
|
# timezone.
|
242
|
-
def get_conversion_procs
|
250
|
+
def get_conversion_procs
|
243
251
|
procs = super
|
244
252
|
|
245
|
-
|
246
|
-
procs[
|
247
|
-
procs[1185] = Creator.new("timestamp with time zone", converter)
|
253
|
+
procs[1115] = Creator.new("timestamp without time zone", procs[1114])
|
254
|
+
procs[1185] = Creator.new("timestamp with time zone", procs[1184])
|
248
255
|
|
249
256
|
procs
|
250
257
|
end
|
@@ -271,8 +278,6 @@ module Sequel
|
|
271
278
|
value = Sequel.recursive_map(value, method(scalar_typecast_method))
|
272
279
|
end
|
273
280
|
PGArray.new(value, creator.type)
|
274
|
-
when String
|
275
|
-
creator.call(value)
|
276
281
|
else
|
277
282
|
raise Sequel::InvalidValue, "invalid value for array type: #{value.inspect}"
|
278
283
|
end
|
@@ -497,15 +502,36 @@ module Sequel
|
|
497
502
|
end
|
498
503
|
end
|
499
504
|
|
505
|
+
module SQL::Builders
|
506
|
+
# Return a Postgres::PGArray proxy for the given array and database array type.
|
507
|
+
def pg_array(v, array_type=nil)
|
508
|
+
case v
|
509
|
+
when Postgres::PGArray
|
510
|
+
if array_type.nil? || v.array_type == array_type
|
511
|
+
v
|
512
|
+
else
|
513
|
+
Postgres::PGArray.new(v.to_a, array_type)
|
514
|
+
end
|
515
|
+
when Array
|
516
|
+
Postgres::PGArray.new(v, array_type)
|
517
|
+
else
|
518
|
+
# May not be defined unless the pg_array_ops extension is used
|
519
|
+
pg_array_op(v)
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
500
524
|
Database.register_extension(:pg_array, Postgres::PGArray::DatabaseMethods)
|
501
525
|
end
|
502
526
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
527
|
+
if Sequel.core_extensions?
|
528
|
+
class Array
|
529
|
+
# Return a PGArray proxy to the receiver, using a
|
530
|
+
# specific database type if given. This is mostly useful
|
531
|
+
# as a short cut for creating PGArray objects that didn't
|
532
|
+
# come from the database.
|
533
|
+
def pg_array(type=nil)
|
534
|
+
Sequel::Postgres::PGArray.new(self, type)
|
535
|
+
end
|
510
536
|
end
|
511
537
|
end
|
@@ -5,8 +5,22 @@
|
|
5
5
|
#
|
6
6
|
# Sequel.extension :pg_array_ops
|
7
7
|
#
|
8
|
-
# The most common usage is
|
9
|
-
#
|
8
|
+
# The most common usage is passing an expression to Sequel.pg_array_op:
|
9
|
+
#
|
10
|
+
# ia = Sequel.pg_array_op(:int_array_column)
|
11
|
+
#
|
12
|
+
# If you have also loaded the pg_array extension, you can use
|
13
|
+
# Sequel.pg_array as well:
|
14
|
+
#
|
15
|
+
# ia = Sequel.pg_array(:int_array_column)
|
16
|
+
#
|
17
|
+
# Also, on most Sequel expression objects, you can call the pg_array
|
18
|
+
# method:
|
19
|
+
#
|
20
|
+
# ia = Sequel.expr(:int_array_column).pg_array
|
21
|
+
#
|
22
|
+
# If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
|
23
|
+
# you can also call Symbol#pg_array:
|
10
24
|
#
|
11
25
|
# ia = :int_array_column.pg_array
|
12
26
|
#
|
@@ -211,6 +225,18 @@ module Sequel
|
|
211
225
|
end
|
212
226
|
end
|
213
227
|
|
228
|
+
module SQL::Builders
|
229
|
+
# Return the object wrapped in an Postgres::ArrayOp.
|
230
|
+
def pg_array_op(v)
|
231
|
+
case v
|
232
|
+
when Postgres::ArrayOp
|
233
|
+
v
|
234
|
+
else
|
235
|
+
Postgres::ArrayOp.new(v)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
214
240
|
class SQL::GenericExpression
|
215
241
|
include Sequel::Postgres::ArrayOpMethods
|
216
242
|
end
|
@@ -220,6 +246,8 @@ module Sequel
|
|
220
246
|
end
|
221
247
|
end
|
222
248
|
|
223
|
-
|
224
|
-
|
249
|
+
if Sequel.core_extensions?
|
250
|
+
class Symbol
|
251
|
+
include Sequel::Postgres::ArrayOpMethods
|
252
|
+
end
|
225
253
|
end
|