sequel 4.47.0 → 4.48.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.
- checksums.yaml +4 -4
- data/CHANGELOG +134 -0
- data/Rakefile +1 -1
- data/doc/release_notes/4.48.0.txt +293 -0
- data/lib/sequel/adapters/ado/access.rb +2 -1
- data/lib/sequel/adapters/do/postgres.rb +5 -2
- data/lib/sequel/adapters/ibmdb.rb +24 -7
- data/lib/sequel/adapters/jdbc.rb +36 -22
- data/lib/sequel/adapters/jdbc/db2.rb +12 -3
- data/lib/sequel/adapters/jdbc/derby.rb +4 -5
- data/lib/sequel/adapters/jdbc/oracle.rb +16 -2
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -18
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +9 -7
- data/lib/sequel/adapters/jdbc/sqlserver.rb +11 -4
- data/lib/sequel/adapters/mock.rb +24 -19
- data/lib/sequel/adapters/mysql.rb +17 -16
- data/lib/sequel/adapters/mysql2.rb +4 -5
- data/lib/sequel/adapters/oracle.rb +5 -9
- data/lib/sequel/adapters/postgres.rb +89 -102
- data/lib/sequel/adapters/shared/db2.rb +22 -6
- data/lib/sequel/adapters/shared/mssql.rb +5 -4
- data/lib/sequel/adapters/shared/mysql.rb +75 -24
- data/lib/sequel/adapters/shared/postgres.rb +196 -94
- data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
- data/lib/sequel/adapters/shared/sqlite.rb +72 -82
- data/lib/sequel/adapters/sqlanywhere.rb +4 -1
- data/lib/sequel/adapters/sqlite.rb +5 -3
- data/lib/sequel/adapters/swift/postgres.rb +5 -2
- data/lib/sequel/adapters/tinytds.rb +0 -5
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/adapters/utils/pg_types.rb +2 -76
- data/lib/sequel/core.rb +2 -2
- data/lib/sequel/database/connecting.rb +5 -5
- data/lib/sequel/database/dataset.rb +6 -3
- data/lib/sequel/database/misc.rb +1 -1
- data/lib/sequel/database/query.rb +3 -0
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset/actions.rb +18 -10
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/misc.rb +1 -0
- data/lib/sequel/dataset/prepared_statements.rb +3 -3
- data/lib/sequel/dataset/query.rb +19 -8
- data/lib/sequel/extensions/core_extensions.rb +4 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +3 -0
- data/lib/sequel/extensions/filter_having.rb +2 -0
- data/lib/sequel/extensions/freeze_datasets.rb +2 -0
- data/lib/sequel/extensions/from_block.rb +1 -1
- data/lib/sequel/extensions/graph_each.rb +2 -2
- data/lib/sequel/extensions/hash_aliases.rb +2 -0
- data/lib/sequel/extensions/identifier_mangling.rb +0 -7
- data/lib/sequel/extensions/meta_def.rb +2 -0
- data/lib/sequel/extensions/migration.rb +6 -6
- data/lib/sequel/extensions/no_auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +207 -130
- data/lib/sequel/extensions/pg_hstore.rb +38 -20
- data/lib/sequel/extensions/pg_inet.rb +18 -6
- data/lib/sequel/extensions/pg_interval.rb +19 -12
- data/lib/sequel/extensions/pg_json.rb +25 -14
- data/lib/sequel/extensions/pg_json_ops.rb +2 -2
- data/lib/sequel/extensions/pg_range.rb +133 -100
- data/lib/sequel/extensions/pg_range_ops.rb +4 -3
- data/lib/sequel/extensions/pg_row.rb +68 -39
- data/lib/sequel/extensions/pg_row_ops.rb +11 -5
- data/lib/sequel/extensions/query_literals.rb +2 -0
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +2 -0
- data/lib/sequel/extensions/s.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +24 -24
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +3 -1
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +83 -0
- data/lib/sequel/extensions/set_overrides.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +0 -1
- data/lib/sequel/extensions/symbol_aref.rb +0 -4
- data/lib/sequel/model.rb +25 -57
- data/lib/sequel/model/associations.rb +14 -5
- data/lib/sequel/model/base.rb +96 -32
- data/lib/sequel/plugins/association_pks.rb +73 -46
- data/lib/sequel/plugins/association_proxies.rb +1 -1
- data/lib/sequel/plugins/auto_validations.rb +6 -2
- data/lib/sequel/plugins/boolean_readers.rb +1 -1
- data/lib/sequel/plugins/caching.rb +19 -13
- data/lib/sequel/plugins/class_table_inheritance.rb +19 -10
- data/lib/sequel/plugins/column_conflicts.rb +7 -2
- data/lib/sequel/plugins/column_select.rb +1 -1
- data/lib/sequel/plugins/csv_serializer.rb +8 -8
- data/lib/sequel/plugins/defaults_setter.rb +10 -0
- data/lib/sequel/plugins/eager_each.rb +1 -1
- data/lib/sequel/plugins/force_encoding.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +9 -12
- data/lib/sequel/plugins/identifier_columns.rb +2 -0
- data/lib/sequel/plugins/instance_filters.rb +3 -1
- data/lib/sequel/plugins/instance_hooks.rb +17 -9
- data/lib/sequel/plugins/json_serializer.rb +17 -10
- data/lib/sequel/plugins/lazy_attributes.rb +8 -7
- data/lib/sequel/plugins/modification_detection.rb +3 -0
- data/lib/sequel/plugins/nested_attributes.rb +5 -1
- data/lib/sequel/plugins/pg_array_associations.rb +5 -0
- data/lib/sequel/plugins/prepared_statements.rb +1 -0
- data/lib/sequel/plugins/rcte_tree.rb +4 -4
- data/lib/sequel/plugins/serialization.rb +3 -10
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/split_values.rb +6 -5
- data/lib/sequel/plugins/static_cache.rb +31 -25
- data/lib/sequel/plugins/subset_conditions.rb +3 -1
- data/lib/sequel/plugins/table_select.rb +1 -1
- data/lib/sequel/plugins/touch.rb +2 -1
- data/lib/sequel/plugins/validation_class_methods.rb +5 -6
- data/lib/sequel/plugins/validation_helpers.rb +2 -4
- data/lib/sequel/plugins/xml_serializer.rb +4 -4
- data/lib/sequel/sql.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +115 -14
- data/spec/adapters/mysql_spec.rb +78 -28
- data/spec/adapters/oracle_spec.rb +24 -24
- data/spec/adapters/postgres_spec.rb +38 -24
- data/spec/adapters/sqlanywhere_spec.rb +88 -86
- data/spec/adapters/sqlite_spec.rb +29 -24
- data/spec/core/connection_pool_spec.rb +17 -0
- data/spec/core/database_spec.rb +6 -0
- data/spec/core/dataset_spec.rb +46 -36
- data/spec/core/schema_spec.rb +16 -0
- data/spec/core/spec_helper.rb +1 -0
- data/spec/core_extensions_spec.rb +6 -2
- data/spec/extensions/active_model_spec.rb +1 -1
- data/spec/extensions/arbitrary_servers_spec.rb +1 -1
- data/spec/extensions/association_pks_spec.rb +34 -2
- data/spec/extensions/auto_literal_strings_spec.rb +5 -1
- data/spec/extensions/auto_validations_spec.rb +2 -0
- data/spec/extensions/boolean_readers_spec.rb +1 -1
- data/spec/extensions/boolean_subsets_spec.rb +1 -1
- data/spec/extensions/class_table_inheritance_spec.rb +48 -2
- data/spec/extensions/column_conflicts_spec.rb +11 -0
- data/spec/extensions/connection_validator_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +8 -8
- data/spec/extensions/defaults_setter_spec.rb +1 -1
- data/spec/extensions/filter_having_spec.rb +5 -3
- data/spec/extensions/hash_aliases_spec.rb +3 -1
- data/spec/extensions/identifier_columns_spec.rb +3 -1
- data/spec/extensions/implicit_subquery_spec.rb +4 -2
- data/spec/extensions/json_serializer_spec.rb +18 -0
- data/spec/extensions/lazy_attributes_spec.rb +3 -3
- data/spec/extensions/meta_def_spec.rb +9 -0
- data/spec/extensions/migration_spec.rb +3 -3
- data/spec/extensions/nested_attributes_spec.rb +14 -3
- data/spec/extensions/no_auto_literal_strings_spec.rb +8 -4
- data/spec/extensions/pg_array_associations_spec.rb +29 -18
- data/spec/extensions/pg_array_spec.rb +44 -25
- data/spec/extensions/pg_hstore_spec.rb +10 -0
- data/spec/extensions/pg_inet_spec.rb +26 -0
- data/spec/extensions/pg_interval_spec.rb +20 -0
- data/spec/extensions/pg_json_spec.rb +24 -0
- data/spec/extensions/pg_range_spec.rb +98 -14
- data/spec/extensions/pg_row_spec.rb +14 -4
- data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
- data/spec/extensions/query_literals_spec.rb +3 -1
- data/spec/extensions/schema_dumper_spec.rb +96 -98
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +10 -6
- data/spec/extensions/sequel_4_dataset_methods_spec.rb +121 -0
- data/spec/extensions/single_table_inheritance_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +7 -1
- data/spec/extensions/static_cache_spec.rb +75 -24
- data/spec/extensions/string_agg_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +9 -0
- data/spec/extensions/validation_helpers_spec.rb +9 -3
- data/spec/extensions/whitelist_security_spec.rb +26 -0
- data/spec/integration/dataset_test.rb +45 -44
- data/spec/integration/plugin_test.rb +20 -0
- data/spec/integration/prepared_statement_test.rb +3 -0
- data/spec/integration/schema_test.rb +21 -1
- data/spec/integration/transaction_test.rb +40 -40
- data/spec/model/class_dataset_methods_spec.rb +14 -4
- data/spec/model/dataset_methods_spec.rb +12 -3
- data/spec/model/model_spec.rb +8 -0
- metadata +6 -4
- data/spec/adapters/firebird_spec.rb +0 -405
- data/spec/adapters/informix_spec.rb +0 -100
|
@@ -49,18 +49,18 @@
|
|
|
49
49
|
#
|
|
50
50
|
# * \[\]
|
|
51
51
|
# * \[\]=
|
|
52
|
-
# * assoc
|
|
52
|
+
# * assoc
|
|
53
53
|
# * delete
|
|
54
54
|
# * fetch
|
|
55
55
|
# * has_key?
|
|
56
56
|
# * has_value?
|
|
57
57
|
# * include?
|
|
58
|
-
# * key
|
|
58
|
+
# * key
|
|
59
59
|
# * key?
|
|
60
60
|
# * member?
|
|
61
61
|
# * merge
|
|
62
62
|
# * merge!
|
|
63
|
-
# * rassoc
|
|
63
|
+
# * rassoc
|
|
64
64
|
# * replace
|
|
65
65
|
# * store
|
|
66
66
|
# * update
|
|
@@ -70,10 +70,7 @@
|
|
|
70
70
|
#
|
|
71
71
|
# DB[:table].insert(:column=>Sequel.hstore('foo'=>'bar'))
|
|
72
72
|
#
|
|
73
|
-
#
|
|
74
|
-
# probably want to modify the schema parsing/typecasting so that it
|
|
75
|
-
# recognizes and correctly handles the hstore columns, which you can
|
|
76
|
-
# do by:
|
|
73
|
+
# To use this extension, first load it into your Sequel::Database instance:
|
|
77
74
|
#
|
|
78
75
|
# DB.extension :pg_hstore
|
|
79
76
|
#
|
|
@@ -95,12 +92,19 @@ module Sequel
|
|
|
95
92
|
# Parser for PostgreSQL hstore output format.
|
|
96
93
|
class Parser < StringScanner
|
|
97
94
|
QUOTE_RE = /"/.freeze
|
|
95
|
+
Sequel::Deprecation.deprecate_constant(self, :QUOTE_RE)
|
|
98
96
|
KV_SEP_RE = /"\s*=>\s*/.freeze
|
|
97
|
+
Sequel::Deprecation.deprecate_constant(self, :KV_SEP_RE)
|
|
99
98
|
NULL_RE = /NULL/.freeze
|
|
99
|
+
Sequel::Deprecation.deprecate_constant(self, :NULL_RE)
|
|
100
100
|
SEP_RE = /,\s*/.freeze
|
|
101
|
+
Sequel::Deprecation.deprecate_constant(self, :SEP_RE)
|
|
101
102
|
QUOTED_RE = /(\\"|[^"])*/.freeze
|
|
103
|
+
Sequel::Deprecation.deprecate_constant(self, :QUOTED_RE)
|
|
102
104
|
REPLACE_RE = /\\(.)/.freeze
|
|
105
|
+
Sequel::Deprecation.deprecate_constant(self, :REPLACE_RE)
|
|
103
106
|
REPLACE_WITH = '\1'.freeze
|
|
107
|
+
Sequel::Deprecation.deprecate_constant(self, :REPLACE_WITH)
|
|
104
108
|
|
|
105
109
|
# Parse the output format that PostgreSQL uses for hstore
|
|
106
110
|
# columns. Note that this does not attempt to parse all
|
|
@@ -114,17 +118,17 @@ module Sequel
|
|
|
114
118
|
return @result if @result
|
|
115
119
|
hash = {}
|
|
116
120
|
while !eos?
|
|
117
|
-
skip(
|
|
121
|
+
skip(/"/)
|
|
118
122
|
k = parse_quoted
|
|
119
|
-
skip(
|
|
120
|
-
if skip(
|
|
123
|
+
skip(/"\s*=>\s*/)
|
|
124
|
+
if skip(/"/)
|
|
121
125
|
v = parse_quoted
|
|
122
|
-
skip(
|
|
126
|
+
skip(/"/)
|
|
123
127
|
else
|
|
124
|
-
scan(
|
|
128
|
+
scan(/NULL/)
|
|
125
129
|
v = nil
|
|
126
130
|
end
|
|
127
|
-
skip(
|
|
131
|
+
skip(/,\s*/)
|
|
128
132
|
hash[k] = v
|
|
129
133
|
end
|
|
130
134
|
@result = hash
|
|
@@ -134,7 +138,7 @@ module Sequel
|
|
|
134
138
|
|
|
135
139
|
# Parse and unescape a quoted key/value.
|
|
136
140
|
def parse_quoted
|
|
137
|
-
scan(
|
|
141
|
+
scan(/(\\"|[^"])*/).gsub(/\\(.)/, '\1')
|
|
138
142
|
end
|
|
139
143
|
end
|
|
140
144
|
|
|
@@ -158,6 +162,13 @@ module Sequel
|
|
|
158
162
|
end
|
|
159
163
|
end
|
|
160
164
|
|
|
165
|
+
# SEQUEL5: Remove
|
|
166
|
+
def reset_conversion_procs
|
|
167
|
+
procs = super
|
|
168
|
+
add_named_conversion_proc(:hstore, &HStore.method(:parse))
|
|
169
|
+
procs
|
|
170
|
+
end
|
|
171
|
+
|
|
161
172
|
private
|
|
162
173
|
|
|
163
174
|
# Recognize the hstore database type.
|
|
@@ -188,12 +199,19 @@ module Sequel
|
|
|
188
199
|
DEFAULT_PROC = lambda{|h, k| h[k.to_s] unless k.is_a?(String)}
|
|
189
200
|
|
|
190
201
|
QUOTE = '"'.freeze
|
|
202
|
+
Sequel::Deprecation.deprecate_constant(self, :QUOTE)
|
|
191
203
|
COMMA = ",".freeze
|
|
204
|
+
Sequel::Deprecation.deprecate_constant(self, :COMMA)
|
|
192
205
|
KV_SEP = "=>".freeze
|
|
206
|
+
Sequel::Deprecation.deprecate_constant(self, :KV_SEP)
|
|
193
207
|
NULL = "NULL".freeze
|
|
208
|
+
Sequel::Deprecation.deprecate_constant(self, :NULL)
|
|
194
209
|
ESCAPE_RE = /("|\\)/.freeze
|
|
210
|
+
Sequel::Deprecation.deprecate_constant(self, :ESCAPE_RE)
|
|
195
211
|
ESCAPE_REPLACE = '\\\\\1'.freeze
|
|
212
|
+
Sequel::Deprecation.deprecate_constant(self, :ESCAPE_REPLACE)
|
|
196
213
|
HSTORE_CAST = '::hstore'.freeze
|
|
214
|
+
Sequel::Deprecation.deprecate_constant(self, :HSTORE_CAST)
|
|
197
215
|
|
|
198
216
|
if RUBY_VERSION >= '1.9'
|
|
199
217
|
# Undef 1.9 marshal_{dump,load} methods in the delegate class,
|
|
@@ -258,7 +276,7 @@ module Sequel
|
|
|
258
276
|
# Append a literalize version of the hstore to the sql.
|
|
259
277
|
def sql_literal_append(ds, sql)
|
|
260
278
|
ds.literal_append(sql, unquoted_literal)
|
|
261
|
-
sql <<
|
|
279
|
+
sql << '::hstore'
|
|
262
280
|
end
|
|
263
281
|
|
|
264
282
|
# Return a string containing the unquoted, unstring-escaped
|
|
@@ -267,10 +285,10 @@ module Sequel
|
|
|
267
285
|
def unquoted_literal
|
|
268
286
|
str = String.new
|
|
269
287
|
comma = false
|
|
270
|
-
commas =
|
|
271
|
-
quote =
|
|
272
|
-
kv_sep =
|
|
273
|
-
null = NULL
|
|
288
|
+
commas = ","
|
|
289
|
+
quote = '"'
|
|
290
|
+
kv_sep = "=>"
|
|
291
|
+
null = "NULL"
|
|
274
292
|
each do |k, v|
|
|
275
293
|
str << commas if comma
|
|
276
294
|
str << quote << escape_value(k) << quote
|
|
@@ -303,7 +321,7 @@ module Sequel
|
|
|
303
321
|
# Escape key/value strings when literalizing to
|
|
304
322
|
# correctly handle backslash and quote characters.
|
|
305
323
|
def escape_value(k)
|
|
306
|
-
k.to_s.gsub(
|
|
324
|
+
k.to_s.gsub(/("|\\)/, '\\\\\1')
|
|
307
325
|
end
|
|
308
326
|
end
|
|
309
327
|
end
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
# Related module: Sequel::Postgres::InetDatabaseMethods
|
|
30
30
|
|
|
31
31
|
require 'ipaddr'
|
|
32
|
-
Sequel.require 'adapters/
|
|
32
|
+
Sequel.require 'adapters/shared/postgres'
|
|
33
33
|
|
|
34
34
|
module Sequel
|
|
35
35
|
module Postgres
|
|
@@ -41,7 +41,14 @@ module Sequel
|
|
|
41
41
|
def self.extended(db)
|
|
42
42
|
db.instance_eval do
|
|
43
43
|
extend_datasets(InetDatasetMethods)
|
|
44
|
-
|
|
44
|
+
meth = IPAddr.method(:new)
|
|
45
|
+
add_conversion_proc(869, meth)
|
|
46
|
+
add_conversion_proc(650, meth)
|
|
47
|
+
if respond_to?(:register_array_type)
|
|
48
|
+
register_array_type('inet', :oid=>1041, :scalar_oid=>869)
|
|
49
|
+
register_array_type('cidr', :oid=>651, :scalar_oid=>650)
|
|
50
|
+
register_array_type('macaddr', :oid=>1040)
|
|
51
|
+
end
|
|
45
52
|
@schema_type_classes[:ipaddr] = IPAddr
|
|
46
53
|
end
|
|
47
54
|
end
|
|
@@ -106,11 +113,16 @@ module Sequel
|
|
|
106
113
|
end
|
|
107
114
|
end
|
|
108
115
|
|
|
109
|
-
|
|
116
|
+
# SEQUEL5: Remove
|
|
117
|
+
meth = IPAddr.method(:new)
|
|
118
|
+
PG__TYPES[869] = PG__TYPES[650] = lambda do |s|
|
|
119
|
+
Sequel::Deprecation.deprecate("Conversion proc for inet/cidr added globally by pg_inet extension", "Load the pg_inet extension into the Database instance")
|
|
120
|
+
IPAddr.new(s)
|
|
121
|
+
end
|
|
110
122
|
if defined?(PGArray) && PGArray.respond_to?(:register)
|
|
111
|
-
PGArray.register('inet', :oid=>1041, :scalar_oid=>869)
|
|
112
|
-
PGArray.register('cidr', :oid=>651, :scalar_oid=>650)
|
|
113
|
-
PGArray.register('macaddr', :oid=>1040)
|
|
123
|
+
PGArray.register('inet', :oid=>1041, :scalar_oid=>869, :skip_deprecation_warning=>true)
|
|
124
|
+
PGArray.register('cidr', :oid=>651, :scalar_oid=>650, :skip_deprecation_warning=>true)
|
|
125
|
+
PGArray.register('macaddr', :oid=>1040, :skip_deprecation_warning=>true)
|
|
114
126
|
end
|
|
115
127
|
end
|
|
116
128
|
|
|
@@ -10,10 +10,7 @@
|
|
|
10
10
|
# ActiveSupport::Duration that use the standard Sequel literalization
|
|
11
11
|
# callbacks, so they work on all adapters.
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
# probably want to modify the typecasting so that it
|
|
15
|
-
# recognizes and correctly handles the interval columns, which you can
|
|
16
|
-
# do by:
|
|
13
|
+
# To use this extension, load it into the Database instance:
|
|
17
14
|
#
|
|
18
15
|
# DB.extension :pg_interval
|
|
19
16
|
#
|
|
@@ -36,12 +33,13 @@
|
|
|
36
33
|
# Related module: Sequel::Postgres::IntervalDatabaseMethods
|
|
37
34
|
|
|
38
35
|
require 'active_support/duration'
|
|
39
|
-
Sequel.require 'adapters/
|
|
36
|
+
Sequel.require 'adapters/shared/postgres'
|
|
40
37
|
|
|
41
38
|
module Sequel
|
|
42
39
|
module Postgres
|
|
43
40
|
module IntervalDatabaseMethods
|
|
44
41
|
EMPTY_INTERVAL = '0'.freeze
|
|
42
|
+
Sequel::Deprecation.deprecate_constant(self, :EMPTY_INTERVAL)
|
|
45
43
|
DURATION_UNITS = [:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
|
|
46
44
|
|
|
47
45
|
# Return an unquoted string version of the duration object suitable for
|
|
@@ -58,7 +56,7 @@ module Sequel
|
|
|
58
56
|
end
|
|
59
57
|
|
|
60
58
|
if s.empty?
|
|
61
|
-
|
|
59
|
+
'0'
|
|
62
60
|
else
|
|
63
61
|
s
|
|
64
62
|
end
|
|
@@ -67,11 +65,12 @@ module Sequel
|
|
|
67
65
|
# Creates callable objects that convert strings into ActiveSupport::Duration instances.
|
|
68
66
|
class Parser
|
|
69
67
|
# Regexp that parses the full range of PostgreSQL interval type output.
|
|
70
|
-
PARSER = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:(?:([+-])?(\d{2,10}):(\d\d):(\d\d(\.\d+)?))|([+-]?\d+ hours?\s?)?([+-]?\d+ mins?\s?)?([+-]?\d+(\.\d+)? secs?\s?)?)?\z/
|
|
68
|
+
PARSER = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:(?:([+-])?(\d{2,10}):(\d\d):(\d\d(\.\d+)?))|([+-]?\d+ hours?\s?)?([+-]?\d+ mins?\s?)?([+-]?\d+(\.\d+)? secs?\s?)?)?\z/
|
|
69
|
+
Sequel::Deprecation.deprecate_constant(self, :PARSER)
|
|
71
70
|
|
|
72
71
|
# Parse the interval input string into an ActiveSupport::Duration instance.
|
|
73
72
|
def call(string)
|
|
74
|
-
raise(InvalidValue, "invalid or unhandled interval format: #{string.inspect}") unless matches =
|
|
73
|
+
raise(InvalidValue, "invalid or unhandled interval format: #{string.inspect}") unless matches = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:(?:([+-])?(\d{2,10}):(\d\d):(\d\d(\.\d+)?))|([+-]?\d+ hours?\s?)?([+-]?\d+ mins?\s?)?([+-]?\d+(\.\d+)? secs?\s?)?)?\z/.match(string)
|
|
75
74
|
|
|
76
75
|
value = 0
|
|
77
76
|
parts = []
|
|
@@ -124,7 +123,10 @@ module Sequel
|
|
|
124
123
|
def self.extended(db)
|
|
125
124
|
db.instance_eval do
|
|
126
125
|
extend_datasets(IntervalDatasetMethods)
|
|
127
|
-
|
|
126
|
+
add_conversion_proc(1186, Postgres::IntervalDatabaseMethods::PARSER)
|
|
127
|
+
if respond_to?(:register_array_type)
|
|
128
|
+
register_array_type('interval', :oid=>1187, :scalar_oid=>1186)
|
|
129
|
+
end
|
|
128
130
|
@schema_type_classes[:interval] = ActiveSupport::Duration
|
|
129
131
|
end
|
|
130
132
|
end
|
|
@@ -174,6 +176,7 @@ module Sequel
|
|
|
174
176
|
|
|
175
177
|
module IntervalDatasetMethods
|
|
176
178
|
CAST_INTERVAL = '::interval'.freeze
|
|
179
|
+
Sequel::Deprecation.deprecate_constant(self, :CAST_INTERVAL)
|
|
177
180
|
|
|
178
181
|
# Handle literalization of ActiveSupport::Duration objects, treating them as
|
|
179
182
|
# PostgreSQL intervals.
|
|
@@ -181,16 +184,20 @@ module Sequel
|
|
|
181
184
|
case v
|
|
182
185
|
when ActiveSupport::Duration
|
|
183
186
|
literal_append(sql, IntervalDatabaseMethods.literal_duration(v))
|
|
184
|
-
sql <<
|
|
187
|
+
sql << '::interval'
|
|
185
188
|
else
|
|
186
189
|
super
|
|
187
190
|
end
|
|
188
191
|
end
|
|
189
192
|
end
|
|
190
193
|
|
|
191
|
-
|
|
194
|
+
# SEQUEL5: Remove
|
|
195
|
+
PG__TYPES[1186] = lambda do |s|
|
|
196
|
+
Sequel::Deprecation.deprecate("Conversion proc for interval added globally by pg_interval extension", "Load the pg_interval extension into the Database instance")
|
|
197
|
+
Postgres::IntervalDatabaseMethods::PARSER.call(s)
|
|
198
|
+
end
|
|
192
199
|
if defined?(PGArray) && PGArray.respond_to?(:register)
|
|
193
|
-
PGArray.register('interval', :oid=>1187, :scalar_oid=>1186)
|
|
200
|
+
PGArray.register('interval', :oid=>1187, :scalar_oid=>1186, :skip_deprecation_warning=>true)
|
|
194
201
|
end
|
|
195
202
|
end
|
|
196
203
|
|
|
@@ -38,10 +38,7 @@
|
|
|
38
38
|
# DB[:table].insert(:column=>Sequel.pg_json([1, 2, 3]))
|
|
39
39
|
# DB[:table].insert(:column=>Sequel.pg_json({'a'=>1, 'b'=>2}))
|
|
40
40
|
#
|
|
41
|
-
#
|
|
42
|
-
# objects, you probably want to modify the schema parsing/typecasting
|
|
43
|
-
# so that it recognizes and correctly handles the json type, which
|
|
44
|
-
# you can do by:
|
|
41
|
+
# To use this extension, please load it into the Database instance:
|
|
45
42
|
#
|
|
46
43
|
# DB.extension :pg_json
|
|
47
44
|
#
|
|
@@ -65,12 +62,14 @@
|
|
|
65
62
|
|
|
66
63
|
require 'delegate'
|
|
67
64
|
require 'json'
|
|
68
|
-
Sequel.require 'adapters/
|
|
65
|
+
Sequel.require 'adapters/shared/postgres'
|
|
69
66
|
|
|
70
67
|
module Sequel
|
|
71
68
|
module Postgres
|
|
72
69
|
CAST_JSON = '::json'.freeze
|
|
70
|
+
Sequel::Deprecation.deprecate_constant(self, :CAST_JSON)
|
|
73
71
|
CAST_JSONB = '::jsonb'.freeze
|
|
72
|
+
Sequel::Deprecation.deprecate_constant(self, :CAST_JSONB)
|
|
74
73
|
|
|
75
74
|
# Class representing PostgreSQL JSON/JSONB column array values.
|
|
76
75
|
class JSONArrayBase < DelegateClass(Array)
|
|
@@ -88,7 +87,7 @@ module Sequel
|
|
|
88
87
|
# Cast as json
|
|
89
88
|
def sql_literal_append(ds, sql)
|
|
90
89
|
super
|
|
91
|
-
sql <<
|
|
90
|
+
sql << '::json'
|
|
92
91
|
end
|
|
93
92
|
end
|
|
94
93
|
|
|
@@ -96,7 +95,7 @@ module Sequel
|
|
|
96
95
|
# Cast as jsonb
|
|
97
96
|
def sql_literal_append(ds, sql)
|
|
98
97
|
super
|
|
99
|
-
sql <<
|
|
98
|
+
sql << '::jsonb'
|
|
100
99
|
end
|
|
101
100
|
end
|
|
102
101
|
|
|
@@ -119,7 +118,7 @@ module Sequel
|
|
|
119
118
|
# Cast as json
|
|
120
119
|
def sql_literal_append(ds, sql)
|
|
121
120
|
super
|
|
122
|
-
sql <<
|
|
121
|
+
sql << '::json'
|
|
123
122
|
end
|
|
124
123
|
end
|
|
125
124
|
|
|
@@ -127,7 +126,7 @@ module Sequel
|
|
|
127
126
|
# Cast as jsonb
|
|
128
127
|
def sql_literal_append(ds, sql)
|
|
129
128
|
super
|
|
130
|
-
sql <<
|
|
129
|
+
sql << '::jsonb'
|
|
131
130
|
end
|
|
132
131
|
end
|
|
133
132
|
|
|
@@ -135,7 +134,12 @@ module Sequel
|
|
|
135
134
|
module JSONDatabaseMethods
|
|
136
135
|
def self.extended(db)
|
|
137
136
|
db.instance_eval do
|
|
138
|
-
|
|
137
|
+
add_conversion_proc(114, JSONDatabaseMethods.method(:db_parse_json))
|
|
138
|
+
add_conversion_proc(3802, JSONDatabaseMethods.method(:db_parse_jsonb))
|
|
139
|
+
if respond_to?(:register_array_type)
|
|
140
|
+
register_array_type('json', :oid=>199, :scalar_oid=>114)
|
|
141
|
+
register_array_type('jsonb', :oid=>3807, :scalar_oid=>3802)
|
|
142
|
+
end
|
|
139
143
|
@schema_type_classes[:json] = [JSONHash, JSONArray]
|
|
140
144
|
@schema_type_classes[:jsonb] = [JSONBHash, JSONBArray]
|
|
141
145
|
end
|
|
@@ -257,11 +261,18 @@ module Sequel
|
|
|
257
261
|
end
|
|
258
262
|
end
|
|
259
263
|
|
|
260
|
-
|
|
261
|
-
|
|
264
|
+
# SEQUEL5: Remove
|
|
265
|
+
PG__TYPES[114] = lambda do |s|
|
|
266
|
+
Sequel::Deprecation.deprecate("Conversion proc for json added globally by pg_json extension", "Load the pg_json extension into the Database instance")
|
|
267
|
+
JSONDatabaseMethods.db_parse_json(s)
|
|
268
|
+
end
|
|
269
|
+
PG__TYPES[3802] = lambda do |s|
|
|
270
|
+
Sequel::Deprecation.deprecate("Conversion proc for jsonb added globally by pg_json extension", "Load the pg_json extension into the Database instance")
|
|
271
|
+
JSONDatabaseMethods.db_parse_jsonb(s)
|
|
272
|
+
end
|
|
262
273
|
if defined?(PGArray) && PGArray.respond_to?(:register)
|
|
263
|
-
PGArray.register('json', :oid=>199, :scalar_oid=>114)
|
|
264
|
-
PGArray.register('jsonb', :oid=>3807, :scalar_oid=>3802)
|
|
274
|
+
PGArray.register('json', :oid=>199, :scalar_oid=>114, :skip_deprecation_warning=>true)
|
|
275
|
+
PGArray.register('jsonb', :oid=>3807, :scalar_oid=>3802, :skip_deprecation_warning=>true)
|
|
265
276
|
end
|
|
266
277
|
end
|
|
267
278
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# The pg_json_ops extension adds support to Sequel's DSL to make
|
|
4
4
|
# it easier to call PostgreSQL JSON functions and operators (added
|
|
5
5
|
# first in PostgreSQL 9.3). It also supports the JSONB functions
|
|
6
|
-
# and operators added in PostgreSQL 9.4
|
|
6
|
+
# and operators added in PostgreSQL 9.4.
|
|
7
7
|
#
|
|
8
8
|
# To load the extension:
|
|
9
9
|
#
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
# jb = Sequel.pg_jsonb(:jsonb_column)
|
|
23
23
|
#
|
|
24
24
|
# Also, on most Sequel expression objects, you can call the pg_json
|
|
25
|
-
# or pg_jsonb
|
|
25
|
+
# or pg_jsonb method:
|
|
26
26
|
#
|
|
27
27
|
# j = Sequel[:json_column].pg_json
|
|
28
28
|
# jb = Sequel[:jsonb_column].pg_jsonb
|
|
@@ -40,10 +40,7 @@
|
|
|
40
40
|
# If you specify the range database type, Sequel will automatically cast
|
|
41
41
|
# the value to that type when literalizing.
|
|
42
42
|
#
|
|
43
|
-
#
|
|
44
|
-
# probably want to modify the schema parsing/typecasting so that it
|
|
45
|
-
# recognizes and correctly handles the range type columns, which you can
|
|
46
|
-
# do by:
|
|
43
|
+
# To use this extension, load it into the Database instance:
|
|
47
44
|
#
|
|
48
45
|
# DB.extension :pg_range
|
|
49
46
|
#
|
|
@@ -52,11 +49,10 @@
|
|
|
52
49
|
#
|
|
53
50
|
# This extension makes it easy to add support for other range types. In
|
|
54
51
|
# general, you just need to make sure that the subtype is handled and has the
|
|
55
|
-
# appropriate converter installed
|
|
56
|
-
# instance's conversion_procs usingthe appropriate type OID. For user defined
|
|
52
|
+
# appropriate converter installed. For user defined
|
|
57
53
|
# types, you can do this via:
|
|
58
54
|
#
|
|
59
|
-
# DB.
|
|
55
|
+
# DB.add_conversion_proc(subtype_oid){|string| }
|
|
60
56
|
#
|
|
61
57
|
# Then you can call
|
|
62
58
|
# Sequel::Postgres::PGRange::DatabaseMethods#register_range_type
|
|
@@ -66,18 +62,6 @@
|
|
|
66
62
|
#
|
|
67
63
|
# DB.register_range_type('timerange')
|
|
68
64
|
#
|
|
69
|
-
# You can also register range types on a global basis using
|
|
70
|
-
# Sequel::Postgres::PGRange.register. In this case, you'll have
|
|
71
|
-
# to specify the type oids:
|
|
72
|
-
#
|
|
73
|
-
# Sequel::Postgres::PG_TYPES[1234] = lambda{|string| }
|
|
74
|
-
# Sequel::Postgres::PGRange.register('foo', :oid=>4321, :subtype_oid=>1234)
|
|
75
|
-
#
|
|
76
|
-
# Both Sequel::Postgres::PGRange::DatabaseMethods#register_range_type
|
|
77
|
-
# and Sequel::Postgres::PGRange.register support many options to
|
|
78
|
-
# customize the range type handling. See the Sequel::Postgres::PGRange.register
|
|
79
|
-
# method documentation.
|
|
80
|
-
#
|
|
81
65
|
# This extension integrates with the pg_array extension. If you plan
|
|
82
66
|
# to use arrays of range types, load the pg_array extension before the
|
|
83
67
|
# pg_range extension:
|
|
@@ -86,54 +70,45 @@
|
|
|
86
70
|
#
|
|
87
71
|
# Related module: Sequel::Postgres::PGRange
|
|
88
72
|
|
|
89
|
-
Sequel.require 'adapters/
|
|
73
|
+
Sequel.require 'adapters/shared/postgres'
|
|
90
74
|
|
|
91
75
|
module Sequel
|
|
92
76
|
module Postgres
|
|
93
77
|
class PGRange
|
|
94
78
|
include Sequel::SQL::AliasMethods
|
|
95
79
|
|
|
96
|
-
#
|
|
97
|
-
# used in the schema parsing.
|
|
80
|
+
# SEQUEL5: Remove
|
|
98
81
|
RANGE_TYPES = {}
|
|
99
82
|
|
|
100
83
|
EMPTY = 'empty'.freeze
|
|
84
|
+
Sequel::Deprecation.deprecate_constant(self, :EMPTY)
|
|
101
85
|
EMPTY_STRING = ''.freeze
|
|
86
|
+
Sequel::Deprecation.deprecate_constant(self, :EMPTY_STRING)
|
|
102
87
|
COMMA = ','.freeze
|
|
88
|
+
Sequel::Deprecation.deprecate_constant(self, :COMMA)
|
|
103
89
|
QUOTED_EMPTY_STRING = '""'.freeze
|
|
90
|
+
Sequel::Deprecation.deprecate_constant(self, :QUOTED_EMPTY_STRING)
|
|
104
91
|
OPEN_PAREN = "(".freeze
|
|
92
|
+
Sequel::Deprecation.deprecate_constant(self, :OPEN_PAREN)
|
|
105
93
|
CLOSE_PAREN = ")".freeze
|
|
94
|
+
Sequel::Deprecation.deprecate_constant(self, :CLOSE_PAREN)
|
|
106
95
|
OPEN_BRACKET = "[".freeze
|
|
96
|
+
Sequel::Deprecation.deprecate_constant(self, :OPEN_BRACKET)
|
|
107
97
|
CLOSE_BRACKET = "]".freeze
|
|
98
|
+
Sequel::Deprecation.deprecate_constant(self, :CLOSE_BRACKET)
|
|
108
99
|
ESCAPE_RE = /("|,|\\|\[|\]|\(|\))/.freeze
|
|
100
|
+
Sequel::Deprecation.deprecate_constant(self, :ESCAPE_RE)
|
|
109
101
|
ESCAPE_REPLACE = '\\\\\1'.freeze
|
|
102
|
+
Sequel::Deprecation.deprecate_constant(self, :ESCAPE_REPLACE)
|
|
110
103
|
CAST = '::'.freeze
|
|
104
|
+
Sequel::Deprecation.deprecate_constant(self, :CAST)
|
|
111
105
|
|
|
112
|
-
#
|
|
113
|
-
# has been extended with DatabaseMethods recognize the range type given and set up the
|
|
114
|
-
# appropriate typecasting. Also sets up automatic typecasting for the native postgres
|
|
115
|
-
# adapter, so that on retrieval, the values are automatically converted to PGRange instances.
|
|
116
|
-
# The db_type argument should be the name of the range type. Accepts the following options:
|
|
117
|
-
#
|
|
118
|
-
# :converter :: A callable object (e.g. Proc), that is called with the start or end of the range
|
|
119
|
-
# (usually a string), and should return the appropriate typecasted object.
|
|
120
|
-
# :oid :: The PostgreSQL OID for the range type. This is used by the Sequel postgres adapter
|
|
121
|
-
# to set up automatic type conversion on retrieval from the database.
|
|
122
|
-
# :subtype_oid :: Should be the PostgreSQL OID for the range's subtype. If given,
|
|
123
|
-
# automatically sets the :converter option by looking for scalar conversion
|
|
124
|
-
# proc.
|
|
125
|
-
# :type_procs :: A hash mapping oids to conversion procs, used for setting the default :converter
|
|
126
|
-
# for :subtype_oid. Defaults to the global Sequel::Postgres::PG_TYPES.
|
|
127
|
-
# :typecast_method_map :: The map in which to place the database type string to type symbol mapping.
|
|
128
|
-
# Defaults to RANGE_TYPES.
|
|
129
|
-
# :typecast_methods_module :: If given, a module object to add the typecasting method to. Defaults
|
|
130
|
-
# to DatabaseMethods.
|
|
131
|
-
#
|
|
132
|
-
# If a block is given, it is treated as the :converter option.
|
|
106
|
+
# SEQUEL5: Remove
|
|
133
107
|
def self.register(db_type, opts=OPTS, &block)
|
|
108
|
+
Sequel::Deprecation.deprecate("Sequel::Postgres::PGRange.register", "Use Database#register_range_type on a Database instance using the pg_range extension") unless opts[:skip_deprecation_warning]
|
|
134
109
|
db_type = db_type.to_s.dup.freeze
|
|
135
110
|
|
|
136
|
-
type_procs = opts[:type_procs] ||
|
|
111
|
+
type_procs = opts[:type_procs] || PG__TYPES
|
|
137
112
|
mod = opts[:typecast_methods_module] || DatabaseMethods
|
|
138
113
|
typecast_method_map = opts[:typecast_method_map] || RANGE_TYPES
|
|
139
114
|
|
|
@@ -155,14 +130,19 @@ module Sequel
|
|
|
155
130
|
define_range_typecast_method(mod, db_type, parser)
|
|
156
131
|
|
|
157
132
|
if oid = opts[:oid]
|
|
133
|
+
if opts[:skip_deprecation_warning]
|
|
134
|
+
def parser.call(s)
|
|
135
|
+
Sequel::Deprecation.deprecate("Conversion proc for #{db_type} added globally by pg_range extension", "Load the pg_range extension into the Database instance")
|
|
136
|
+
super
|
|
137
|
+
end
|
|
138
|
+
end
|
|
158
139
|
type_procs[oid] = parser
|
|
159
140
|
end
|
|
160
141
|
|
|
161
142
|
nil
|
|
162
143
|
end
|
|
163
144
|
|
|
164
|
-
#
|
|
165
|
-
# the parser argument to do the type conversion.
|
|
145
|
+
# SEQUEL5: Remove
|
|
166
146
|
def self.define_range_typecast_method(mod, type, parser)
|
|
167
147
|
mod.class_eval do
|
|
168
148
|
meth = :"typecast_value_#{type}"
|
|
@@ -174,12 +154,12 @@ module Sequel
|
|
|
174
154
|
|
|
175
155
|
# Creates callable objects that convert strings into PGRange instances.
|
|
176
156
|
class Parser
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
PARSER = /\A(\[|\()("((?:\\"|[^"])*)"|[^"]*),("((?:\\"|[^"])*)"|[^"]*)(\]|\))\z/o
|
|
180
|
-
|
|
157
|
+
PARSER = /\A(\[|\()("((?:\\"|[^"])*)"|[^"]*),("((?:\\"|[^"])*)"|[^"]*)(\]|\))\z/
|
|
158
|
+
Sequel::Deprecation.deprecate_constant(self, :PARSER)
|
|
181
159
|
REPLACE_RE = /\\(.)/.freeze
|
|
160
|
+
Sequel::Deprecation.deprecate_constant(self, :REPLACE_RE)
|
|
182
161
|
REPLACE_WITH = '\1'.freeze
|
|
162
|
+
Sequel::Deprecation.deprecate_constant(self, :REPLACE_WITH)
|
|
183
163
|
|
|
184
164
|
# The database range type for this parser (e.g. 'int4range'),
|
|
185
165
|
# automatically setting the db_type for the returned PGRange instances.
|
|
@@ -197,11 +177,11 @@ module Sequel
|
|
|
197
177
|
|
|
198
178
|
# Parse the range type input string into a PGRange value.
|
|
199
179
|
def call(string)
|
|
200
|
-
if string ==
|
|
180
|
+
if string == 'empty'
|
|
201
181
|
return PGRange.empty(db_type)
|
|
202
182
|
end
|
|
203
183
|
|
|
204
|
-
raise(InvalidValue, "invalid or unhandled range format: #{string.inspect}") unless matches =
|
|
184
|
+
raise(InvalidValue, "invalid or unhandled range format: #{string.inspect}") unless matches = /\A(\[|\()("((?:\\"|[^"])*)"|[^"]*),("((?:\\"|[^"])*)"|[^"]*)(\]|\))\z/.match(string)
|
|
205
185
|
|
|
206
186
|
exclude_begin = matches[1] == '('
|
|
207
187
|
exclude_end = matches[6] == ')'
|
|
@@ -215,12 +195,12 @@ module Sequel
|
|
|
215
195
|
# to always use the quoted output form when characters need to be escaped, so
|
|
216
196
|
# there isn't a need to unescape unquoted output.
|
|
217
197
|
if beg = matches[3]
|
|
218
|
-
beg.gsub!(
|
|
198
|
+
beg.gsub!(/\\(.)/, '\1')
|
|
219
199
|
else
|
|
220
200
|
beg = matches[2] unless matches[2].empty?
|
|
221
201
|
end
|
|
222
202
|
if en = matches[5]
|
|
223
|
-
en.gsub!(
|
|
203
|
+
en.gsub!(/\\(.)/, '\1')
|
|
224
204
|
else
|
|
225
205
|
en = matches[4] unless matches[4].empty?
|
|
226
206
|
end
|
|
@@ -241,20 +221,32 @@ module Sequel
|
|
|
241
221
|
db.instance_eval do
|
|
242
222
|
@pg_range_schema_types ||= {}
|
|
243
223
|
extend_datasets(DatasetMethods)
|
|
244
|
-
|
|
224
|
+
register_range_type('int4range', :oid=>3904, :subtype_oid=>23)
|
|
225
|
+
register_range_type('numrange', :oid=>3906, :subtype_oid=>1700)
|
|
226
|
+
register_range_type('tsrange', :oid=>3908, :subtype_oid=>1114)
|
|
227
|
+
register_range_type('tstzrange', :oid=>3910, :subtype_oid=>1184)
|
|
228
|
+
register_range_type('daterange', :oid=>3912, :subtype_oid=>1082)
|
|
229
|
+
register_range_type('int8range', :oid=>3926, :subtype_oid=>20)
|
|
230
|
+
if respond_to?(:register_array_type)
|
|
231
|
+
register_array_type('int4range', :oid=>3905, :scalar_oid=>3904, :scalar_typecast=>:int4range)
|
|
232
|
+
register_array_type('numrange', :oid=>3907, :scalar_oid=>3906, :scalar_typecast=>:numrange)
|
|
233
|
+
register_array_type('tsrange', :oid=>3909, :scalar_oid=>3908, :scalar_typecast=>:tsrange)
|
|
234
|
+
register_array_type('tstzrange', :oid=>3911, :scalar_oid=>3910, :scalar_typecast=>:tstzrange)
|
|
235
|
+
register_array_type('daterange', :oid=>3913, :scalar_oid=>3912, :scalar_typecast=>:daterange)
|
|
236
|
+
register_array_type('int8range', :oid=>3927, :scalar_oid=>3926, :scalar_typecast=>:int8range)
|
|
237
|
+
end
|
|
245
238
|
[:int4range, :numrange, :tsrange, :tstzrange, :daterange, :int8range].each do |v|
|
|
246
239
|
@schema_type_classes[v] = PGRange
|
|
247
240
|
end
|
|
248
|
-
end
|
|
249
241
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
242
|
+
procs = conversion_procs
|
|
243
|
+
add_conversion_proc(3908, Parser.new("tsrange", procs[1114]))
|
|
244
|
+
add_conversion_proc(3910, Parser.new("tstzrange", procs[1184]))
|
|
245
|
+
if defined?(PGArray::Creator)
|
|
246
|
+
add_conversion_proc(3909, PGArray::Creator.new("tsrange", procs[3908]))
|
|
247
|
+
add_conversion_proc(3911, PGArray::Creator.new("tstzrange", procs[3910]))
|
|
248
|
+
end
|
|
256
249
|
end
|
|
257
|
-
|
|
258
250
|
end
|
|
259
251
|
|
|
260
252
|
# Handle Range and PGRange values in bound variables
|
|
@@ -276,20 +268,62 @@ module Sequel
|
|
|
276
268
|
end
|
|
277
269
|
|
|
278
270
|
# Register a database specific range type. This can be used to support
|
|
279
|
-
# different range types per Database.
|
|
280
|
-
#
|
|
281
|
-
#
|
|
271
|
+
# different range types per Database. Options:
|
|
272
|
+
#
|
|
273
|
+
# :converter :: A callable object (e.g. Proc), that is called with the start or end of the range
|
|
274
|
+
# (usually a string), and should return the appropriate typecasted object.
|
|
275
|
+
# :oid :: The PostgreSQL OID for the range type. This is used by the Sequel postgres adapter
|
|
276
|
+
# to set up automatic type conversion on retrieval from the database.
|
|
277
|
+
# :subtype_oid :: Should be the PostgreSQL OID for the range's subtype. If given,
|
|
278
|
+
# automatically sets the :converter option by looking for scalar conversion
|
|
279
|
+
# proc.
|
|
280
|
+
#
|
|
281
|
+
# If a block is given, it is treated as the :converter option.
|
|
282
282
|
def register_range_type(db_type, opts=OPTS, &block)
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
oid = opts[:oid]
|
|
284
|
+
soid = opts[:subtype_oid]
|
|
285
|
+
|
|
286
|
+
if has_converter = opts.has_key?(:converter)
|
|
287
|
+
raise Error, "can't provide both a block and :converter option to register_range_type" if block
|
|
288
|
+
converter = opts[:converter]
|
|
289
|
+
else
|
|
290
|
+
has_converter = true if block
|
|
291
|
+
converter = block
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
unless (soid || has_converter) && oid
|
|
285
295
|
range_oid, subtype_oid = from(:pg_range).join(:pg_type, :oid=>:rngtypid).where(:typname=>db_type.to_s).get([:rngtypid, :rngsubtype])
|
|
286
|
-
|
|
287
|
-
|
|
296
|
+
soid ||= subtype_oid unless has_converter
|
|
297
|
+
oid ||= range_oid
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
db_type = db_type.to_s.dup.freeze
|
|
301
|
+
|
|
302
|
+
if converter = opts[:converter]
|
|
303
|
+
raise Error, "can't provide both a block and :converter option to register" if block
|
|
304
|
+
else
|
|
305
|
+
converter = block
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
if soid
|
|
309
|
+
raise Error, "can't provide both a converter and :subtype_oid option to register" if has_converter
|
|
310
|
+
raise Error, "no conversion proc for :subtype_oid=>#{soid.inspect} in conversion_procs" unless converter = conversion_procs[soid]
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
parser = Parser.new(db_type, converter)
|
|
314
|
+
add_conversion_proc(oid, parser)
|
|
315
|
+
|
|
316
|
+
@pg_range_schema_types[db_type] = db_type.to_sym
|
|
317
|
+
|
|
318
|
+
(class << self; self end).class_eval do
|
|
319
|
+
meth = :"typecast_value_#{db_type}"
|
|
320
|
+
define_method(meth){|v| typecast_value_pg_range(v, parser)}
|
|
321
|
+
private meth
|
|
288
322
|
end
|
|
289
323
|
|
|
290
|
-
PGRange.register(db_type, opts, &block)
|
|
291
324
|
@schema_type_classes[:"#{opts[:type_symbol] || db_type}"] = PGRange
|
|
292
|
-
conversion_procs_updated
|
|
325
|
+
conversion_procs_updated # SEQUEL5: Remove
|
|
326
|
+
nil
|
|
293
327
|
end
|
|
294
328
|
|
|
295
329
|
private
|
|
@@ -304,9 +338,7 @@ module Sequel
|
|
|
304
338
|
end
|
|
305
339
|
end
|
|
306
340
|
|
|
307
|
-
#
|
|
308
|
-
# they use the database's timezone instead of the global Sequel
|
|
309
|
-
# timezone.
|
|
341
|
+
# SEQUEL5: Remove
|
|
310
342
|
def get_conversion_procs
|
|
311
343
|
procs = super
|
|
312
344
|
|
|
@@ -322,7 +354,7 @@ module Sequel
|
|
|
322
354
|
|
|
323
355
|
# Recognize the registered database range types.
|
|
324
356
|
def schema_column_type(db_type)
|
|
325
|
-
if type = @pg_range_schema_types[db_type] || RANGE_TYPES[db_type]
|
|
357
|
+
if type = @pg_range_schema_types[db_type] || RANGE_TYPES[db_type] # SEQUEL5: Remove || RANGE_TYPES[db_type]
|
|
326
358
|
type
|
|
327
359
|
else
|
|
328
360
|
super
|
|
@@ -490,17 +522,17 @@ module Sequel
|
|
|
490
522
|
# Append a literalize version of the receiver to the sql.
|
|
491
523
|
def sql_literal_append(ds, sql)
|
|
492
524
|
if (s = @db_type) && !empty?
|
|
493
|
-
sql << s.to_s <<
|
|
525
|
+
sql << s.to_s << "("
|
|
494
526
|
ds.literal_append(sql, self.begin)
|
|
495
|
-
sql <<
|
|
527
|
+
sql << ','
|
|
496
528
|
ds.literal_append(sql, self.end)
|
|
497
|
-
sql <<
|
|
498
|
-
ds.literal_append(sql, "#{exclude_begin? ?
|
|
499
|
-
sql <<
|
|
529
|
+
sql << ','
|
|
530
|
+
ds.literal_append(sql, "#{exclude_begin? ? "(" : "["}#{exclude_end? ? ")" : "]"}")
|
|
531
|
+
sql << ")"
|
|
500
532
|
else
|
|
501
533
|
ds.literal_append(sql, unquoted_literal(ds))
|
|
502
534
|
if s
|
|
503
|
-
sql <<
|
|
535
|
+
sql << '::' << s.to_s
|
|
504
536
|
end
|
|
505
537
|
end
|
|
506
538
|
end
|
|
@@ -536,9 +568,9 @@ module Sequel
|
|
|
536
568
|
# Separated out for use by the bound argument code.
|
|
537
569
|
def unquoted_literal(ds)
|
|
538
570
|
if empty?
|
|
539
|
-
|
|
571
|
+
'empty'
|
|
540
572
|
else
|
|
541
|
-
"#{exclude_begin? ?
|
|
573
|
+
"#{exclude_begin? ? "(" : "["}#{escape_value(self.begin, ds)},#{escape_value(self.end, ds)}#{exclude_end? ? ")" : "]"}"
|
|
542
574
|
end
|
|
543
575
|
end
|
|
544
576
|
|
|
@@ -549,7 +581,7 @@ module Sequel
|
|
|
549
581
|
def escape_value(k, ds)
|
|
550
582
|
case k
|
|
551
583
|
when nil
|
|
552
|
-
|
|
584
|
+
''
|
|
553
585
|
when Date, Time
|
|
554
586
|
ds.literal(k)[1...-1]
|
|
555
587
|
when Integer, Float
|
|
@@ -560,29 +592,30 @@ module Sequel
|
|
|
560
592
|
k
|
|
561
593
|
when String
|
|
562
594
|
if k.empty?
|
|
563
|
-
|
|
595
|
+
'""'
|
|
564
596
|
else
|
|
565
|
-
k.gsub(
|
|
597
|
+
k.gsub(/("|,|\\|\[|\]|\(|\))/, '\\\\\1')
|
|
566
598
|
end
|
|
567
599
|
else
|
|
568
|
-
ds.literal(k).gsub(
|
|
600
|
+
ds.literal(k).gsub(/("|,|\\|\[|\]|\(|\))/, '\\\\\1')
|
|
569
601
|
end
|
|
570
602
|
end
|
|
571
603
|
end
|
|
572
604
|
|
|
573
|
-
|
|
574
|
-
PGRange.register('
|
|
575
|
-
PGRange.register('
|
|
576
|
-
PGRange.register('
|
|
577
|
-
PGRange.register('
|
|
578
|
-
PGRange.register('
|
|
605
|
+
# SEQUEL5: Remove
|
|
606
|
+
PGRange.register('int4range', :oid=>3904, :subtype_oid=>23, :skip_deprecation_warning=>true)
|
|
607
|
+
PGRange.register('numrange', :oid=>3906, :subtype_oid=>1700, :skip_deprecation_warning=>true)
|
|
608
|
+
PGRange.register('tsrange', :oid=>3908, :subtype_oid=>1114, :skip_deprecation_warning=>true)
|
|
609
|
+
PGRange.register('tstzrange', :oid=>3910, :subtype_oid=>1184, :skip_deprecation_warning=>true)
|
|
610
|
+
PGRange.register('daterange', :oid=>3912, :subtype_oid=>1082, :skip_deprecation_warning=>true)
|
|
611
|
+
PGRange.register('int8range', :oid=>3926, :subtype_oid=>20, :skip_deprecation_warning=>true)
|
|
579
612
|
if defined?(PGArray) && PGArray.respond_to?(:register)
|
|
580
|
-
PGArray.register('int4range', :oid=>3905, :scalar_oid=>3904, :scalar_typecast=>:int4range)
|
|
581
|
-
PGArray.register('numrange', :oid=>3907, :scalar_oid=>3906, :scalar_typecast=>:numrange)
|
|
582
|
-
PGArray.register('tsrange', :oid=>3909, :scalar_oid=>3908, :scalar_typecast=>:tsrange)
|
|
583
|
-
PGArray.register('tstzrange', :oid=>3911, :scalar_oid=>3910, :scalar_typecast=>:tstzrange)
|
|
584
|
-
PGArray.register('daterange', :oid=>3913, :scalar_oid=>3912, :scalar_typecast=>:daterange)
|
|
585
|
-
PGArray.register('int8range', :oid=>3927, :scalar_oid=>3926, :scalar_typecast=>:int8range)
|
|
613
|
+
PGArray.register('int4range', :oid=>3905, :scalar_oid=>3904, :scalar_typecast=>:int4range, :skip_deprecation_warning=>true)
|
|
614
|
+
PGArray.register('numrange', :oid=>3907, :scalar_oid=>3906, :scalar_typecast=>:numrange, :skip_deprecation_warning=>true)
|
|
615
|
+
PGArray.register('tsrange', :oid=>3909, :scalar_oid=>3908, :scalar_typecast=>:tsrange, :skip_deprecation_warning=>true)
|
|
616
|
+
PGArray.register('tstzrange', :oid=>3911, :scalar_oid=>3910, :scalar_typecast=>:tstzrange, :skip_deprecation_warning=>true)
|
|
617
|
+
PGArray.register('daterange', :oid=>3913, :scalar_oid=>3912, :scalar_typecast=>:daterange, :skip_deprecation_warning=>true)
|
|
618
|
+
PGArray.register('int8range', :oid=>3927, :scalar_oid=>3926, :scalar_typecast=>:int8range, :skip_deprecation_warning=>true)
|
|
586
619
|
end
|
|
587
620
|
end
|
|
588
621
|
|