sequel 5.95.1 → 5.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1ce1e79be7d6ab1cbb8cedfb80a162a81af9f2efe3de83102c2377e023e2f81
4
- data.tar.gz: 93d997767f449e42cb76618207e816e4057277ca47d66371fa31903d3934bb91
3
+ metadata.gz: 236cf31a3c7848a6699dc871558a387748593a83dda8a722aad2e1c6beaad2d9
4
+ data.tar.gz: 974c8617fcecc74f10fab9c7fa8dd9e2f74a7a56767cf47cafd95e1108cc5f57
5
5
  SHA512:
6
- metadata.gz: 88aa3c9f86d2bf1e5286605291c162d84dc0e8a2fa7cf002767234b431f8ff9719729ba93c89f62e98a7e33be4f02dba4826a09315ae0fe387f95d60ae9e1cda
7
- data.tar.gz: 1f0c1e589056f3f0f6b2585e3dbf5e76a9173170357f37c59cff1ee8a4dcb830699f7e4a7bdd413947dab79f3f51f6bef5bc2902ebab030963a4ef8cf8de3ce8
6
+ metadata.gz: 5b396689d99af2a0882358e80150dc452b96a9cd09a73a9cdace42b903dd0958d341bf67e0570bd382dd051df54dc66b2d2b3e396506518c619d08bd006ebd1b
7
+ data.tar.gz: '0839e0177ccbb9d67880835b92e0b8767ea339b96375da914d0471a2cc24f25cdffbd8ada3b45ba69bdfc167a4609ed44fde1a7fd1db4c7574dff3f2efbfd80f'
@@ -154,6 +154,11 @@ module Sequel
154
154
  @operations << {:op => :alter_constraint, :name => name}.merge!(opts)
155
155
  end
156
156
 
157
+ # :inherit :: Set true to use INHERIT, or false to use NO INHERIT (PostgreSQL 18+)
158
+ def rename_constraint(name, new_name)
159
+ @operations << {:op => :rename_constraint, :name => name, :new_name => new_name}
160
+ end
161
+
157
162
  # Validate the constraint with the given name, which should have
158
163
  # been added previously with NOT VALID.
159
164
  def validate_constraint(name)
@@ -566,6 +571,7 @@ module Sequel
566
571
  # :if_exists :: Don't raise an error if the schema doesn't exist.
567
572
  def drop_schema(name, opts=OPTS)
568
573
  self << drop_schema_sql(name, opts)
574
+ remove_all_cached_schemas
569
575
  end
570
576
 
571
577
  # Drops a trigger from the database. Arguments:
@@ -721,6 +727,14 @@ module Sequel
721
727
  Sequel.synchronize{@primary_key_sequences[quoted_table] = value} if value
722
728
  end
723
729
 
730
+ # Rename a schema in the database. Arguments:
731
+ # name :: Current name of the schema
732
+ # opts :: New name for the schema
733
+ def rename_schema(name, new_name)
734
+ self << rename_schema_sql(name, new_name)
735
+ remove_all_cached_schemas
736
+ end
737
+
724
738
  # Refresh the materialized view with the given name.
725
739
  #
726
740
  # DB.refresh_view(:items_view)
@@ -1210,6 +1224,10 @@ module Sequel
1210
1224
  Postgres::AlterTableGenerator
1211
1225
  end
1212
1226
 
1227
+ def alter_table_rename_constraint_sql(table, op)
1228
+ "RENAME CONSTRAINT #{quote_identifier(op[:name])} TO #{quote_identifier(op[:new_name])}"
1229
+ end
1230
+
1213
1231
  def alter_table_set_column_type_sql(table, op)
1214
1232
  s = super
1215
1233
  if using = op[:using]
@@ -1291,7 +1309,7 @@ module Sequel
1291
1309
  sql << (identity == :always ? "ALWAYS" : "BY DEFAULT")
1292
1310
  sql << " AS IDENTITY"
1293
1311
  elsif (generated = column[:generated_always_as])
1294
- sql << " GENERATED ALWAYS AS (#{literal(generated)}) STORED"
1312
+ sql << " GENERATED ALWAYS AS (#{literal(generated)}) #{column[:virtual] ? 'VIRTUAL' : 'STORED'}"
1295
1313
  end
1296
1314
  end
1297
1315
  end
@@ -1797,6 +1815,18 @@ module Sequel
1797
1815
  super
1798
1816
  end
