sequel 5.59.0 → 5.60.1

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