sequel 5.59.0 → 5.60.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47d7144911d61be13cc600fc3153c8e30eb384476ea7fb94ce61bd0f2f627c36
4
- data.tar.gz: fa763e2f24d5b6b26feecb405b5a43d8bbf30d2b727590e8fd98031640dfef2a
3
+ metadata.gz: cd8695696d6b55edf6337870f3ff172aeb6fe2ef9ba4bbc23daae0af26908649
4
+ data.tar.gz: 2483bbb3549adbcb9f179165119051b7bb234d6e714e4afa116c0ffddf379dc6
5
5
  SHA512:
6
- metadata.gz: 3855f6fbb47f26bfd0e9570ed8b7e908815bc7de3752751b92708c3e88948719f62dafe26cc1ea83b598c73e1ee84e4dbf12f01437dd1b087eed68ca4281b33d
7
- data.tar.gz: 932fa5c97bc8dcf077a50961b2da7ecd59ae0c077409c2b0c3111d875fe468d5fbb4030f155faf17d3ba3ed0392e264d8e5ebaa11ad04db3ab98c209e2199440
6
+ metadata.gz: 0527cba1fcc06d8001cbd55473b3af5c23a9f5c004113fc24aa6f9e029c5ed2cf4f938bf184d79922164cdc3ea502d12860d46d64237bdbd306bf5ce50f59ffa
7
+ data.tar.gz: e13c17553592773e70c0e9a6753438444a5245f3cd0664c6c5a6c0a08a271d1d92180b110c7b7e5981f7ca6dc2b18d90da3feeb05a14ae863fcfd99d5673650e
data/CHANGELOG CHANGED
@@ -1,3 +1,17 @@
1
+ === 5.60.1 (2022-09-02)
2
+
3
+ * Revert conversion of respond_to? to defined?, as it breaks with unused refinements on Ruby 2 (jeremyevans) (#1919)
4
+
5
+ === 5.60.0 (2022-09-01)
6
+
7
+ * Support arbitrary expressions for date_arithmetic interval values on PostgreSQL 9.4+ (jeremyevans)
8
+
9
+ * Support native IS DISTINCT FROM on SQLite 3.39+ instead of emulating support in the is_distinct_from extension (jeremyevans)
10
+
11
+ * Support HAVING without GROUP BY on SQLite 3.39+ (jeremyevans)
12
+
13
+ * Convert most respond_to? calls to equivalent defined? for better performance (jeremyevans)
14
+
1
15
  === 5.59.0 (2022-08-01)
2
16
 
3
17
  * Set :allow_eager association option to false for instance specific associations without eager loaders (jeremyevans)
data/README.rdoc CHANGED
@@ -416,7 +416,7 @@ As with +delete+, +update+ affects all rows in the dataset, so +where+ first,
416
416
 
417
417
  === Merging records
418
418
 
419
- Merging records using the SQL MERGE statment is done using <tt>merge*</tt> methods.
419
+ Merging records using the SQL MERGE statement is done using <tt>merge*</tt> methods.
420
420
  You use +merge_using+ to specify the merge source and join conditions.
421
421
  You can use +merge_insert+, +merge_delete+, and/or +merge_update+ to set the
422
422
  INSERT, DELETE, and UPDATE clauses for the merge. +merge_insert+ takes the same
data/bin/sequel CHANGED
@@ -194,7 +194,11 @@ begin
194
194
  TO_DB = connect_proc[db2]
195
195
  same_db = DB.database_type==TO_DB.database_type
196
196
  index_opts = {:same_db=>same_db}
197
+
198
+ # :nocov:
197
199
  index_opts[:index_names] = :namespace if !DB.global_index_namespace? && TO_DB.global_index_namespace?
200
+ # :nocov:
201
+
198
202
  if DB.database_type == :sqlite && !same_db
199
203
  # SQLite integer types allows 64-bit integers
200
204
  TO_DB.extension :integer64
@@ -212,18 +216,20 @@ begin
212
216
  puts "Begin copying data"
213
217
  DB.transaction do
214
218
  TO_DB.transaction do
219
+ all_status_lines = ENV['SEQUEL_BIN_STATUS_ALL_LINES']
220
+
215
221
  DB.tables.each do |table|
216
222
  puts "Begin copying records for table: #{table}"
217
223
  time = Time.now
218
224
  to_ds = TO_DB.from(table)
219
225
  j = 0
220
226
  DB.from(table).each do |record|
221
- if Time.now - time > 5
227
+ to_ds.insert(record)
228
+ j += 1
229
+ if Time.now - time > 5 || all_status_lines
222
230
  puts "Status: #{j} records copied"
223
231
  time = Time.now
224
232
  end
225
- to_ds.insert(record)
226
- j += 1
227
233
  end
228
234
  puts "Finished copying #{j} records for table: #{table}"
229
235
  end
@@ -260,8 +266,10 @@ if !ARGV.empty?
260
266
  ARGV.each{|v| load(v)}
261
267
  elsif !$stdin.isatty
262
268
  eval($stdin.read)
269
+ # :nocov:
263
270
  else
264
271
  require 'irb'
265
272
  puts "Your database is stored in DB..."
266
273
  IRB.start
267
274
  end
275
+ # :nocov:
@@ -0,0 +1,22 @@
1
+ = New Features
2
+
3
+ * The date_arithmetic extension now supports arbitrary expressions
4
+ as interval values on PostgreSQL 9.4+. Previously, only integers
5
+ were supported for the interval values.
6
+
7
+ = Other Improvements
8
+
9
+ * Most Kernel#respond_to? calls have been converted to equivalent
10
+ defined? calls for better performance. defined? is a keyword
11
+ and is about 50% faster for the same behavior.
12
+
13
+ * The is_distinct_from extension now supports the IS DISTINCT FROM
14
+ syntax natively on SQLite 3.39+, instead of emulating it.
15
+
16
+ * HAVING without GROUP BY is now supported on SQLite 3.39+.
17
+
18
+ * Coverage testing has been significantly expanded. Previously,
19
+ the core, model, plugin, and extension code had 100% line/branch
20
+ coverage. 100% line/branch coverage has been added for the
21
+ core extensions, bin/sequel, and the postgres adapter with the
22
+ pg driver.
@@ -5,6 +5,7 @@ require_relative 'shared/postgres'
5
5
  begin
6
6
  require 'pg'
7
7
 
8
+ # :nocov:
8
9
  Sequel::Postgres::PGError = PG::Error if defined?(PG::Error)
9
10
  Sequel::Postgres::PGconn = PG::Connection if defined?(PG::Connection)
10
11
  Sequel::Postgres::PGresult = PG::Result if defined?(PG::Result)
@@ -14,14 +15,17 @@ begin
14
15
  raise LoadError unless defined?(PGconn::CONNECTION_OK)
15
16
  end
16
17
 
17
- Sequel::Postgres::USES_PG = true
18
18
  if defined?(PG::TypeMapByClass)
19
+ # :nocov:
19
20
  type_map = Sequel::Postgres::PG_QUERY_TYPE_MAP = PG::TypeMapByClass.new
20
21
  type_map[Integer] = PG::TextEncoder::Integer.new
21
22
  type_map[FalseClass] = type_map[TrueClass] = PG::TextEncoder::Boolean.new
22
23
  type_map[Float] = PG::TextEncoder::Float.new
23
24
  end
25
+
26
+ Sequel::Postgres::USES_PG = true
24
27
  rescue LoadError => e
28
+ # :nocov:
25
29
  begin
26
30
  require 'sequel/postgres-pr'
27
31
  rescue LoadError
@@ -32,16 +36,19 @@ rescue LoadError => e
32
36
  end
33
37
  end
34
38
  Sequel::Postgres::USES_PG = false
39
+ # :nocov:
35
40
  end
36
41
 
37
42
  module Sequel
38
43
  module Postgres
44
+ # :nocov:
39
45
  if USES_PG
40
46
  # Whether the given sequel_pg version integer is supported.
41
47
  def self.sequel_pg_version_supported?(version)
42
48
  version >= 10617
43
49
  end
44
50
  end
51
+ # :nocov:
45
52
 
46
53
  # PGconn subclass for connection specific methods used with the
47
54
  # pg or postgres-pr driver.
@@ -49,7 +56,9 @@ module Sequel
49
56
  # The underlying exception classes to reraise as disconnect errors
50
57
  # instead of regular database errors.
51
58
  DISCONNECT_ERROR_CLASSES = [IOError, Errno::EPIPE, Errno::ECONNRESET]
59
+ # :nocov:
52
60
  if defined?(::PG::ConnectionBad)
61
+ # :nocov:
53
62
  DISCONNECT_ERROR_CLASSES << ::PG::ConnectionBad
54
63
  end
55
64
  DISCONNECT_ERROR_CLASSES.freeze
@@ -75,6 +84,7 @@ module Sequel
75
84
  # are SQL strings.
76
85
  attr_reader :prepared_statements
77
86
 
87
+ # :nocov:
78
88
  unless public_method_defined?(:async_exec_params)
79
89
  alias async_exec_params async_exec
80
90
  end
@@ -117,6 +127,7 @@ module Sequel
117
127
  alias cmd_tuples cmdtuples
118
128
  end
119
129
  end
130
+ # :nocov:
120
131
 
121
132
  # Raise a Sequel::DatabaseDisconnectError if a one of the disconnect
122
133
  # error classes is raised, or a PGError is raised and the connection
@@ -210,7 +221,9 @@ module Sequel
210
221
  :sslmode => opts[:sslmode],
211
222
  :sslrootcert => opts[:sslrootcert]
212
223
  }.delete_if { |key, value| blank_object?(value) }