1799
1817
 
1818
+ # Clear all cached schema information
1819
+ def remove_all_cached_schemas
1820
+ @primary_keys.clear
1821
+ @primary_key_sequences.clear
1822
+ @schemas.clear
1823
+ end
1824
+
1825
+ # SQL for renaming a schema.
1826
+ def rename_schema_sql(name, new_name)
1827
+ "ALTER SCHEMA #{quote_identifier(name)} RENAME TO #{quote_identifier(new_name)}"
1828
+ end
1829
+
1800
1830
  # SQL DDL statement for renaming a table. PostgreSQL doesn't allow you to change a table's schema in
1801
1831
  # a rename table operation, so specifying a new schema in new_name will not have an effect.
1802
1832
  def rename_table_sql(name, new_name)
@@ -156,6 +156,9 @@ module Sequel
156
156
  # PostgreSQL specific options:
157
157
  #
158
158
  # :identity :: Create an identity column.
159
+ # :virtual :: When using :generated_always_as, create a VIRTUAL column instead of a STORED
160
+ # column (PostgreSQL 18+). VIRTUAL is the default if not specified on
161
+ # PostgreSQL 18+, but for backwards compatibility, Sequel's default is STORED.
159
162
  #
160
163
  # MySQL specific options:
161
164
  #
@@ -1256,8 +1256,6 @@ module Sequel
1256
1256
  # receiver's current order. This yields the row and the array of order expressions
1257
1257
  # to the block, which should return an array of values to use.
1258
1258
  def ignore_values_preceding(row)
1259
- @opts[:order].map{|v| v.is_a?(SQL::OrderedExpression) ? v.expression : v}
1260
-
1261
1259
  order_exprs = @opts[:order].map do |v|
1262
1260
  if v.is_a?(SQL::OrderedExpression)
1263
1261
  descending = v.descending
@@ -37,18 +37,11 @@ module Sequel
37
37
  value.to_s
38
38
  end
39
39
 
40
- if RUBY_VERSION >= '2.4'
41
- def _typecast_value_string_to_decimal(value)
42
- BigDecimal(value)
43
- rescue
44
- BigDecimal('0.0')
45
- end
46
- else
47
- # :nocov:
48
- def _typecast_value_string_to_decimal(value)
49
- BigDecimal(value)
50
- end
51
- # :nocov:
40
+ # Typecast invalid BigDecimal to 0.0.
41
+ def _typecast_value_string_to_decimal(value)
42
+ BigDecimal(value)
43
+ rescue
44
+ BigDecimal('0.0')
52
45
  end
53
46
  end
54
47
 
@@ -56,6 +56,13 @@
56
56
  # ia.join(':', ' ') # array_to_string(int_array_column, ':', ' ')
57
57
  # ia.unnest # unnest(int_array_column)
58
58
  # ia.unnest(:b) # unnest(int_array_column, b)
59
+ #
60
+ # On PostgreSQL 18+, the following are supported:
61
+ #
62
+ # ia.sort # array_sort(int_array_column)
63
+ # ia.sort(desc: true) # array_sort(int_array_column, true)
64
+ # ia.sort(nulls: :first) # array_sort(int_array_column, false, true)
65
+ # ia.reverse # array_reverse(int_array_column)
59
66
  #
60
67
  # See the PostgreSQL array function and operator documentation for more
61
68
  # details on what these functions and operators do.
@@ -217,6 +224,40 @@ module Sequel
217
224
  ArrayOp.new(function(:array_replace, element, replacement))
218
225
  end
219
226
 
227
+ # Call the array_reverse method:
228
+ #
229
+ # array_op.reverse # array_reverse(array)
230
+ def reverse
231
+ function(:array_reverse)
232
+ end
233
+
234
+ # Call the array_sort method. Options:
235
+ #
236
+ # :desc :: Sort in descending order instead of ascending order.
237
+ # :nulls :: If sorting in ascending order and value is :first, include NULL
238
+ # values before non-NULL values. If sorting in descending order and
239
+ # value is :last, include non-NULL values before NULL values.
240
+ #
241
+ # array_op.sort # array_sort(array)
242
+ # array_op.sort(desc: true) # array_sort(array, true)
243
+ # array_op.sort(nulls: :first) # array_sort(array, false, true)
244
+ # array_op.sort(desc: true, nulls: :last) # array_sort(array, true, false)
245
+ def sort(opts=OPTS)
246
+ desc = opts[:desc]
247
+ nulls = opts[:nulls]
248
+ if desc
249
+ if nulls == :last
250
+ function(:array_sort, true, false)
251
+ else
252
+ function(:array_sort, true)
253
+ end
254
+ elsif nulls == :first
255
+ function(:array_sort, false, true)
256
+ else
257
+ function(:array_sort)
258
+ end
259
+ end
260
+
220
261
  # Call the array_to_string method:
