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