224
+ # :nocov:
213
225
  connection_params.merge!(opts[:driver_options]) if opts[:driver_options]
226
+ # :nocov:
214
227
  conn = Adapter.connect(opts[:conn_str] || connection_params)
215
228
 
216
229
  conn.instance_variable_set(:@prepared_statements, {})
@@ -218,6 +231,13 @@ module Sequel
218
231
  if receiver = opts[:notice_receiver]
219
232
  conn.set_notice_receiver(&receiver)
220
233
  end
234
+
235
+ # :nocov:
236
+ if conn.respond_to?(:type_map_for_queries=) && defined?(PG_QUERY_TYPE_MAP)
237
+ # :nocov:
238
+ conn.type_map_for_queries = PG_QUERY_TYPE_MAP
239
+ end
240
+ # :nocov:
221
241
  else
222
242
  unless typecast_value_boolean(@opts.fetch(:force_standard_strings, true))
223
243
  raise Error, "Cannot create connection using postgres-pr unless force_standard_strings is set"
@@ -232,12 +252,11 @@ module Sequel
232
252
  opts[:password]
233
253
  )
234
254
  end
255
+ # :nocov:
235
256
 
236
257
  conn.instance_variable_set(:@db, self)
237
- if USES_PG && conn.respond_to?(:type_map_for_queries=) && defined?(PG_QUERY_TYPE_MAP)
238
- conn.type_map_for_queries = PG_QUERY_TYPE_MAP
239
- end
240
258
 