221
262
  #
222
263
  # array_op.join # array_to_string(array, '')
@@ -348,6 +348,8 @@ module Sequel
348
348
  # automatically parameterized.
349
349
  def auto_param_type(v)
350
350
  case v
351
+ when Symbol
352
+ false
351
353
  when String
352
354
  case v
353
355
  when LiteralString
@@ -166,6 +166,11 @@
166
166
  # # "d" date EXISTS FALSE ON ERROR
167
167
  # # ))
168
168
  #
169
+ # On PostgreSQL 18+, strip_nulls can take an argument for whether to strip in arrays
170
+ #
171
+ # j.strip_nulls(in_arrays: true) # json_strip_nulls(json_column, true)
172
+ # j.strip_nulls(in_arrays: false) # json_strip_nulls(json_column, false)
173
+ #
169
174
  # If you are also using the pg_json extension, you should load it before
170
175
  # loading this extension. Doing so will allow you to use the #op method on
171
176
  # JSONHash, JSONHarray, JSONBHash, and JSONBArray, allowing you to perform json/jsonb operations
@@ -380,11 +385,22 @@ module Sequel
380
385
  self.class.new(JSONQueryOp.new(self, path, opts))
381
386
  end
382
387
 
383
- # Returns a json value stripped of all internal null values.
388
+ # Returns a json value stripped of all internal null values. Options:
389
+ #
390
+ # :in_arrays :: Whether to strip null values in JSON arrays
384
391
  #
385
- # json_op.strip_nulls # json_strip_nulls(json)
386
- def strip_nulls
387
- self.class.new(function(:strip_nulls))
392
+ # json_op.strip_nulls # json_strip_nulls(json)
393
+ # json_op.strip_nulls(in_arrays: true) # json_strip_nulls(json, true)
394
+ # json_op.strip_nulls(in_arrays: false) # json_strip_nulls(json, false)
395
+ def strip_nulls(opts=OPTS)
396
+ in_arrays = opts[:in_arrays]
397
+ f = if in_arrays.nil?
398
+ function(:strip_nulls)
399
+ else
400
+ function(:strip_nulls, in_arrays)
401
+ end
402
+
403
+ self.class.new(f)
388
404
  end
389
405
 
390
406
  # Returns json_table SQL function expression, querying JSON data and returning
@@ -339,7 +339,7 @@ module Sequel
339
339
 
340
340
  # Allow automatic parameterization.
341
341
  def sequel_auto_param_type(ds)
342
- "::#{db_type}"
342
+ "::#{db_type}" if all?{|range| range.is_a?(Range) || ds.send(:auto_param_type, range)}
343
343
  end
344
344
  end
345
345
  end
@@ -421,6 +421,17 @@ module Sequel
421
421
  @exclude_end
422
422
  end
423
423
 
424
+ # Support a friendly output
425
+ def inspect
426
+ range = if empty?
427
+ "empty"
428
+ else
429
+ "#{@exclude_begin ? "(" : "["}#{@begin},#{@end}#{@exclude_end ? ")" : "]"}"
430
+ end
431
+
432
+ "#<#{self.class.name} #{range}#{"::#{@db_type}" if @db_type}>"
433
+ end
434
+
424
435
  # Append a literalize version of the receiver to the sql.
425
436
  def sql_literal_append(ds, sql)
426
437
  if (s = @db_type) && !empty?
@@ -481,9 +492,9 @@ module Sequel
481
492
  end
482
493
  end
483
494
 
484
- # Allow automatic parameterization for ranges with types.
495
+ # Allow automatic parameterization for ranges with types, if both start .
485
496
  def sequel_auto_param_type(ds)
486
- "::#{db_type}" if db_type
497
+ "::#{db_type}" if db_type && (!@begin || ds.send(:auto_param_type, @begin)) && (!@end || ds.send(:auto_param_type, @end))
487
498
  end
488
499
 
489
500
  private
