sequel 5.60.0 → 5.61.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 +16 -0
- data/doc/release_notes/5.61.0.txt +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc.rb +5 -5
- data/lib/sequel/adapters/mock.rb +1 -1
- data/lib/sequel/adapters/mysql.rb +3 -3
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/ast_transformer.rb +1 -1
- data/lib/sequel/database/misc.rb +56 -12
- data/lib/sequel/dataset/sql.rb +2 -2
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/pg_array.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +1 -1
- data/lib/sequel/extensions/pg_enum.rb +1 -1
- data/lib/sequel/extensions/pg_extended_date_support.rb +15 -24
- data/lib/sequel/extensions/pg_hstore_ops.rb +3 -3
- data/lib/sequel/extensions/pg_inet.rb +3 -3
- data/lib/sequel/extensions/pg_interval.rb +2 -2
- data/lib/sequel/extensions/pg_json.rb +1 -1
- data/lib/sequel/extensions/pg_json_ops.rb +3 -55
- data/lib/sequel/extensions/pg_multirange.rb +2 -2
- data/lib/sequel/extensions/pg_range.rb +3 -3
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
- data/lib/sequel/model/associations.rb +6 -6
- data/lib/sequel/model/base.rb +3 -3
- data/lib/sequel/model/exceptions.rb +1 -1
- data/lib/sequel/model/inflections.rb +6 -6
- data/lib/sequel/plugins/auto_validations.rb +1 -1
- data/lib/sequel/plugins/defaults_setter.rb +1 -1
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/insert_conflict.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +1 -1
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +1 -1
- data/lib/sequel/plugins/validation_class_methods.rb +3 -3
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f542d5f0e7cca642a8fccd52cb4099101f38dbd1617ff2437b8690766b5f2bdd
|
|
4
|
+
data.tar.gz: 79ff2215f1e38e523e7e64a5779bee695a939a03f046a5e2e9a5974a804a714c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e0bdc80d388f1bdbf39674624522f7086ca5b0904df2bb28d7b6f3c8f6057df38eca1c0854905a87d920286e578d1e0fe269deb33c3c3f1691d2113a9f23d11
|
|
7
|
+
data.tar.gz: 31ebb15cc504b82c5406c2f7eb6a02a99aa035e9486ecd52698403eff7bd79a99e606229dbbf392ac3fabd1b68c9a7ebc09c127dea3970e2a083c7d781159f33
|
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
=== 5.61.0 (2022-10-01)
|
|
2
|
+
|
|
3
|
+
* Make Database#foreign_key_list on PostgreSQL return results for partitioned tables (jeremyevans)
|
|
4
|
+
|
|
5
|
+
* Add Database#check_string_typecast_bytesize for checking bytesize of strings before typecasting (jeremyevans)
|
|
6
|
+
|
|
7
|
+
* Treat negative hexidecimal strings similar to positive hexidecimal strings when typecasting to integer (jeremyevans)
|
|
8
|
+
|
|
9
|
+
* Remove is_json and is_not_json methods from the pg_json_ops extension, as the support was removed in PostgreSQL 15 beta 4 (jeremyevans)
|
|
10
|
+
|
|
11
|
+
* Fix handling of timestamps before the date of calendar reform when using pg_extended_date_support extension on Ruby 3.2 (jeremyevans)
|
|
12
|
+
|
|
13
|
+
=== 5.60.1 (2022-09-02)
|
|
14
|
+
|
|
15
|
+
* Revert conversion of respond_to? to defined?, as it breaks with unused refinements on Ruby 2 (jeremyevans) (#1919)
|
|
16
|
+
|
|
1
17
|
=== 5.60.0 (2022-09-01)
|
|
2
18
|
|
|
3
19
|
* Support arbitrary expressions for date_arithmetic interval values on PostgreSQL 9.4+ (jeremyevans)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
= Improvements
|
|
2
|
+
|
|
3
|
+
* When typecasting strings to other types, Sequel::Database will now
|
|
4
|
+
by default not typecast strings that are much longer than expected
|
|
5
|
+
for the underlying type. Depending on the underlying type, there
|
|
6
|
+
is a limit of either 100 or 1000 bytes on the input string. This
|
|
7
|
+
avoids potential performance issues when trying to convert
|
|
8
|
+
arbitrary sized user input to specific types.
|
|
9
|
+
|
|
10
|
+
* The respond_to? to defined? change made in 5.60.0 was reverted in
|
|
11
|
+
5.60.1 as it broke cases on Ruby < 3 where the object had an unused
|
|
12
|
+
refinement that added the method.
|
|
13
|
+
|
|
14
|
+
* When typecasting strings to integer, strings such as -0xa are now
|
|
15
|
+
treated as negative hexidecimal strings, similar to how 0xa is
|
|
16
|
+
treated as a positive hexidecimal string.
|
|
17
|
+
|
|
18
|
+
* Database#foreign_key_list now returns results for partitioned
|
|
19
|
+
tables on PostgreSQL 11+.
|
|
20
|
+
|
|
21
|
+
* Timestamps before the date of calendar reform are now handled
|
|
22
|
+
correctly by the pg_extended_date_support extension when using
|
|
23
|
+
Ruby 3.2 preview 2+.
|
|
24
|
+
|
|
25
|
+
= Backwards Compatibility
|
|
26
|
+
|
|
27
|
+
* The change to not typecast strings that are too long can break
|
|
28
|
+
backwards compatibility for applications that expect typecasting
|
|
29
|
+
for input beyond Sequel's limits. You can disable the string
|
|
30
|
+
bytesize checking by setting:
|
|
31
|
+
|
|
32
|
+
DB.check_string_typecast_bytesize = false
|
|
33
|
+
|
|
34
|
+
or by passing the check_string_typecast_bytesize: false option when
|
|
35
|
+
creating the Database instance.
|
|
36
|
+
|
|
37
|
+
* Code to workaround a bug in JRuby 9.2.0.0 has been removed from the
|
|
38
|
+
pg_extended_date_support extension. Users of the extension should
|
|
39
|
+
upgrade to a newer JRuby version.
|
|
40
|
+
|
|
41
|
+
* The is_json and is_not_json methods have been removed from the
|
|
42
|
+
pg_json_ops extension, as the underlying support was removed in
|
|
43
|
+
PostgreSQL 15 beta 4.
|
|
@@ -125,7 +125,7 @@ module Sequel
|
|
|
125
125
|
|
|
126
126
|
# The result code for the exception, if the jdbc driver supports result codes for exceptions.
|
|
127
127
|
def sqlite_error_code(exception)
|
|
128
|
-
exception.resultCode.code if
|
|
128
|
+
exception.resultCode.code if exception.respond_to?(:resultCode)
|
|
129
129
|
end
|
|
130
130
|
end
|
|
131
131
|
end
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Sequel
|
|
|
38
38
|
else
|
|
39
39
|
if defined?(::Jdbc) && ( ::Jdbc.const_defined?(name) rescue nil )
|
|
40
40
|
jdbc_module = ::Jdbc.const_get(name) # e.g. Jdbc::SQLite3
|
|
41
|
-
jdbc_module.load_driver if
|
|
41
|
+
jdbc_module.load_driver if jdbc_module.respond_to?(:load_driver)
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
@@ -396,9 +396,9 @@ module Sequel
|
|
|
396
396
|
|
|
397
397
|
def database_exception_sqlstate(exception, opts)
|
|
398
398
|
if database_exception_use_sqlstates?
|
|
399
|
-
while
|
|
399
|
+
while exception.respond_to?(:cause)
|
|
400
400
|
exception = exception.cause
|
|
401
|
-
return exception.getSQLState if
|
|
401
|
+
return exception.getSQLState if exception.respond_to?(:getSQLState)
|
|
402
402
|
end
|
|
403
403
|
end
|
|
404
404
|
nil
|
|
@@ -415,8 +415,8 @@ module Sequel
|
|
|
415
415
|
|
|
416
416
|
# Raise a disconnect error if the SQL state of the cause of the exception indicates so.
|
|
417
417
|
def disconnect_error?(exception, opts)
|
|
418
|
-
cause =
|
|
419
|
-
super || (
|
|
418
|
+
cause = exception.respond_to?(:cause) ? exception.cause : exception
|
|
419
|
+
super || (cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/)
|
|
420
420
|
end
|
|
421
421
|
|
|
422
422
|
# Execute the prepared statement. If the provided name is a
|
data/lib/sequel/adapters/mock.rb
CHANGED
|
@@ -72,7 +72,7 @@ module Sequel
|
|
|
72
72
|
def connect(server)
|
|
73
73
|
opts = server_opts(server)
|
|
74
74
|
|
|
75
|
-
if
|
|
75
|
+
if Mysql.respond_to?(:init)
|
|
76
76
|
conn = Mysql.init
|
|
77
77
|
conn.options(Mysql::READ_DEFAULT_GROUP, opts[:config_default_group] || "client")
|
|
78
78
|
conn.options(Mysql::OPT_LOCAL_INFILE, opts[:config_local_infile]) if opts.has_key?(:config_local_infile)
|
|
@@ -186,7 +186,7 @@ module Sequel
|
|
|
186
186
|
elsif defined?(yield)
|
|
187
187
|
yield conn
|
|
188
188
|
end
|
|
189
|
-
if
|
|
189
|
+
if conn.respond_to?(:more_results?)
|
|
190
190
|
while conn.more_results? do
|
|
191
191
|
if r
|
|
192
192
|
r.free
|
|
@@ -207,7 +207,7 @@ module Sequel
|
|
|
207
207
|
ensure
|
|
208
208
|
r.free if r
|
|
209
209
|
# Use up all results to avoid a commands out of sync message.
|
|
210
|
-
if
|
|
210
|
+
if conn.respond_to?(:more_results?)
|
|
211
211
|
while conn.more_results? do
|
|
212
212
|
begin
|
|
213
213
|
conn.next_result
|
|
@@ -149,7 +149,7 @@ module Sequel
|
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
def database_specific_error_class(exception, opts)
|
|
152
|
-
return super unless
|
|
152
|
+
return super unless exception.respond_to?(:code)
|
|
153
153
|
case exception.code
|
|
154
154
|
when 1400, 1407
|
|
155
155
|
NotNullConstraintViolation
|
|
@@ -160,7 +160,7 @@ module Sequel
|
|
|
160
160
|
begin
|
|
161
161
|
defined?(yield) ? yield(q) : q.cmd_tuples
|
|
162
162
|
ensure
|
|
163
|
-
q.clear if q &&
|
|
163
|
+
q.clear if q && q.respond_to?(:clear)
|
|
164
164
|
end
|
|
165
165
|
end
|
|
166
166
|
|
|
@@ -258,7 +258,7 @@ module Sequel
|
|
|
258
258
|
|
|
259
259
|
# :nocov:
|
|
260
260
|
if encoding = opts[:encoding] || opts[:charset]
|
|
261
|
-
if
|
|
261
|
+
if conn.respond_to?(:set_client_encoding)
|
|
262
262
|
conn.set_client_encoding(encoding)
|
|
263
263
|
else
|
|
264
264
|
conn.async_exec("set client_encoding to '#{encoding}'")
|
|
@@ -492,12 +492,12 @@ module Sequel
|
|
|
492
492
|
opts[:after_listen].call(conn) if opts[:after_listen]
|
|
493
493
|
timeout = opts[:timeout]
|
|
494
494
|
if timeout
|
|
495
|
-
timeout_block =
|
|
495
|
+
timeout_block = timeout.respond_to?(:call) ? timeout : proc{timeout}
|
|
496
496
|
end
|
|
497
497
|
|
|
498
498
|
if l = opts[:loop]
|
|
499
499
|
raise Error, 'calling #listen with :loop requires a block' unless block
|
|
500
|
-
loop_call =
|
|
500
|
+
loop_call = l.respond_to?(:call)
|
|
501
501
|
catch(:stop) do
|
|
502
502
|
while true
|
|
503
503
|
t = timeout_block ? [timeout_block.call] : []
|
|
@@ -582,7 +582,7 @@ module Sequel
|
|
|
582
582
|
|
|
583
583
|
def database_exception_sqlstate(exception, opts)
|
|
584
584
|
# :nocov:
|
|
585
|
-
if
|
|
585
|
+
if exception.respond_to?(:result) && (result = exception.result)
|
|
586
586
|
# :nocov:
|
|
587
587
|
result.error_field(PGresult::PG_DIAG_SQLSTATE)
|
|
588
588
|
end
|
|
@@ -625,7 +625,7 @@ module Sequel
|
|
|
625
625
|
begin
|
|
626
626
|
defined?(yield) ? yield(q) : q.cmd_tuples
|
|
627
627
|
ensure
|
|
628
|
-
q.clear if q &&
|
|
628
|
+
q.clear if q && q.respond_to?(:clear)
|
|
629
629
|
end
|
|
630
630
|
end
|
|
631
631
|
|
|
@@ -205,7 +205,7 @@ module Sequel
|
|
|
205
205
|
return @server_version = Integer(@opts[:server_version])
|
|
206
206
|
end
|
|
207
207
|
@server_version = synchronize(server) do |conn|
|
|
208
|
-
(conn.server_version rescue nil) if
|
|
208
|
+
(conn.server_version rescue nil) if conn.respond_to?(:server_version)
|
|
209
209
|
end
|
|
210
210
|
unless @server_version
|
|
211
211
|
m = /^(\d+)\.(\d+)\.(\d+)/.match(fetch("SELECT CAST(SERVERPROPERTY('ProductVersion') AS varchar)").single_value.to_s)
|
|
@@ -121,7 +121,7 @@ module Sequel
|
|
|
121
121
|
def server_version(server=nil)
|
|
122
122
|
return @server_version if @server_version
|
|
123
123
|
@server_version = synchronize(server) do |conn|
|
|
124
|
-
(conn.server_version rescue nil) if
|
|
124
|
+
(conn.server_version rescue nil) if conn.respond_to?(:server_version)
|
|
125
125
|
end
|
|
126
126
|
unless @server_version
|
|
127
127
|
@server_version = if m = /(\d+)\.(\d+)\.?(\d+)?\.?(\d+)?/.match(fetch("select version from PRODUCT_COMPONENT_VERSION where lower(product) like 'oracle%'").single_value)
|
|
@@ -305,7 +305,7 @@ module Sequel
|
|
|
305
305
|
if USE_EXTENDED_RESULT_CODES
|
|
306
306
|
# Support SQLite exception codes if ruby-sqlite3 supports them.
|
|
307
307
|
def sqlite_error_code(exception)
|
|
308
|
-
exception.code if
|
|
308
|
+
exception.code if exception.respond_to?(:code)
|
|
309
309
|
end
|
|
310
310
|
end
|
|
311
311
|
end
|
data/lib/sequel/database/misc.rb
CHANGED
|
@@ -91,6 +91,11 @@ module Sequel
|
|
|
91
91
|
# The specific default size of string columns for this Sequel::Database, usually 255 by default.
|
|
92
92
|
attr_accessor :default_string_column_size
|
|
93
93
|
|
|
94
|
+
# Whether to check the bytesize of strings before typecasting (to avoid typecasting strings that
|
|
95
|
+
# would be too long for the given type), true by default. Strings that are too long will raise
|
|
96
|
+
# a typecasting error.
|
|
97
|
+
attr_accessor :check_string_typecast_bytesize
|
|
98
|
+
|
|
94
99
|
# Constructs a new instance of a database connection with the specified
|
|
95
100
|
# options hash.
|
|
96
101
|
#
|
|
@@ -98,6 +103,7 @@ module Sequel
|
|
|
98
103
|
# :before_preconnect :: Callable that runs after extensions from :preconnect_extensions are loaded,
|
|
99
104
|
# but before any connections are created.
|
|
100
105
|
# :cache_schema :: Whether schema should be cached for this Database instance
|
|
106
|
+
# :check_string_typecast_bytesize :: Whether to check the bytesize of strings before typecasting.
|
|
101
107
|
# :default_string_column_size :: The default size of string columns, 255 by default.
|
|
102
108
|
# :extensions :: Extensions to load into this Database instance. Can be a symbol, array of symbols,
|
|
103
109
|
# or string with extensions separated by columns. These extensions are loaded after
|
|
@@ -107,7 +113,7 @@ module Sequel
|
|
|
107
113
|
# :loggers :: An array of loggers to use.
|
|
108
114
|
# :log_connection_info :: Whether connection information should be logged when logging queries.
|
|
109
115
|
# :log_warn_duration :: The number of elapsed seconds after which queries should be logged at warn level.
|
|
110
|
-
# :name :: A name to use for the Database object, displayed in PoolTimeout
|
|
116
|
+
# :name :: A name to use for the Database object, displayed in PoolTimeout.
|
|
111
117
|
# :preconnect :: Automatically create the maximum number of connections, so that they don't
|
|
112
118
|
# need to be created as needed. This is useful when connecting takes a long time
|
|
113
119
|
# and you want to avoid possible latency during runtime.
|
|
@@ -116,7 +122,7 @@ module Sequel
|
|
|
116
122
|
# :preconnect_extensions :: Similar to the :extensions option, but loads the extensions before the
|
|
117
123
|
# connections are made by the :preconnect option.
|
|
118
124
|
# :quote_identifiers :: Whether to quote identifiers.
|
|
119
|
-
# :servers :: A hash specifying a server/shard specific options, keyed by shard symbol
|
|
125
|
+
# :servers :: A hash specifying a server/shard specific options, keyed by shard symbol.
|
|
120
126
|
# :single_threaded :: Whether to use a single-threaded connection pool.
|
|
121
127
|
# :sql_log_level :: Method to use to log SQL to a logger, :info by default.
|
|
122
128
|
#
|
|
@@ -132,6 +138,7 @@ module Sequel
|
|
|
132
138
|
@opts[:adapter_class] = self.class
|
|
133
139
|
@opts[:single_threaded] = @single_threaded = typecast_value_boolean(@opts.fetch(:single_threaded, Sequel.single_threaded))
|
|
134
140
|
@default_string_column_size = @opts[:default_string_column_size] || DEFAULT_STRING_COLUMN_SIZE
|
|
141
|
+
@check_string_typecast_bytesize = typecast_value_boolean(@opts.fetch(:check_string_typecast_bytesize, true))
|
|
135
142
|
|
|
136
143
|
@schemas = {}
|
|
137
144
|
@prepared_statements = {}
|
|
@@ -350,7 +357,7 @@ module Sequel
|
|
|
350
357
|
# strings with all whitespace, and ones that respond
|
|
351
358
|
# true to empty?
|
|
352
359
|
def blank_object?(obj)
|
|
353
|
-
return obj.blank? if
|
|
360
|
+
return obj.blank? if obj.respond_to?(:blank?)
|
|
354
361
|
case obj
|
|
355
362
|
when NilClass, FalseClass
|
|
356
363
|
true
|
|
@@ -359,7 +366,7 @@ module Sequel
|
|
|
359
366
|
when String
|
|
360
367
|
obj.strip.empty?
|
|
361
368
|
else
|
|
362
|
-
|
|
369
|
+
obj.respond_to?(:empty?) ? obj.empty? : false
|
|
363
370
|
end
|
|
364
371
|
end
|
|
365
372
|
|
|
@@ -465,6 +472,21 @@ module Sequel
|
|
|
465
472
|
# Don't rescue other exceptions, they will be raised normally.
|
|
466
473
|
end
|
|
467
474
|
|
|
475
|
+
# Check the bytesize of a string before conversion. There is no point
|
|
476
|
+
# trying to typecast strings that would be way too long.
|
|
477
|
+
def typecast_check_string_length(string, max_size)
|
|
478
|
+
if @check_string_typecast_bytesize && string.bytesize > max_size
|
|
479
|
+
raise InvalidValue, "string too long to typecast (bytesize: #{string.bytesize}, max: #{max_size})"
|
|
480
|
+
end
|
|
481
|
+
string
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# Check the bytesize of the string value, if value is a string.
|
|
485
|
+
def typecast_check_length(value, max_size)
|
|
486
|
+
typecast_check_string_length(value, max_size) if String === value
|
|
487
|
+
value
|
|
488
|
+
end
|
|
489
|
+
|
|
468
490
|
# Typecast the value to an SQL::Blob
|
|
469
491
|
def typecast_value_blob(value)
|
|
470
492
|
value.is_a?(Sequel::SQL::Blob) ? value : Sequel::SQL::Blob.new(value)
|
|
@@ -488,9 +510,9 @@ module Sequel
|
|
|
488
510
|
when Date
|
|
489
511
|
value
|
|
490
512
|
when String
|
|
491
|
-
Sequel.string_to_date(value)
|
|
513
|
+
Sequel.string_to_date(typecast_check_string_length(value, 100))
|
|
492
514
|
when Hash
|
|
493
|
-
Date.new(*[:year, :month, :day].map{|x| (value[x] || value[x.to_s]).to_i})
|
|
515
|
+
Date.new(*[:year, :month, :day].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
|
|
494
516
|
else
|
|
495
517
|
raise InvalidValue, "invalid value for Date: #{value.inspect}"
|
|
496
518
|
end
|
|
@@ -498,7 +520,17 @@ module Sequel
|
|
|
498
520
|
|
|
499
521
|
# Typecast the value to a DateTime or Time depending on Sequel.datetime_class
|
|
500
522
|
def typecast_value_datetime(value)
|
|
501
|
-
|
|
523
|
+
case value
|
|
524
|
+
when String
|
|
525
|
+
Sequel.typecast_to_application_timestamp(typecast_check_string_length(value, 100))
|
|
526
|
+
when Hash
|
|
527
|
+
[:year, :month, :day, :hour, :minute, :second, :nanos, :offset].each do |x|
|
|
528
|
+
typecast_check_length(value[x] || value[x.to_s], 100)
|
|
529
|
+
end
|
|
530
|
+
Sequel.typecast_to_application_timestamp(value)
|
|
531
|
+
else
|
|
532
|
+
Sequel.typecast_to_application_timestamp(value)
|
|
533
|
+
end
|
|
502
534
|
end
|
|
503
535
|
|
|
504
536
|
if RUBY_VERSION >= '2.4'
|
|
@@ -531,18 +563,30 @@ module Sequel
|
|
|
531
563
|
when Numeric
|
|
532
564
|
BigDecimal(value.to_s)
|
|
533
565
|
when String
|
|
534
|
-
_typecast_value_string_to_decimal(value)
|
|
566
|
+
_typecast_value_string_to_decimal(typecast_check_string_length(value, 1000))
|
|
535
567
|
else
|
|
536
568
|
raise InvalidValue, "invalid value for BigDecimal: #{value.inspect}"
|
|
537
569
|
end
|
|
538
570
|
end
|
|
539
571
|
|
|
540
572
|
# Typecast the value to a Float
|
|
541
|
-
|
|
573
|
+
def typecast_value_float(value)
|
|
574
|
+
Float(typecast_check_length(value, 1000))
|
|
575
|
+
end
|
|
542
576
|
|
|
543
577
|
# Typecast the value to an Integer
|
|
544
578
|
def typecast_value_integer(value)
|
|
545
|
-
|
|
579
|
+
case value
|
|
580
|
+
when String
|
|
581
|
+
typecast_check_string_length(value, 100)
|
|
582
|
+
if value =~ /\A-?0+(\d)/
|
|
583
|
+
Integer(value, 10)
|
|
584
|
+
else
|
|
585
|
+
Integer(value)
|
|
586
|
+
end
|
|
587
|
+
else
|
|
588
|
+
Integer(value)
|
|
589
|
+
end
|
|
546
590
|
end
|
|
547
591
|
|
|
548
592
|
# Typecast the value to a String
|
|
@@ -565,9 +609,9 @@ module Sequel
|
|
|
565
609
|
SQLTime.create(value.hour, value.min, value.sec, value.nsec/1000.0)
|
|
566
610
|
end
|
|
567
611
|
when String
|
|
568
|
-
Sequel.string_to_time(value)
|
|
612
|
+
Sequel.string_to_time(typecast_check_string_length(value, 100))
|
|
569
613
|
when Hash
|
|
570
|
-
SQLTime.create(*[:hour, :minute, :second].map{|x| (value[x] || value[x.to_s]).to_i})
|
|
614
|
+
SQLTime.create(*[:hour, :minute, :second].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
|
|
571
615
|
else
|
|
572
616
|
raise Sequel::InvalidValue, "invalid value for Time: #{value.inspect}"
|
|
573
617
|
end
|
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -1398,9 +1398,9 @@ module Sequel
|
|
|
1398
1398
|
# don't cache SQL for a dataset that uses this.
|
|
1399
1399
|
disable_sql_caching!
|
|
1400
1400
|
|
|
1401
|
-
if
|
|
1401
|
+
if v.respond_to?(:sql_literal_append)
|
|
1402
1402
|
v.sql_literal_append(self, sql)
|
|
1403
|
-
elsif
|
|
1403
|
+
elsif v.respond_to?(:sql_literal)
|
|
1404
1404
|
sql << v.sql_literal(self)
|
|
1405
1405
|
else
|
|
1406
1406
|
raise Error, "can't express #{v.inspect} as a SQL literal"
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
# :decimal :: use 0.0 for unsupported strings
|
|
9
9
|
# :string :: silently allow hash and array conversion to string
|
|
10
10
|
#
|
|
11
|
+
# This also removes bytesize checks for string inputs for float, integer
|
|
12
|
+
# and decimal conversions.
|
|
13
|
+
#
|
|
11
14
|
# To load the extension into the database:
|
|
12
15
|
#
|
|
13
16
|
# DB.extension :looser_typecasting
|
|
@@ -301,7 +301,7 @@ module Sequel
|
|
|
301
301
|
end
|
|
302
302
|
end
|
|
303
303
|
|
|
304
|
-
unless
|
|
304
|
+
unless Sequel::Postgres.respond_to?(:parse_pg_array)
|
|
305
305
|
require 'strscan'
|
|
306
306
|
|
|
307
307
|
# PostgreSQL array parser that handles PostgreSQL array output format.
|
|
@@ -412,7 +412,7 @@ module Sequel
|
|
|
412
412
|
@converter = converter
|
|
413
413
|
end
|
|
414
414
|
|
|
415
|
-
if
|
|
415
|
+
if Sequel::Postgres.respond_to?(:parse_pg_array)
|
|
416
416
|
# :nocov:
|
|
417
417
|
# Use sequel_pg's C-based parser if it has already been defined.
|
|
418
418
|
def call(string)
|
|
@@ -144,7 +144,7 @@ module Sequel
|
|
|
144
144
|
select_hash_groups(Sequel.cast(:enumtypid, Integer).as(:v), :enumlabel).freeze
|
|
145
145
|
enum_labels.each_value(&:freeze)
|
|
146
146
|
|
|
147
|
-
if
|
|
147
|
+
if respond_to?(:register_array_type)
|
|
148
148
|
array_types = metadata_dataset.
|
|
149
149
|
from(:pg_type).
|
|
150
150
|
where(:oid=>enum_labels.keys).
|
|
@@ -29,6 +29,8 @@ module Sequel
|
|
|
29
29
|
INFINITE_DATETIME_VALUES = ([PLUS_INFINITY, MINUS_INFINITY] + INFINITE_TIMESTAMP_STRINGS).freeze
|
|
30
30
|
PLUS_DATE_INFINITY = Date::Infinity.new
|
|
31
31
|
MINUS_DATE_INFINITY = -PLUS_DATE_INFINITY
|
|
32
|
+
RATIONAL_60 = Rational(60)
|
|
33
|
+
TIME_CAN_PARSE_BC = RUBY_VERSION >= '2.5'
|
|
32
34
|
|
|
33
35
|
# Add dataset methods and update the conversion proces for dates and timestamps.
|
|
34
36
|
def self.extended(db)
|
|
@@ -86,27 +88,18 @@ module Sequel
|
|
|
86
88
|
if value.is_a?(String) && (m = /((?:[-+]\d\d:\d\d)(:\d\d)?)?( BC)?\z/.match(value)) && (m[2] || m[3])
|
|
87
89
|
if m[3]
|
|
88
90
|
value = value.sub(' BC', '').sub(' ', ' BC ')
|
|
89
|
-
conv = defined?(JRUBY_VERSION) && JRUBY_VERSION == '9.2.0.0'
|
|
90
91
|
end
|
|
91
|
-
if m[2]
|
|
92
|
-
dt = DateTime
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
# :nocov:
|
|
101
|
-
end
|
|
102
|
-
unless Sequel.datetime_class == DateTime
|
|
103
|
-
dt = dt.to_time
|
|
104
|
-
if conv && (timezone == nil || timezone == :local) && !m[1]
|
|
105
|
-
# :nocov:
|
|
106
|
-
dt = Sequel.send(:convert_input_timestamp, dt.strftime("%F %T.%6N"), :local)
|
|
107
|
-
# :nocov:
|
|
108
|
-
end
|
|
92
|
+
if m[2]
|
|
93
|
+
dt = if Sequel.datetime_class == DateTime
|
|
94
|
+
DateTime.parse(value)
|
|
95
|
+
elsif TIME_CAN_PARSE_BC
|
|
96
|
+
Time.parse(value)
|
|
97
|
+
# :nocov:
|
|
98
|
+
else
|
|
99
|
+
DateTime.parse(value).to_time
|
|
100
|
+
# :nocov:
|
|
109
101
|
end
|
|
102
|
+
|
|
110
103
|
Sequel.convert_output_timestamp(dt, Sequel.application_timezone)
|
|
111
104
|
else
|
|
112
105
|
super(value)
|
|
@@ -223,10 +216,7 @@ module Sequel
|
|
|
223
216
|
# Work around JRuby bug #4822 in Time#to_datetime for times before date of calendar reform
|
|
224
217
|
def literal_time(time)
|
|
225
218
|
if time < TIME_YEAR_1
|
|
226
|
-
|
|
227
|
-
# Work around JRuby bug #5191
|
|
228
|
-
dt >>= 12 if JRUBY_VERSION == '9.2.0.0'
|
|
229
|
-
literal_datetime(dt)
|
|
219
|
+
literal_datetime(DateTime.parse(super))
|
|
230
220
|
else
|
|
231
221
|
super
|
|
232
222
|
end
|
|
@@ -236,7 +226,8 @@ module Sequel
|
|
|
236
226
|
# Handle BC Time objects.
|
|
237
227
|
def literal_time(time)
|
|
238
228
|
if time < TIME_YEAR_1
|
|
239
|
-
|
|
229
|
+
time = db.from_application_timestamp(time)
|
|
230
|
+
time.strftime("'#{sprintf('%04i', time.year.abs+1)}-%m-%d %H:%M:%S.%N#{format_timestamp_offset(*(time.utc_offset/RATIONAL_60).divmod(60))} BC'")
|
|
240
231
|
else
|
|
241
232
|
super
|
|
242
233
|
end
|
|
@@ -296,7 +296,7 @@ module Sequel
|
|
|
296
296
|
|
|
297
297
|
# Wrap argument in a PGArray if it is an array
|
|
298
298
|
def wrap_input_array(obj)
|
|
299
|
-
if obj.is_a?(Array) &&
|
|
299
|
+
if obj.is_a?(Array) && Sequel.respond_to?(:pg_array)
|
|
300
300
|
Sequel.pg_array(obj)
|
|
301
301
|
else
|
|
302
302
|
obj
|
|
@@ -305,7 +305,7 @@ module Sequel
|
|
|
305
305
|
|
|
306
306
|
# Wrap argument in an Hstore if it is a hash
|
|
307
307
|
def wrap_input_hash(obj)
|
|
308
|
-
if obj.is_a?(Hash) &&
|
|
308
|
+
if obj.is_a?(Hash) && Sequel.respond_to?(:hstore)
|
|
309
309
|
Sequel.hstore(obj)
|
|
310
310
|
else
|
|
311
311
|
obj
|
|
@@ -314,7 +314,7 @@ module Sequel
|
|
|
314
314
|
|
|
315
315
|
# Wrap argument in a PGArrayOp if supported
|
|
316
316
|
def wrap_output_array(obj)
|
|
317
|
-
if
|
|
317
|
+
if Sequel.respond_to?(:pg_array_op)
|
|
318
318
|
Sequel.pg_array_op(obj)
|
|
319
319
|
else
|
|
320
320
|
obj
|
|
@@ -49,13 +49,13 @@ module Sequel
|
|
|
49
49
|
meth = IPAddr.method(:new)
|
|
50
50
|
add_conversion_proc(869, meth)
|
|
51
51
|
add_conversion_proc(650, meth)
|
|
52
|
-
if
|
|
52
|
+
if respond_to?(:register_array_type)
|
|
53
53
|
register_array_type('inet', :oid=>1041, :scalar_oid=>869)
|
|
54
54
|
register_array_type('cidr', :oid=>651, :scalar_oid=>650)
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
if
|
|
58
|
+
if respond_to?(:register_array_type)
|
|
59
59
|
register_array_type('macaddr', :oid=>1040, :scalar_oid=>829)
|
|
60
60
|
end
|
|
61
61
|
@schema_type_classes[:ipaddr] = IPAddr
|
|
@@ -111,7 +111,7 @@ module Sequel
|
|
|
111
111
|
when IPAddr
|
|
112
112
|
value
|
|
113
113
|
when String
|
|
114
|
-
IPAddr.new(value)
|
|
114
|
+
IPAddr.new(typecast_check_string_length(value, 100))
|
|
115
115
|
else
|
|
116
116
|
raise Sequel::InvalidValue, "invalid value for inet/cidr: #{value.inspect}"
|
|
117
117
|
end
|
|
@@ -144,7 +144,7 @@ module Sequel
|
|
|
144
144
|
db.instance_exec do
|
|
145
145
|
extend_datasets(IntervalDatasetMethods)
|
|
146
146
|
add_conversion_proc(1186, Postgres::IntervalDatabaseMethods::PARSER)
|
|
147
|
-
if
|
|
147
|
+
if respond_to?(:register_array_type)
|
|
148
148
|
register_array_type('interval', :oid=>1187, :scalar_oid=>1186)
|
|
149
149
|
end
|
|
150
150
|
@schema_type_classes[:interval] = ActiveSupport::Duration
|
|
@@ -197,7 +197,7 @@ module Sequel
|
|
|
197
197
|
when Numeric
|
|
198
198
|
ActiveSupport::Duration.new(value, [[:seconds, value]])
|
|
199
199
|
when String
|
|
200
|
-
PARSER.call(value)
|
|
200
|
+
PARSER.call(typecast_check_string_length(value, 1000))
|
|
201
201
|
else
|
|
202
202
|
raise Sequel::InvalidValue, "invalid value for interval type: #{value.inspect}"
|
|
203
203
|
end
|
|
@@ -227,7 +227,7 @@ module Sequel
|
|
|
227
227
|
db.instance_exec do
|
|
228
228
|
add_conversion_proc(114, method(:_db_parse_json))
|
|
229
229
|
add_conversion_proc(3802, method(:_db_parse_jsonb))
|
|
230
|
-
if
|
|
230
|
+
if respond_to?(:register_array_type)
|
|
231
231
|
register_array_type('json', :oid=>199, :scalar_oid=>114)
|
|
232
232
|
register_array_type('jsonb', :oid=>3807, :scalar_oid=>3802)
|
|
233
233
|
end
|
|
@@ -123,15 +123,6 @@
|
|
|
123
123
|
# c = Sequel.pg_jsonb_op(:c)
|
|
124
124
|
# DB[:t].update(c['key1'] => 1.to_json, c['key2'] => "a".to_json)
|
|
125
125
|
#
|
|
126
|
-
# On PostgreSQL 15+, the <tt>IS [NOT] JSON</tt> operator is supported:
|
|
127
|
-
#
|
|
128
|
-
# j.is_json # j IS JSON
|
|
129
|
-
# j.is_json(type: :object) # j IS JSON OBJECT
|
|
130
|
-
# j.is_json(type: :object, unique: true) # j IS JSON OBJECT WITH UNIQUE
|
|
131
|
-
# j.is_not_json # j IS NOT JSON
|
|
132
|
-
# j.is_json(type: :array) # j IS NOT JSON ARRAY
|
|
133
|
-
# j.is_json(unique: true) # j IS NOT JSON WITH UNIQUE
|
|
134
|
-
#
|
|
135
126
|
# If you are also using the pg_json extension, you should load it before
|
|
136
127
|
# loading this extension. Doing so will allow you to use the #op method on
|
|
137
128
|
# JSONHash, JSONHarray, JSONBHash, and JSONBArray, allowing you to perform json/jsonb operations
|
|
@@ -160,18 +151,6 @@ module Sequel
|
|
|
160
151
|
GET_PATH = ["(".freeze, " #> ".freeze, ")".freeze].freeze
|
|
161
152
|
GET_PATH_TEXT = ["(".freeze, " #>> ".freeze, ")".freeze].freeze
|
|
162
153
|
|
|
163
|
-
IS_JSON = ["(".freeze, " IS JSON".freeze, "".freeze, ")".freeze].freeze
|
|
164
|
-
IS_NOT_JSON = ["(".freeze, " IS NOT JSON".freeze, "".freeze, ")".freeze].freeze
|
|
165
|
-
EMPTY_STRING = Sequel::LiteralString.new('').freeze
|
|
166
|
-
WITH_UNIQUE = Sequel::LiteralString.new(' WITH UNIQUE').freeze
|
|
167
|
-
IS_JSON_MAP = {
|
|
168
|
-
nil => EMPTY_STRING,
|
|
169
|
-
:value => Sequel::LiteralString.new(' VALUE').freeze,
|
|
170
|
-
:scalar => Sequel::LiteralString.new(' SCALAR').freeze,
|
|
171
|
-
:object => Sequel::LiteralString.new(' OBJECT').freeze,
|
|
172
|
-
:array => Sequel::LiteralString.new(' ARRAY').freeze
|
|
173
|
-
}.freeze
|
|
174
|
-
|
|
175
154
|
# Get JSON array element or object field as json. If an array is given,
|
|
176
155
|
# gets the object at the specified path.
|
|
177
156
|
#
|
|
@@ -254,30 +233,6 @@ module Sequel
|
|
|
254
233
|
end
|
|
255
234
|
end
|
|
256
235
|
|
|
257
|
-
# Return whether the json object can be parsed as JSON.
|
|
258
|
-
#
|
|
259
|
-
# Options:
|
|
260
|
-
# :type :: Check whether the json object can be parsed as a specific type
|
|
261
|
-
# of JSON (:value, :scalar, :object, :array).
|
|
262
|
-
# :unique :: Check JSON objects for unique keys.
|
|
263
|
-
#
|
|
264
|
-
# json_op.is_json # json IS JSON
|
|
265
|
-
# json_op.is_json(type: :object) # json IS JSON OBJECT
|
|
266
|
-
# json_op.is_json(unique: true) # json IS JSON WITH UNIQUE
|
|
267
|
-
def is_json(opts=OPTS)
|
|
268
|
-
_is_json(IS_JSON, opts)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
# Return whether the json object cannot be parsed as JSON. The opposite
|
|
272
|
-
# of #is_json. See #is_json for options.
|
|
273
|
-
#
|
|
274
|
-
# json_op.is_not_json # json IS NOT JSON
|
|
275
|
-
# json_op.is_not_json(type: :object) # json IS NOT JSON OBJECT
|
|
276
|
-
# json_op.is_not_json(unique: true) # json IS NOT JSON WITH UNIQUE
|
|
277
|
-
def is_not_json(opts=OPTS)
|
|
278
|
-
_is_json(IS_NOT_JSON, opts)
|
|
279
|
-
end
|
|
280
|
-
|
|
281
236
|
# Returns a set of keys AS text in the json object.
|
|
282
237
|
#
|
|
283
238
|
# json_op.keys # json_object_keys(json)
|
|
@@ -331,13 +286,6 @@ module Sequel
|
|
|
331
286
|
|
|
332
287
|
private
|
|
333
288
|
|
|
334
|
-
# Internals of IS [NOT] JSON support
|
|
335
|
-
def _is_json(lit_array, opts)
|
|
336
|
-
raise Error, "invalid is_json :type option: #{opts[:type].inspect}" unless type = IS_JSON_MAP[opts[:type]]
|
|
337
|
-
unique = opts[:unique] ? WITH_UNIQUE : EMPTY_STRING
|
|
338
|
-
Sequel::SQL::BooleanExpression.new(:NOOP, Sequel::SQL::PlaceholderLiteralString.new(lit_array, [self, type, unique]))
|
|
339
|
-
end
|
|
340
|
-
|
|
341
289
|
# Return a placeholder literal with the given str and args, wrapped
|
|
342
290
|
# in an JSONOp or JSONBOp, used by operators that return json or jsonb.
|
|
343
291
|
def json_op(str, args)
|
|
@@ -358,7 +306,7 @@ module Sequel
|
|
|
358
306
|
# Automatically wrap argument in a PGArray if it is a plain Array.
|
|
359
307
|
# Requires that the pg_array extension has been loaded to work.
|
|
360
308
|
def wrap_array(arg)
|
|
361
|
-
if arg.instance_of?(Array) &&
|
|
309
|
+
if arg.instance_of?(Array) && Sequel.respond_to?(:pg_array)
|
|
362
310
|
Sequel.pg_array(arg)
|
|
363
311
|
else
|
|
364
312
|
arg
|
|
@@ -652,7 +600,7 @@ module Sequel
|
|
|
652
600
|
|
|
653
601
|
# Wrap argument in a PGArray if it is an array
|
|
654
602
|
def wrap_input_array(obj)
|
|
655
|
-
if obj.is_a?(Array) &&
|
|
603
|
+
if obj.is_a?(Array) && Sequel.respond_to?(:pg_array)
|
|
656
604
|
Sequel.pg_array(obj)
|
|
657
605
|
else
|
|
658
606
|
obj
|
|
@@ -661,7 +609,7 @@ module Sequel
|
|
|
661
609
|
|
|
662
610
|
# Wrap argument in a JSONBArray or JSONBHash if it is an array or hash.
|
|
663
611
|
def wrap_input_jsonb(obj)
|
|
664
|
-
if
|
|
612
|
+
if Sequel.respond_to?(:pg_jsonb) && (obj.is_a?(Array) || obj.is_a?(Hash))
|
|
665
613
|
Sequel.pg_jsonb(obj)
|
|
666
614
|
else
|
|
667
615
|
obj
|
|
@@ -124,7 +124,7 @@ module Sequel
|
|
|
124
124
|
register_multirange_type('datemultirange', :range_oid=>3912, :oid=>4535)
|
|
125
125
|
register_multirange_type('int8multirange', :range_oid=>3926, :oid=>4536)
|
|
126
126
|
|
|
127
|
-
if
|
|
127
|
+
if respond_to?(:register_array_type)
|
|
128
128
|
register_array_type('int4multirange', :oid=>6150, :scalar_oid=>4451, :scalar_typecast=>:int4multirange)
|
|
129
129
|
register_array_type('nummultirange', :oid=>6151, :scalar_oid=>4532, :scalar_typecast=>:nummultirange)
|
|
130
130
|
register_array_type('tsmultirange', :oid=>6152, :scalar_oid=>4533, :scalar_typecast=>:tsmultirange)
|
|
@@ -141,7 +141,7 @@ module Sequel
|
|
|
141
141
|
add_conversion_proc(4533, PGMultiRange::Creator.new("tsmultirange", procs[3908]))
|
|
142
142
|
add_conversion_proc(4534, PGMultiRange::Creator.new("tstzmultirange", procs[3910]))
|
|
143
143
|
|
|
144
|
-
if
|
|
144
|
+
if respond_to?(:register_array_type) && defined?(PGArray::Creator)
|
|
145
145
|
add_conversion_proc(6152, PGArray::Creator.new("tsmultirange", procs[4533]))
|
|
146
146
|
add_conversion_proc(6153, PGArray::Creator.new("tstzmultirange", procs[4534]))
|
|
147
147
|
end
|
|
@@ -139,7 +139,7 @@ module Sequel
|
|
|
139
139
|
register_range_type('tstzrange', :oid=>3910, :subtype_oid=>1184)
|
|
140
140
|
register_range_type('daterange', :oid=>3912, :subtype_oid=>1082)
|
|
141
141
|
register_range_type('int8range', :oid=>3926, :subtype_oid=>20)
|
|
142
|
-
if
|
|
142
|
+
if respond_to?(:register_array_type)
|
|
143
143
|
register_array_type('int4range', :oid=>3905, :scalar_oid=>3904, :scalar_typecast=>:int4range)
|
|
144
144
|
register_array_type('numrange', :oid=>3907, :scalar_oid=>3906, :scalar_typecast=>:numrange)
|
|
145
145
|
register_array_type('tsrange', :oid=>3909, :scalar_oid=>3908, :scalar_typecast=>:tsrange)
|
|
@@ -154,7 +154,7 @@ module Sequel
|
|
|
154
154
|
procs = conversion_procs
|
|
155
155
|
add_conversion_proc(3908, Parser.new("tsrange", procs[1114]))
|
|
156
156
|
add_conversion_proc(3910, Parser.new("tstzrange", procs[1184]))
|
|
157
|
-
if
|
|
157
|
+
if respond_to?(:register_array_type) && defined?(PGArray::Creator)
|
|
158
158
|
add_conversion_proc(3909, PGArray::Creator.new("tsrange", procs[3908]))
|
|
159
159
|
add_conversion_proc(3911, PGArray::Creator.new("tstzrange", procs[3910]))
|
|
160
160
|
end
|
|
@@ -282,7 +282,7 @@ module Sequel
|
|
|
282
282
|
when Range
|
|
283
283
|
PGRange.from_range(value, parser.db_type)
|
|
284
284
|
when String
|
|
285
|
-
parser.call(value)
|
|
285
|
+
parser.call(typecast_check_string_length(value, 100))
|
|
286
286
|
else
|
|
287
287
|
raise Sequel::InvalidValue, "invalid value for range type: #{value.inspect}"
|
|
288
288
|
end
|
|
@@ -375,7 +375,7 @@ module Sequel
|
|
|
375
375
|
@row_schema_types = {}
|
|
376
376
|
extend(@row_type_method_module = Module.new)
|
|
377
377
|
add_conversion_proc(2249, PGRow::Parser.new(:converter=>PGRow::ArrayRow))
|
|
378
|
-
if
|
|
378
|
+
if respond_to?(:register_array_type)
|
|
379
379
|
register_array_type('record', :oid=>2287, :scalar_oid=>2249)
|
|
380
380
|
end
|
|
381
381
|
end
|
|
@@ -464,7 +464,7 @@ module Sequel
|
|
|
464
464
|
parser = Parser.new(parser_opts)
|
|
465
465
|
add_conversion_proc(parser.oid, parser)
|
|
466
466
|
|
|
467
|
-
if
|
|
467
|
+
if respond_to?(:register_array_type) && array_oid && array_oid > 0
|
|
468
468
|
array_type_name = if type_schema
|
|
469
469
|
"#{type_schema}.#{type_name}"
|
|
470
470
|
else
|
|
@@ -115,13 +115,13 @@ SQL
|
|
|
115
115
|
# :before_thread_exit :: An object that responds to +call+ that is called before the
|
|
116
116
|
# the created thread exits.
|
|
117
117
|
def listen_for_static_cache_updates(models, opts=OPTS)
|
|
118
|
-
raise Error, "this database object does not respond to listen, use the postgres adapter with the pg driver" unless
|
|
118
|
+
raise Error, "this database object does not respond to listen, use the postgres adapter with the pg driver" unless respond_to?(:listen)
|
|
119
119
|
models = [models] unless models.is_a?(Array)
|
|
120
120
|
raise Error, "array of models to listen for changes cannot be empty" if models.empty?
|
|
121
121
|
|
|
122
122
|
oid_map = {}
|
|
123
123
|
models.each do |model|
|
|
124
|
-
raise Error, "#{model.inspect} does not use the static_cache plugin" unless
|
|
124
|
+
raise Error, "#{model.inspect} does not use the static_cache plugin" unless model.respond_to?(:load_cache)
|
|
125
125
|
oid_map[get(regclass_oid(model.dataset.first_source_table))] = model
|
|
126
126
|
end
|
|
127
127
|
|
|
@@ -3016,7 +3016,7 @@ module Sequel
|
|
|
3016
3016
|
def complex_expression_sql_append(sql, op, args)
|
|
3017
3017
|
r = args[1]
|
|
3018
3018
|
if (((op == :'=' || op == :'!=') && r.is_a?(Sequel::Model)) ||
|
|
3019
|
-
(multiple = ((op == :IN || op == :'NOT IN') && ((is_ds = r.is_a?(Sequel::Dataset)) || (
|
|
3019
|
+
(multiple = ((op == :IN || op == :'NOT IN') && ((is_ds = r.is_a?(Sequel::Dataset)) || (r.respond_to?(:all?) && r.all?{|x| x.is_a?(Sequel::Model)})))))
|
|
3020
3020
|
l = args[0]
|
|
3021
3021
|
if ar = model.association_reflections[l]
|
|
3022
3022
|
raise Error, "filtering by associations is not allowed for #{ar.inspect}" if ar[:allow_filtering_by] == false
|
|
@@ -3024,7 +3024,7 @@ module Sequel
|
|
|
3024
3024
|
if multiple
|
|
3025
3025
|
klass = ar.associated_class
|
|
3026
3026
|
if is_ds
|
|
3027
|
-
if
|
|
3027
|
+
if r.respond_to?(:model)
|
|
3028
3028
|
unless r.model <= klass
|
|
3029
3029
|
# A dataset for a different model class, could be a valid regular query
|
|
3030
3030
|
return super
|
|
@@ -3356,10 +3356,10 @@ module Sequel
|
|
|
3356
3356
|
assoc_table_alias = ds.unused_table_alias(alias_base)
|
|
3357
3357
|
loader = r[:eager_grapher]
|
|
3358
3358
|
if !associations.empty?
|
|
3359
|
-
if
|
|
3359
|
+
if associations.first.respond_to?(:call)
|
|
3360
3360
|
callback = associations.first
|
|
3361
3361
|
associations = {}
|
|
3362
|
-
elsif associations.length == 1 && (assocs = associations.first).is_a?(Hash) && assocs.length == 1 && (pr_assoc = assocs.to_a.first) &&
|
|
3362
|
+
elsif associations.length == 1 && (assocs = associations.first).is_a?(Hash) && assocs.length == 1 && (pr_assoc = assocs.to_a.first) && pr_assoc.first.respond_to?(:call)
|
|
3363
3363
|
callback, assoc = pr_assoc
|
|
3364
3364
|
associations = assoc.is_a?(Array) ? assoc : [assoc]
|
|
3365
3365
|
end
|
|
@@ -3601,10 +3601,10 @@ module Sequel
|
|
|
3601
3601
|
end
|
|
3602
3602
|
|
|
3603
3603
|
associations = eager_assoc[r[:name]]
|
|
3604
|
-
if
|
|
3604
|
+
if associations.respond_to?(:call)
|
|
3605
3605
|
eager_block = associations
|
|
3606
3606
|
associations = OPTS
|
|
3607
|
-
elsif associations.is_a?(Hash) && associations.length == 1 && (pr_assoc = associations.to_a.first) &&
|
|
3607
|
+
elsif associations.is_a?(Hash) && associations.length == 1 && (pr_assoc = associations.to_a.first) && pr_assoc.first.respond_to?(:call)
|
|
3608
3608
|
eager_block, associations = pr_assoc
|
|
3609
3609
|
end
|
|
3610
3610
|
|
data/lib/sequel/model/base.rb
CHANGED
|
@@ -492,13 +492,13 @@ module Sequel
|
|
|
492
492
|
def plugin(plugin, *args, &block)
|
|
493
493
|
m = plugin.is_a?(Module) ? plugin : plugin_module(plugin)
|
|
494
494
|
|
|
495
|
-
if !
|
|
495
|
+
if !m.respond_to?(:apply) && !m.respond_to?(:configure) && (!args.empty? || block)
|
|
496
496
|
Deprecation.deprecate("Plugin #{plugin} accepts no arguments or block, and passing arguments/block to it", "Remove arguments and block when loading the plugin")
|
|
497
497
|
end
|
|
498
498
|
|
|
499
499
|
unless @plugins.include?(m)
|
|
500
500
|
@plugins << m
|
|
501
|
-
m.apply(self, *args, &block) if
|
|
501
|
+
m.apply(self, *args, &block) if m.respond_to?(:apply)
|
|
502
502
|
extend(m::ClassMethods) if m.const_defined?(:ClassMethods, false)
|
|
503
503
|
include(m::InstanceMethods) if m.const_defined?(:InstanceMethods, false)
|
|
504
504
|
if m.const_defined?(:DatasetMethods, false)
|
|
@@ -506,7 +506,7 @@ module Sequel
|
|
|
506
506
|
end
|
|
507
507
|
end
|
|
508
508
|
|
|
509
|
-
m.configure(self, *args, &block) if
|
|
509
|
+
m.configure(self, *args, &block) if m.respond_to?(:configure)
|
|
510
510
|
end
|
|
511
511
|
# :nocov:
|
|
512
512
|
ruby2_keywords(:plugin) if respond_to?(:ruby2_keywords, true)
|
|
@@ -99,7 +99,7 @@ module Sequel
|
|
|
99
99
|
# Convert the given string to CamelCase. Will also convert '/' to '::' which is useful for converting paths to namespaces.
|
|
100
100
|
def camelize(s)
|
|
101
101
|
s = s.to_s
|
|
102
|
-
return s.camelize if
|
|
102
|
+
return s.camelize if s.respond_to?(:camelize)
|
|
103
103
|
s = s.gsub(/\/(.?)/){|x| "::#{x[-1..-1].upcase unless x == '/'}"}.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
|
|
104
104
|
s
|
|
105
105
|
end
|
|
@@ -109,7 +109,7 @@ module Sequel
|
|
|
109
109
|
# or is not initialized.
|
|
110
110
|
def constantize(s)
|
|
111
111
|
s = s.to_s
|
|
112
|
-
return s.constantize if
|
|
112
|
+
return s.constantize if s.respond_to?(:constantize)
|
|
113
113
|
raise(NameError, "#{s.inspect} is not a valid constant name!") unless m = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.match(s)
|
|
114
114
|
Object.module_eval("::#{m[1]}", __FILE__, __LINE__)
|
|
115
115
|
end
|
|
@@ -117,14 +117,14 @@ module Sequel
|
|
|
117
117
|
# Removes the module part from the expression in the string
|
|
118
118
|
def demodulize(s)
|
|
119
119
|
s = s.to_s
|
|
120
|
-
return s.demodulize if
|
|
120
|
+
return s.demodulize if s.respond_to?(:demodulize)
|
|
121
121
|
s.gsub(/^.*::/, '')
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
# Returns the plural form of the word in the string.
|
|
125
125
|
def pluralize(s)
|
|
126
126
|
s = s.to_s
|
|
127
|
-
return s.pluralize if
|
|
127
|
+
return s.pluralize if s.respond_to?(:pluralize)
|
|
128
128
|
result = s.dup
|
|
129
129
|
Inflections.plurals.each{|(rule, replacement)| break if result.gsub!(rule, replacement)} unless Inflections.uncountables.include?(s.downcase)
|
|
130
130
|
result
|
|
@@ -133,7 +133,7 @@ module Sequel
|
|
|
133
133
|
# The reverse of pluralize, returns the singular form of a word in a string.
|
|
134
134
|
def singularize(s)
|
|
135
135
|
s = s.to_s
|
|
136
|
-
return s.singularize if
|
|
136
|
+
return s.singularize if s.respond_to?(:singularize)
|
|
137
137
|
result = s.dup
|
|
138
138
|
Inflections.singulars.each{|(rule, replacement)| break if result.gsub!(rule, replacement)} unless Inflections.uncountables.include?(s.downcase)
|
|
139
139
|
result
|
|
@@ -143,7 +143,7 @@ module Sequel
|
|
|
143
143
|
# Also changes '::' to '/' to convert namespaces to paths.
|
|
144
144
|
def underscore(s)
|
|
145
145
|
s = s.to_s
|
|
146
|
-
return s.underscore if
|
|
146
|
+
return s.underscore if s.respond_to?(:underscore)
|
|
147
147
|
s.gsub('::', '/').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
|
148
148
|
gsub(/([a-z\d])([A-Z])/, '\1_\2').tr('-', '_').downcase
|
|
149
149
|
end
|
|
@@ -252,7 +252,7 @@ module Sequel
|
|
|
252
252
|
|
|
253
253
|
unless skip.include?(:unique)
|
|
254
254
|
unique_opts = Hash[opts[:unique]]
|
|
255
|
-
if
|
|
255
|
+
if model.respond_to?(:sti_dataset)
|
|
256
256
|
unique_opts[:dataset] = model.sti_dataset
|
|
257
257
|
end
|
|
258
258
|
model.auto_validate_unique_columns.each{|cols| validates_unique(cols, unique_opts)}
|
data/lib/sequel/plugins/dirty.rb
CHANGED
|
@@ -203,7 +203,7 @@ module Sequel
|
|
|
203
203
|
get_column_value(column)
|
|
204
204
|
end
|
|
205
205
|
|
|
206
|
-
initial_values[column] = if value && value != true &&
|
|
206
|
+
initial_values[column] = if value && value != true && value.respond_to?(:clone)
|
|
207
207
|
begin
|
|
208
208
|
value.clone
|
|
209
209
|
rescue TypeError
|
|
@@ -36,7 +36,7 @@ module Sequel
|
|
|
36
36
|
module InsertConflict
|
|
37
37
|
def self.configure(model)
|
|
38
38
|
model.instance_exec do
|
|
39
|
-
if @dataset &&
|
|
39
|
+
if @dataset && !@dataset.respond_to?(:insert_conflict)
|
|
40
40
|
raise Error, "#{self}'s dataset does not support insert_conflict"
|
|
41
41
|
end
|
|
42
42
|
end
|
|
@@ -259,7 +259,7 @@ module Sequel
|
|
|
259
259
|
# specific :fields if configured.
|
|
260
260
|
def nested_attributes_set_attributes(meta, obj, attributes)
|
|
261
261
|
if fields = meta[:fields]
|
|
262
|
-
fields = fields.call(obj) if
|
|
262
|
+
fields = fields.call(obj) if fields.respond_to?(:call)
|
|
263
263
|
obj.set_fields(attributes, fields, :missing=>:skip)
|
|
264
264
|
else
|
|
265
265
|
obj.set(attributes)
|
|
@@ -159,7 +159,7 @@ module Sequel
|
|
|
159
159
|
|
|
160
160
|
case @dataset.first_source_table
|
|
161
161
|
when Symbol, String, SQL::Identifier, SQL::QualifiedIdentifier
|
|
162
|
-
convert_errors =
|
|
162
|
+
convert_errors = db.respond_to?(:error_info)
|
|
163
163
|
end
|
|
164
164
|
|
|
165
165
|
unless convert_errors
|
|
@@ -162,7 +162,7 @@ module Sequel
|
|
|
162
162
|
if !cc.include?(column) && (new? || get_column_value(column) != v)
|
|
163
163
|
cc << column
|
|
164
164
|
|
|
165
|
-
will_change_column(column) if
|
|
165
|
+
will_change_column(column) if respond_to?(:will_change_column)
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
deserialized_values[column] = v
|
|
@@ -91,7 +91,7 @@ module Sequel
|
|
|
91
91
|
# +many_to_many+ association, make sure the associated object is created on the
|
|
92
92
|
# current object's shard, unless the passed object already has an assigned shard.
|
|
93
93
|
def ensure_associated_primary_key(opts, o, *args)
|
|
94
|
-
o.set_server?(@server) if
|
|
94
|
+
o.set_server?(@server) if o.respond_to?(:set_server?)
|
|
95
95
|
super
|
|
96
96
|
end
|
|
97
97
|
|
|
@@ -35,7 +35,7 @@ module Sequel
|
|
|
35
35
|
# class B < Sequel::Model; end
|
|
36
36
|
# a # => [A, B]
|
|
37
37
|
module Subclasses
|
|
38
|
-
NEED_SUBCLASSES = !
|
|
38
|
+
NEED_SUBCLASSES = !Object.respond_to?(:subclasses) || Object.method(:subclasses).source_location
|
|
39
39
|
private_constant :NEED_SUBCLASSES
|
|
40
40
|
|
|
41
41
|
# Initialize the subclasses instance variable for the model.
|
|
@@ -282,7 +282,7 @@ module Sequel
|
|
|
282
282
|
o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i
|
|
283
283
|
end
|
|
284
284
|
if w = opts[:within]
|
|
285
|
-
o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.public_send(
|
|
285
|
+
o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.public_send(w.respond_to?(:cover?) ? :cover? : :include?, v.size)
|
|
286
286
|
end
|
|
287
287
|
end
|
|
288
288
|
end
|
|
@@ -337,14 +337,14 @@ module Sequel
|
|
|
337
337
|
def validates_inclusion_of(*atts)
|
|
338
338
|
opts = extract_options!(atts)
|
|
339
339
|
n = opts[:in]
|
|
340
|
-
unless n && (
|
|
340
|
+
unless n && (n.respond_to?(:cover?) || n.respond_to?(:include?))
|
|
341
341
|
raise ArgumentError, "The :in parameter is required, and must respond to cover? or include?"
|
|
342
342
|
end
|
|
343
343
|
opts[:message] ||= "is not in range or set: #{n.inspect}"
|
|
344
344
|
reflect_validation(:inclusion, opts, atts)
|
|
345
345
|
atts << opts
|
|
346
346
|
validates_each(*atts) do |o, a, v|
|
|
347
|
-
o.errors.add(a, opts[:message]) unless n.public_send(
|
|
347
|
+
o.errors.add(a, opts[:message]) unless n.public_send(n.respond_to?(:cover?) ? :cover? : :include?, v)
|
|
348
348
|
end
|
|
349
349
|
end
|
|
350
350
|
|
|
@@ -107,7 +107,7 @@ module Sequel
|
|
|
107
107
|
|
|
108
108
|
# Check attribute value(s) is included in the given set.
|
|
109
109
|
def validates_includes(set, atts, opts=OPTS)
|
|
110
|
-
validatable_attributes_for_type(:includes, atts, opts){|a,v,m| validation_error_message(m, set) unless set.public_send(
|
|
110
|
+
validatable_attributes_for_type(:includes, atts, opts){|a,v,m| validation_error_message(m, set) unless set.public_send(set.respond_to?(:cover?) ? :cover? : :include?, v)}
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
# Check attribute value(s) string representation is a valid integer.
|
data/lib/sequel/sql.rb
CHANGED
|
@@ -1347,7 +1347,7 @@ module Sequel
|
|
|
1347
1347
|
# underlying callable only accepts a single argument, call it
|
|
1348
1348
|
# with the given dataset.
|
|
1349
1349
|
def call(ds)
|
|
1350
|
-
if
|
|
1350
|
+
if @callable.respond_to?(:arity) && @callable.arity == 1
|
|
1351
1351
|
@callable.call(ds)
|
|
1352
1352
|
else
|
|
1353
1353
|
@callable.call
|
data/lib/sequel/version.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Sequel
|
|
|
6
6
|
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
|
8
8
|
# release, generally around once a month.
|
|
9
|
-
MINOR =
|
|
9
|
+
MINOR = 61
|
|
10
10
|
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sequel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.61.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-10-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -192,6 +192,7 @@ extra_rdoc_files:
|
|
|
192
192
|
- doc/release_notes/5.59.0.txt
|
|
193
193
|
- doc/release_notes/5.6.0.txt
|
|
194
194
|
- doc/release_notes/5.60.0.txt
|
|
195
|
+
- doc/release_notes/5.61.0.txt
|
|
195
196
|
- doc/release_notes/5.7.0.txt
|
|
196
197
|
- doc/release_notes/5.8.0.txt
|
|
197
198
|
- doc/release_notes/5.9.0.txt
|
|
@@ -280,6 +281,7 @@ files:
|
|
|
280
281
|
- doc/release_notes/5.59.0.txt
|
|
281
282
|
- doc/release_notes/5.6.0.txt
|
|
282
283
|
- doc/release_notes/5.60.0.txt
|
|
284
|
+
- doc/release_notes/5.61.0.txt
|
|
283
285
|
- doc/release_notes/5.7.0.txt
|
|
284
286
|
- doc/release_notes/5.8.0.txt
|
|
285
287
|
- doc/release_notes/5.9.0.txt
|