259
+ # :nocov:
241
260
  if encoding = opts[:encoding] || opts[:charset]
242
261
  if conn.respond_to?(:set_client_encoding)
243
262
  conn.set_client_encoding(encoding)
@@ -245,6 +264,7 @@ module Sequel
245
264
  conn.async_exec("set client_encoding to '#{encoding}'")
246
265
  end
247
266
  end
267
+ # :nocov:
248
268
 
249
269
  connection_configuration_sqls(opts).each{|sql| conn.execute(sql)}
250
270
  conn
@@ -271,7 +291,9 @@ module Sequel
271
291
  nil
272
292
  end
273
293
 
294
+ # :nocov:
274
295
  if USES_PG && Object.const_defined?(:PG) && ::PG.const_defined?(:Constants) && ::PG::Constants.const_defined?(:PG_DIAG_SCHEMA_NAME)
296
+ # :nocov:
275
297
  # Return a hash of information about the related PGError (or Sequel::DatabaseError that
276
298
  # wraps a PGError), with the following entries (any of which may be +nil+):
277
299
  #
@@ -322,7 +344,9 @@ module Sequel
322
344
  synchronize(opts[:server]){|conn| check_database_errors{_execute(conn, sql, opts, &block)}}
323
345
  end
324
346
 
347
+ # :nocov:
325
348
  if USES_PG