@@ -3063,7 +3063,7 @@ module Sequel
3063
3063
  if (((op == :'=' || op == :'!=') && r.is_a?(Sequel::Model)) ||
3064
3064
  (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)})))))
3065
3065
  l = args[0]
3066
- if ar = model.association_reflections[l]
3066
+ if ar = model.association_reflection(l)
3067
3067
  raise Error, "filtering by associations is not allowed for #{ar.inspect}" if ar[:allow_filtering_by] == false
3068
3068
 
3069
3069
  if multiple
@@ -1358,17 +1358,16 @@ END
1358
1358
  @values.keys
1359
1359
  end
1360
1360
 
1361
- # Refresh this record using +for_update+ (by default, or the specified style when given)
1361
+ # Refresh this record using +:update+ lock style (by default, or the specified style when given),
1362
1362
  # unless this is a new record. Returns self. This can be used to make sure no other
1363
- # process is updating the record at the same time.
1363
+ # process can modify the record during the transaction containing this call. Using
1364
+ # this method only makes sense inside transactions.
1364
1365
  #
1365
1366
  # If style is a string, it will be used directly. You should never pass a string
1366
1367
  # to this method that is derived from user input, as that can lead to
1367
1368
  # SQL injection.
1368
1369
  #
1369
- # A symbol may be used for database independent locking behavior, but
1370
- # all supported symbols have separate methods (e.g. for_update).
1371
- #
1370
+ # A symbol may be used if the adapter supports that lock style.
1372
1371
  #
1373
1372
  # a = Artist[1]
1374
1373
  # Artist.db.transaction do
@@ -1378,7 +1377,7 @@ END
1378
1377
  #
1379
1378
  # a = Artist[2]
1380
1379
  # Artist.db.transaction do
1381
- # a.lock!('FOR NO KEY UPDATE')
1380
+ # a.lock!(:no_key_update)
1382
1381
  # a.update(name: 'B')
1383
1382
  # end
1384
1383
  def lock!(style=:update)