349
+ # :nocov:
326
350
  # +copy_table+ uses PostgreSQL's +COPY TO STDOUT+ SQL statement to return formatted
327
351
  # results directly to the caller. This method is only supported if pg is the
328
352
  # underlying ruby driver. This method should only be called if you want
@@ -515,8 +539,10 @@ module Sequel
515
539
  def adapter_initialize
516
540
  @use_iso_date_format = typecast_value_boolean(@opts.fetch(:use_iso_date_format, true))
517
541
  initialize_postgres_adapter
542
+ # :nocov:
518
543
  add_conversion_proc(17, method(:unescape_bytea)) if USES_PG
519
544
  add_conversion_proc(1082, TYPE_TRANSLATOR_DATE) if @use_iso_date_format
545
+ # :nocov:
520
546
  self.convert_infinite_timestamps = @opts[:convert_infinite_timestamps]
521
547
  end
522
548
 
@@ -526,19 +552,22 @@ module Sequel
526
552
  rescue => e
527
553
  raise_error(e, :classes=>database_error_classes)
528
554
  end
529
-
530
555
  # Set the DateStyle to ISO if configured, for faster date parsing.
531
556
  def connection_configuration_sqls(opts=@opts)
532
557
  sqls = super
558
+ # :nocov:
533
559
  sqls << "SET DateStyle = 'ISO'" if @use_iso_date_format
560
+ # :nocov:
534
561
  sqls
535
562
  end
536
563
 
564
+ # :nocov:
537
565
  if USES_PG
538
566
  def unescape_bytea(s)
539
567
  ::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s))
540
568
  end
541
569
  end
570
+ # :nocov:
542
571
 
543
572
  DATABASE_ERROR_CLASSES = [PGError].freeze
544
573
  def database_error_classes
@@ -552,7 +581,9 @@ module Sequel
552
581
  end
553
582
 
554
583
  def database_exception_sqlstate(exception, opts)
584
+ # :nocov:
555
585
  if exception.respond_to?(:result) && (result = exception.result)
586
+ # :nocov:
556
587
  result.error_field(PGresult::PG_DIAG_SQLSTATE)
557
588
  end
558
589
  end
@@ -662,7 +693,9 @@ module Sequel
662
693
  clone(:where=>Sequel.lit(['CURRENT OF '], Sequel.identifier(cursor_name)))
663
694
  end
664
695
 
696
+ # :nocov:
665
697
  if USES_PG
698
+ # :nocov:
666
699
  PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
667
700
 
668
701
  # PostgreSQL specific argument mapper used for mapping the named
@@ -809,6 +842,7 @@ module Sequel
809
842
  end
810
843
  end
811
844
 
845
+ # :nocov:
812
846
  if Sequel::Postgres::USES_PG && !ENV['NO_SEQUEL_PG']
813
847
  begin
814
848
  require 'sequel_pg'
@@ -820,3 +854,4 @@ if Sequel::Postgres::USES_PG && !ENV['NO_SEQUEL_PG']
820
854
  rescue LoadError
821
855
  end
822
856
  end
857
+ # :nocov:
@@ -230,7 +230,6 @@ module Sequel
230
230
  module DatabaseMethods
231
231
  include UnmodifiedIdentifiers::DatabaseMethods
232
232
 
233
- PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
234
233
  FOREIGN_KEY_LIST_ON_DELETE_MAP = {'a'=>:no_action, 'r'=>:restrict, 'c'=>:cascade, 'n'=>:set_null, 'd'=>:set_default}.freeze
235
234
  ON_COMMIT = {:drop => 'DROP', :delete_rows => 'DELETE ROWS', :preserve_rows => 'PRESERVE ROWS'}.freeze
236
235
  ON_COMMIT.each_value(&:freeze)
@@ -365,9 +364,10 @@ module Sequel
365
364
 
366
365
  table_oid = regclass_oid(table)
367
366
  im = input_identifier_meth
368
- unless column = im.call(opts[:column] || ((sch = schema(table).find{|_, sc| sc[:primary_key] && sc[:auto_increment]}) && sch[0]))
367
+ unless column = (opts[:column] || ((sch = schema(table).find{|_, sc| sc[:primary_key] && sc[:auto_increment]}) && sch[0]))
369
368
  raise Error, "could not determine column to convert from serial to identity automatically"
370
369
  end
370
+ column = im.call(column)
371
371
 
372
372
  column_num = ds.from(:pg_attribute).
373
373
  where(:attrelid=>table_oid, :attname=>column).
@@ -569,10 +569,12 @@ module Sequel
569
569
  if server_version >= 90500
570
570
  cpos = Sequel.expr{array_position(co[:conkey], ctable[:attnum])}
571
571
  rpos = Sequel.expr{array_position(co[:confkey], rtable[:attnum])}
572
+ # :nocov:
572
573
  else
573
574
  range = 0...32
574
575
  cpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:conkey], [x]), x]}, 32, ctable[:attnum])}
575
576
  rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32, rtable[:attnum])}
577
+ # :nocov:
576
578
  end
577
579
 
578
580
  ds = metadata_dataset.
@@ -653,9 +655,11 @@ module Sequel
653
655
 
654
656
  if server_version >= 90500
655
657
  order = [Sequel[:indc][:relname], Sequel.function(:array_position, Sequel[:ind][:indkey], Sequel[:att][:attnum])]
658
+ # :nocov:
656
659
  else
657
660
  range = 0...32
658
661
  order = [Sequel[:indc][:relname], SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(Sequel[:ind][:indkey], [x]), x]}, 32, Sequel[:att][:attnum])]
662
+ # :nocov:
659
663
  end
660
664
 
661
665
  attnums = SQL::Function.new(:ANY, Sequel[:ind][:indkey])
@@ -676,8 +680,10 @@ module Sequel
676
680
  select{[indc[:relname].as(:name), ind[:indisunique].as(:unique), att[:attname].as(:column), con[:condeferrable].as(:deferrable)]}
677
681
 
678
682
  ds = ds.where(:indpred=>nil) unless opts[:include_partial]
683
+ # :nocov:
679
684
  ds = ds.where(:indisready=>true) if server_version >= 80300
680
685
  ds = ds.where(:indislive=>true) if server_version >= 90300
686
+ # :nocov:
681
687
 
682
688
  indexes = {}
683
689
  ds.each do |r|
@@ -758,10 +764,12 @@ module Sequel
758
764
  seq_ds = metadata_dataset.from(:pg_sequence).where(:seqrelid=>regclass_oid(LiteralString.new(seq)))
759
765
  increment_by = :seqincrement
760
766
  min_value = :seqmin
767
+ # :nocov:
761
768
  else