@@ -0,0 +1,151 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The deprecated_associations plugin adds support for
6
+ # deprecating associations. Attempts to use association
7
+ # methods and access association metadata for deprecated
8
+ # associations results in a warning.
9
+ #
10
+ # Album.plugin :deprecated_associations
11
+ # Album.many_to_one :artist, deprecated: true
12
+ # album = Album[1]
13
+ #
14
+ # # Warnings for all of the following calls
15
+ # album.artist
16
+ # album.artist_dataset
17
+ # album.artist = Artist[2]
18
+ # Album.association_reflection(:artist)
19
+ # Album.eager(:artist)
20
+ # Album.eager_graph(:artist)
21
+ # Album.where(artist: Artist[1]).all
22
+ #
23
+ # By default, the plugin issues a single warning per
24
+ # association method or association reflection. See
25
+ # DeprecatedAssociations.configure for options to make
26
+ # deprecated association issue warnings for every access,
27
+ # to include backtraces in warnings, or to raise an
28
+ # exception instead of warning.
29
+ #
30
+ # Note that Model.association_reflections and
31
+ # Model.all_association_reflections will include deprecated
32
+ # associations, and accessing the metadata for deprecated
33
+ # associations through these interfaces not issue warnings.
34
+ #
35
+ # Usage:
36
+ #
37
+ # # Make all models support deprecated associations
38
+ # # (called before loading subclasses)
39
+ # Sequel::Model.plugin :deprecated_associations
40
+ #
41
+ # # Make Album class support deprecated associations
42
+ # Album.plugin :deprecated_associations
43
+ module DeprecatedAssociations
44
+ # Exception class used for deprecated association use when
45
+ # raising exceptions instead of emitting warnings.
46
+ class Access < Sequel::Error; end
47
+
48
+ # Configure the deprecated associations plugin. Options:
49
+ #
50
+ # backtrace: Print backtrace with warning
51
+ # deduplicate: Set to false to emit warnings for every
52
+ # deprecated association method call/access
53
+ # (when not caching associations, this is always false)
54
+ # raise: Raise Sequel::Plugin::DeprecatedAssociations::Access
55
+ # instead of warning
56
+ def self.configure(model, opts = OPTS)
57
+ model.instance_exec do
58
+ (@deprecated_associations_config ||= {}).merge!(opts)
59
+ end
60
+ end
61
+
62
+ module ClassMethods
63
+ # Issue a deprecation warning if the association is deprecated.
64
+ def association_reflection(assoc)
65
+ ref = super
66
+ if ref && ref[:deprecated]
67
+ emit_deprecated_association_warning(ref, nil) do
68
+ "Access of association reflection for deprecated association: class:#{name} association:#{assoc}"
69
+ end
70
+ end
71
+ ref
72
+ end
73
+
74
+ private
75
+
76
+ # Issue a deprecation warning when the defined method is called if the
77
+ # association is deprecated and the method name does not start with the
78
+ # underscore (to avoid not warning twice, once for the public association
79
+ # method and once for the private association method).
80
+ def association_module_def(name, opts=OPTS, &block)
81
+ super
82
+ if opts[:deprecated] && name[0] != "_"
83
+ deprecated_associations_module.module_exec do
84
+ define_method(name) do |*a, &b|
85
+ self.class.send(:emit_deprecated_association_warning, opts, name) do
86
+ "Calling deprecated association method: class:#{self.class.name} association:#{opts[:name]} method:#{name}"
87
+ end
88
+ super(*a, &b)
89
+ end
90
+ alias_method name, name
91
+ end
92
+ end
93
+ nil
94
+ end
95
+
96
+ # Issue a deprecation warning when the defined method is called if the
97
+ # association is deprecated.
98
+ def association_module_delegate_def(name, opts, &block)
99
+ super
100
+ if opts[:deprecated]
101
+ deprecated_associations_module.module_exec do
102
+ define_method(name) do |*a, &b|
103
+ self.class.send(:emit_deprecated_association_warning, opts, name) do
104
+ "Calling deprecated association method: class:#{self.class.name} association:#{opts[:name]} method:#{name}"
105
+ end
106
+ super(*a, &b)
107
+ end
108
+ # :nocov:
109
+ ruby2_keywords(name) if respond_to?(:ruby2_keywords, true)
110
+ # :nocov:
111
+ alias_method(name, name)
112
+ end
113
+ end
114
+ nil
115
+ end
116
+
117
+ # A module to add deprecated association methods to. These methods
118
+ # handle issuing the deprecation warnings, and call super to get the
119
+ # default behavior.
120
+ def deprecated_associations_module
121
+ return @deprecated_associations_module if defined?(@deprecated_associations_module)
122
+ @deprecated_associations_module = Module.new
123
+ include(@deprecated_associations_module)
124
+ @deprecated_associations_module
125
+ end
126
+
127
+ # Emit a deprecation warning, or raise an exception if the :raise
128
+ # plugin option was used.
129
+ def emit_deprecated_association_warning(ref, method)
130
+ config = @deprecated_associations_config
131
+
132
+ raise Access, yield if config[:raise]
133
+
134
+ unless config[:deduplicate] == false
135
+ emit = false
136
+ ref.send(:cached_fetch, [:deprecated_associations, method]) do
137
+ emit = true
138
+ end
139
+ return unless emit
140
+ end
141
+
142
+ if config[:backtrace]
143
+ warn yield, caller(2)
144
+ else
145
+ warn yield, :uplevel => 2
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -106,13 +106,7 @@ module Sequel
106
106
  # and breaks some aspects of the json_serializer plugin. You can undo the damage
107
107
  # done by active_support/json by doing:
108
108
  #
109
- # module ActiveSupportBrokenJSONFix
110
- # def to_json(options = {})
111
- # JSON.generate(self)
112
- # end
113
- # end
114
- # Array.send(:prepend, ActiveSupportBrokenJSONFix)
115
- # Hash.send(:prepend, ActiveSupportBrokenJSONFix)
109
+ # ActiveSupport::ToJsonWithActiveSupportEncoder.send(:remove_method, :to_json)
116
110
  #
117
111
  # Note that this will probably cause active_support/json to no longer work
118
112
  # correctly in some cases.
@@ -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 = 95
9
+ MINOR = 97
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 = 1
13
+ TINY = 0
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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.95.1
4
+ version: 5.97.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -342,6 +342,7 @@ files:
342
342
  - lib/sequel/plugins/def_dataset_method.rb
343
343
  - lib/sequel/plugins/defaults_setter.rb
344
344
  - lib/sequel/plugins/delay_add_association.rb
345
+ - lib/sequel/plugins/deprecated_associations.rb
345
346
  - lib/sequel/plugins/dirty.rb
346
347
  - lib/sequel/plugins/eager_each.rb
347
348
  - lib/sequel/plugins/eager_graph_eager.rb