762
769
  seq_ds = metadata_dataset.from(LiteralString.new(seq))
763
770
  increment_by = :increment_by
764
771
  min_value = :min_value
772
+ # :nocov:
765
773
  end
766
774
 
767
775
  get{setval(seq, db[table].select(coalesce(max(pk)+seq_ds.select(increment_by), seq_ds.select(min_value))), false)}
@@ -774,7 +782,9 @@ module Sequel
774
782
  # PostgreSQL uses SERIAL psuedo-type instead of AUTOINCREMENT for
775
783
  # managing incrementing primary keys.
776
784
  def serial_primary_key_options
785
+ # :nocov:
777
786
  auto_increment_key = server_version >= 100002 ? :identity : :serial
787
+ # :nocov:
778
788
  {:primary_key => true, auto_increment_key => true, :type=>Integer}
779
789
  end
780
790
 
@@ -1152,7 +1162,7 @@ module Sequel
1152
1162
  when :hash
1153
1163
  mod, remainder = generator.hash_values
1154
1164
  sql << " FOR VALUES WITH (MODULUS #{literal(mod)}, REMAINDER #{literal(remainder)})"
1155
- when :default
1165
+ else # when :default
1156
1166
  sql << " DEFAULT"
1157
1167
  end
1158
1168
 
@@ -1356,11 +1366,6 @@ module Sequel
1356
1366
  end
1357
1367
  end
1358
1368
 
1359
- # Use a dollar sign instead of question mark for the argument placeholder.
1360
- def prepared_arg_placeholder
1361
- PREPARED_ARG_PLACEHOLDER
1362
- end
1363
-
1364
1369
  # Return an expression the oid for the table expr. Used by the metadata parsing
1365
1370
  # code to disambiguate unqualified tables.
1366
1371
  def regclass_oid(expr, opts=OPTS)
@@ -1434,10 +1439,14 @@ module Sequel
1434
1439
  where{{pg_class[:oid]=>oid}}.
1435
1440
  order{pg_attribute[:attnum]}
1436
1441
 
1442
+ # :nocov:
1437
1443
  if server_version > 100000
1444
+ # :nocov:
1438
1445
  ds = ds.select_append{pg_attribute[:attidentity]}
1439
1446
 
1447
+ # :nocov:
1440
1448
  if server_version > 120000
1449
+ # :nocov:
1441
1450
  ds = ds.select_append{Sequel.~(pg_attribute[:attgenerated]=>'').as(:generated)}
1442
1451
  end
1443
1452
  end
@@ -1525,7 +1534,9 @@ module Sequel
1525
1534
 
1526
1535
  # PostgreSQL 9.4+ supports views with check option.
1527
1536
  def view_with_check_option_support
1537
+ # :nocov:
1528
1538
  :local if server_version >= 90400
1539
+ # :nocov:
1529
1540
  end
1530
1541
  end
1531
1542
 
@@ -1921,6 +1932,8 @@ module Sequel
1921
1932
  server_version >= 90000
1922
1933
  when :groups, :exclude
1923
1934
  server_version >= 110000
1935
+ else
1936
+ false
1924
1937
  end
1925
1938
  end
1926
1939
 
@@ -2067,12 +2080,11 @@ module Sequel
2067
2080
 
2068
2081
  # Return the primary key to use for RETURNING in an INSERT statement
2069
2082
  def insert_pk
2070
- if (f = opts[:from]) && !f.empty?
2071
- case t = f.first
2072
- when Symbol, String, SQL::Identifier, SQL::QualifiedIdentifier
2073
- if pk = db.primary_key(t)
2074
- Sequel::SQL::Identifier.new(pk)
2075
- end
2083
+ (f = opts[:from]) && !f.empty? && (t = f.first)
2084
+ case t
2085
+ when Symbol, String, SQL::Identifier, SQL::QualifiedIdentifier
2086
+ if pk = db.primary_key(t)
2087
+ Sequel::SQL::Identifier.new(pk)
2076
2088
  end
2077
2089
  end
2078
2090
  end
@@ -663,7 +663,7 @@ module Sequel
663
663
 
664
664
  # HAVING requires GROUP BY on SQLite
665
665
  def having(*cond)
666
- raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset") unless @opts[:group]
666
+ raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset") if !@opts[:group] && db.sqlite_version < 33900
667
667
  super
668
668
  end
669
669
 
@@ -32,6 +32,10 @@
32
32
  #
33
33
  # DB[:table].select(add.as(:d)).where(sub > Sequel::CURRENT_TIMESTAMP)
34
34
  #
35
+ # On most databases, the values you provide for years/months/days/etc. must
36
+ # be numeric values and not arbitrary SQL expressions. However, on PostgreSQL
37
+ # 9.4+, use of arbitrary SQL expressions is supported.
38
+ #
35
39
  # Related module: Sequel::SQL::DateAdd
36
40
 
37
41
  #
@@ -54,7 +58,16 @@ module Sequel
54
58
  interval = interval.parts
55
59
  end
56
60
  parts = {}
57
- interval.each{|k,v| parts[k] = -v unless v.nil?}
61
+ interval.each do |k,v|
62
+ case v
63
+ when nil
64
+ # ignore
65
+ when Numeric
66
+ parts[k] = -v
67
+ else
68
+ parts[k] = Sequel::SQL::NumericExpression.new(:*, v, -1)
69
+ end
70
+ end
58
71
  DateAdd.new(expr, parts, opts)
59
72
  end
60
73
  end
@@ -68,6 +81,7 @@ module Sequel
68
81
  module DatasetMethods
69
82
  DURATION_UNITS = [:years, :months, :days, :hours, :minutes, :seconds].freeze
70
83
  DEF_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| s.to_s.freeze}).freeze
84
+ POSTGRES_DURATION_UNITS = DURATION_UNITS.zip([:years, :months, :days, :hours, :mins, :secs].map{|s| s.to_s.freeze}).freeze
71
85
  MYSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s.upcase[0...-1]).freeze}).freeze
72
86
  MSSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s[0...-1]).freeze}).freeze
73
87
  H2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| s.to_s[0...-1].freeze}).freeze
@@ -87,14 +101,28 @@ module Sequel
87
101
 
88
102
  cast = case db_type = db.database_type
89
103
  when :postgres
90
- interval = String.new
91
- each_valid_interval_unit(h, DEF_DURATION_UNITS) do |value, sql_unit|
92
- interval << "#{value} #{sql_unit} "
104
+ casted = Sequel.cast(expr, cast_type)
105
+
106
+ if db.server_version >= 90400
107
+ placeholder = []
108
+ vals = []
109
+ each_valid_interval_unit(h, POSTGRES_DURATION_UNITS) do |value, sql_unit|
110
+ placeholder << "#{', ' unless placeholder.empty?}#{sql_unit} := "
111
+ vals << value
112
+ end
113
+ interval = Sequel.function(:make_interval, Sequel.lit(placeholder, *vals)) unless vals.empty?
114
+ else
115
+ parts = String.new
116
+ each_valid_interval_unit(h, DEF_DURATION_UNITS) do |value, sql_unit|
117
+ parts << "#{value} #{sql_unit} "
118
+ end
119
+ interval = Sequel.cast(parts, :interval) unless parts.empty?
93
120
  end
94
- if interval.empty?
95
- return literal_append(sql, Sequel.cast(expr, cast_type))
121
+
122
+ if interval
123
+ return complex_expression_sql_append(sql, :+, [casted, interval])
96
124
  else
97
- return complex_expression_sql_append(sql, :+, [Sequel.cast(expr, cast_type), Sequel.cast(interval, :interval)])
125
+ return literal_append(sql, casted)
98
126
  end
99
127
  when :sqlite
100
128
  args = [expr]
@@ -3,7 +3,7 @@
3
3
  # The is_distinct_from extension adds the ability to use the
4
4
  # SQL standard IS DISTINCT FROM operator, which is similar to the
5
5
  # not equals operator, except that NULL values are considered
6
- # equal. Only PostgreSQL and H2 currently support this operator. On
6
+ # equal. PostgreSQL, SQLite 3.39+, and H2 currently support this operator. On
7
7
  # other databases, support is emulated.
8
8
  #
9
9
  # First, you need to load the extension into the database:
@@ -90,6 +90,8 @@ module Sequel
90
90
  case db.database_type
91
91
  when :postgres, :h2
92
92
  true
93
+ when :sqlite
94
+ db.sqlite_version >= 33900
93
95
  else
94
96
  false
95
97
  end
@@ -35,6 +35,7 @@ if RUBY_VERSION >= '2.0'
35
35
  class Symbol
36
36
  prepend Sequel::SymbolAref
37
37
  end
38
+ # :nocov:
38
39
  else
39
40
  class Symbol
40
41
  if method_defined?(:[])
@@ -51,3 +52,4 @@ else
51
52
  end
52
53
  end
53
54
  end
55
+ # :nocov:
@@ -63,7 +63,7 @@ module Sequel
63
63
  end
64
64
  end
65
65
  # :nocov:
66
- ruby2_keywords(meth) if respond_to?(:ruby2_keywords, false)
66
+ mod.send(:ruby2_keywords, meth) if mod.respond_to?(:ruby2_keywords, true)
67
67
  # :nocov:
68
68
  end
69
69
 
@@ -97,7 +97,7 @@ module Sequel
97
97
  end
98
98
  end
99
99
  # :nocov:
100
- ruby2_keywords(meth) if respond_to?(:ruby2_keywords, false)
100
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
101
101
  # :nocov:
102
102
  end
103
103
 
@@ -129,7 +129,7 @@ module Sequel
129
129
  end
130
130
  end
131
131
  # :nocov:
132
- ruby2_keywords(meth) if respond_to?(:ruby2_keywords, false)
132
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
133
133
  # :nocov:
134
134
  end
135
135
 
@@ -159,7 +159,7 @@ module Sequel
159
159
  end
160
160
  end
161
161
  # :nocov:
162
- ruby2_keywords(meth) if respond_to?(:ruby2_keywords, false)
162
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
163
163
  # :nocov:
164
164
  end
165
165
 
@@ -6,11 +6,11 @@ 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 = 59
9
+ MINOR = 60
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
13
- TINY = 0
13
+ TINY = 1
14
14
 
15
15
  # The version of Sequel you are using, as a string (e.g. "2.11.0")
16
16
  VERSION = [MAJOR, MINOR, TINY].join('.').freeze
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.59.0
4
+ version: 5.60.1
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-08-01 00:00:00.000000000 Z
11
+ date: 2022-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -191,6 +191,7 @@ extra_rdoc_files:
191
191
  - doc/release_notes/5.58.0.txt
192
192
  - doc/release_notes/5.59.0.txt
193
193
  - doc/release_notes/5.6.0.txt
194
+ - doc/release_notes/5.60.0.txt
194
195
  - doc/release_notes/5.7.0.txt
195
196
  - doc/release_notes/5.8.0.txt
196
197
  - doc/release_notes/5.9.0.txt
@@ -278,6 +279,7 @@ files:
278
279
  - doc/release_notes/5.58.0.txt
279
280
  - doc/release_notes/5.59.0.txt
280
281
  - doc/release_notes/5.6.0.txt
282
+ - doc/release_notes/5.60.0.txt
281
283
  - doc/release_notes/5.7.0.txt
282
284
  - doc/release_notes/5.8.0.txt
283
285
  - doc/release_notes/5.9.0.txt