sequel 5.73.0 → 5.75.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: bf3b8749cd91ac285e66359ae16adf9605c13e673a0cf3f7251527573d71fed6
4
- data.tar.gz: 817f6980be08b29368eb0f08631d64ae48a4281aa1b2974b589441fea50e2dac
3
+ metadata.gz: 3047129164c9cdffee31414419904329e410db71e7e4243c0549614498a2b0d4
4
+ data.tar.gz: 9cc84ed8e9dba53aac7175be04699089932566e4015aed7a465c43552808c8b4
5
5
  SHA512:
6
- metadata.gz: 6da7c5e7a7c74c4767c55d126adc3743875a5dd0822ee780b22b1ca3c3791cc10d08cf74c984776dbd9fbbcf61d9246bcef4c81e64204e5d72aa59545ef9a2d9
7
- data.tar.gz: 7ac12f6689d846345fed77e23665679ae4886d60e4d25d4e201a3cfdac4f231882af0aaf3e615bd9981d09c2e9537c1e287fad614f81760f2d897b87402b38b1
6
+ metadata.gz: 15ed5c13e4793191546cd452aa5865e65fd7b3bb0458ffdb674d526398b7c9446e2da0f43a339daa3f1dc256eb551f0b773ac9ffc192b4d19f389d0c7e296d98
7
+ data.tar.gz: 1f25851b50857fbbf8378216794f26d0d8e9baa247f008feac466a218ae6b0777249252b6d05756e075096c5312b9d3b1334b7c4bc1884251e7b892cc17ae7c6
data/CHANGELOG CHANGED
@@ -1,3 +1,25 @@
1
+ === 5.75.0 (2023-12-01)
2
+
3
+ * Make any_not_empty? extension support passing pattern argument to any? (jeremyevans) (#2100)
4
+
5
+ * Respect :skip_transaction option in PostgreSQL Dataset#paged_each (jeremyevans) (#2097)
6
+
7
+ * Add TimestampMigrator.run_single to run a single migration file up or down (opya, jeremyevans) (#2093)
8
+
9
+ * Support INSERT RETURNING on MariaDB 10.5+, and use it when saving new model objects (jeremyevans)
10
+
11
+ * Add Database#{defer,immediate}_constraints on PostgreSQL for changing handling of deferrable constraints in a transaction (jeremyevans)
12
+
13
+ === 5.74.0 (2023-11-01)
14
+
15
+ * Make generated columns show up in Database#schema when using SQLite 3.37+ (jeremyevans) (#2087)
16
+
17
+ * Add revert method for Sequel.migration blocks, to revert changes inside the block on up, and apply the changes on down (jeremyevans)
18
+
19
+ * Re-add is_json and is_not_json methods to the pg_json_ops extension, as the support was re-added in PostgreSQL 16 (jeremyevans)
20
+
21
+ * Avoid infinite loop when handling exceptions with a cause loop in jdbc adapter (jeremyevans)
22
+
1
23
  === 5.73.0 (2023-10-01)
2
24
 
3
25
  * Handle disconnect errors in ibmdb and jdbc/db2 adapters (jeremyevans) (#2083)
data/doc/migration.rdoc CHANGED
@@ -90,6 +90,20 @@ the following methods:
90
90
 
91
91
  If you use any other methods, you should create your own +down+ block.
92
92
 
93
+ To revert a migration created with +change+, you can copy the migration to a new file, and
94
+ replace +change+ with +revert+. For example, if you no longer need the artists table, you
95
+ can use the following migration. This will drop the artists table when migrating up, and
96
+ recreate it when migrating down:
97
+
98
+ Sequel.migration do
99
+ revert do
100
+ create_table(:artists) do
101
+ primary_key :id
102
+ String :name, null: false
103
+ end
104
+ end
105
+ end
106
+
93
107
  In normal usage, when Sequel's migrator runs, it runs the +up+ blocks for all
94
108
  migrations that have not yet been applied. However, you can use the <tt>-M</tt>
95
109
  switch to specify the version to which to migrate, and if it is lower than the
@@ -0,0 +1,45 @@
1
+ = New Features
2
+
3
+ * Sequel.migration blocks now support a revert method, which reverts
4
+ the changes in the block on up, and applies them on down. So if
5
+ you have a migration such as:
6
+
7
+ Sequel.migration do
8
+ change do
9
+ create_table :table do
10
+ # ...
11
+ end
12
+ end
13
+ end
14
+
15
+ and you later want to add a migration that drops the table, you
16
+ can use:
17
+
18
+ Sequel.migration do
19
+ revert do
20
+ create_table :table do
21
+ # ...
22
+ end
23
+ end
24
+ end
25
+
26
+ This will drop the table when migrating up, and create a table
27
+ with the given schema when migrating down.
28
+
29
+ * is_json and is_not_json methods have been added to the pg_json_ops
30
+ extension, for the IS [NOT] JSON operator supported in PostgreSQL
31
+ 16+. These were previously added in Sequel 5.59.0, and removed
32
+ in Sequel 5.61.0 as support was removed in PostgreSQL 15 beta 4.
33
+ PostgreSQL 16 shipped with support for them, so support has been
34
+ recommitted to Sequel.
35
+
36
+ = Other Improvements
37
+
38
+ * SQLite generated columns now show up in Database#schema when using
39
+ SQLite 3.37+.
40
+
41
+ * Sequel now attempts to avoid an infinite loop in pathlogical cases
42
+ in the jdbc adapter, where the exception cause chain has a loop.
43
+ Additionally, if an exception is already recognized as a disconnect,
44
+ or an exception already responds to a getSQLState method, Sequel no
45
+ longer looks at the causes of the exception.
@@ -0,0 +1,35 @@
1
+ = New Features
2
+
3
+ * Database#{defer,immediate}_constraints methods have been added on
4
+ PostgreSQL for changing handling of deferrable constraints inside
5
+ a transaction. defer_constraints sets deferrable constraints to
6
+ be deferred (not checked until transaction commit), and
7
+ immediate_constraints sets deferrable constraints to be checked
8
+ as part of the related query, and any already deferred constraint
9
+ checks to be applied immediately. You can pass the :constraints
10
+ option to only apply the changes to specific constraints.
11
+
12
+ * TimestampMigrator.run_single has been added, to migrate a single
13
+ migration up or down.
14
+
15
+ = Other Improvements
16
+
17
+ * INSERT RETURNING is now supported on MariaDB 10.5+, and used
18
+ automatically when saving new model objects. Note that this
19
+ is not supported when using the jdbc adapter, because the
20
+ jdbc-mysql driver doesn't support it. A jdbc/mariadb adapter
21
+ could be added, as it's likely recent versions of the
22
+ jdbc-mariadb driver would support it, but the jdbc-mariadb gem
23
+ hasn't been updated in over 4 years. Talk to the jdbc-mariadb
24
+ gem maintainers if you want to use this feature with the jdbc
25
+ adapter.
26
+
27
+ * The Dataset#paged_each optimization in the postgres adapter
28
+ now respects the :skip_transaction option, making it the
29
+ same as the :hold option. Note that this has effects beyond
30
+ just skipping the transaction, but non-HOLD cursors are only
31
+ supported inside transactions.
32
+
33
+ * The any_not_empty? extension's Dataset#any? method now supports
34
+ an argument, passing it to Enumerable#any? (which has supported
35
+ an argument since Ruby 2.5).
@@ -36,10 +36,6 @@ module Sequel
36
36
 
37
37
  private
38
38
 
39
- def database_exception_sqlstate(exception, opts)
40
- exception.sql_state if exception.respond_to?(:sql_state)
41
- end
42
-
43
39
  def set_ps_arg(cps, arg, i)
44
40
  case arg
45
41
  when Sequel::SQL::Blob
@@ -36,6 +36,10 @@ module Sequel
36
36
 
37
37
  private
38
38
 
39
+ def database_exception_use_sqlstates?
40
+ false
41
+ end
42
+
39
43
  # Use @@IDENTITY to get the last inserted id
40
44
  def last_insert_id(conn, opts=OPTS)
41
45
  statement(conn) do |stmt|
@@ -79,6 +79,10 @@ module Sequel
79
79
  super.with_extend(MetadataDatasetMethods)
80
80
  end
81
81
 
82
+ def database_exception_use_sqlstates?
83
+ false
84
+ end
85
+
82
86
  def disconnect_error?(exception, opts)
83
87
  super || (exception.message =~ /connection is closed/)
84
88
  end
@@ -396,11 +396,16 @@ module Sequel
396
396
 
397
397
  def database_exception_sqlstate(exception, opts)
398
398
  if database_exception_use_sqlstates?
399
- while exception.respond_to?(:cause)
400
- exception = exception.cause
401
- return exception.getSQLState if exception.respond_to?(:getSQLState)
402
- end
399
+ _database_exception_sqlstate(exception, opts)
403
400
  end
401
+ end
402
+
403
+ def _database_exception_sqlstate(exception, opts)
404
+ 16.times do
405
+ return exception.getSQLState if exception.respond_to?(:getSQLState)
406
+ break unless exception.respond_to?(:cause) && (exception = exception.cause)
407
+ end
408
+
404
409
  nil
405
410
  end
406
411
 
@@ -415,8 +420,7 @@ module Sequel
415
420
 
416
421
  # Raise a disconnect error if the SQL state of the cause of the exception indicates so.
417
422
  def disconnect_error?(exception, opts)
418
- cause = exception.respond_to?(:cause) ? exception.cause : exception
419
- super || (cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/)
423
+ super || (_database_exception_sqlstate(exception, opts) =~ /^08/)
420
424
  end
421
425
 
422
426
  # Execute the prepared statement. If the provided name is a
@@ -672,6 +672,7 @@ module Sequel
672
672
  # cursor usage.
673
673
  # :rows_per_fetch :: The number of rows per fetch (default 1000). Higher
674
674
  # numbers result in fewer queries but greater memory use.
675
+ # :skip_transaction :: Same as :hold, but :hold takes priority.
675
676
  #
676
677
  # Usage:
677
678
  #
@@ -764,13 +765,13 @@ module Sequel
764
765
 
765
766
  # Use a cursor to fetch groups of records at a time, yielding them to the block.
766
767
  def cursor_fetch_rows(sql)
767
- server_opts = {:server=>@opts[:server] || :read_only}
768
768
  cursor = @opts[:cursor]
769
- hold = cursor[:hold]
769
+ hold = cursor.fetch(:hold){cursor[:skip_transaction]}
770
+ server_opts = {:server=>@opts[:server] || :read_only, :skip_transaction=>hold}
770
771
  cursor_name = quote_identifier(cursor[:cursor_name] || 'sequel_cursor')
771
772
  rows_per_fetch = cursor[:rows_per_fetch].to_i
772
773
 
773
- db.public_send(*(hold ? [:synchronize, server_opts[:server]] : [:transaction, server_opts])) do
774
+ db.transaction(server_opts) do
774
775
  begin
775
776
  execute_ddl("DECLARE #{cursor_name} NO SCROLL CURSOR WITH#{'OUT' unless hold} HOLD FOR #{sql}", server_opts)
776
777
  rows_per_fetch = 1000 if rows_per_fetch <= 0
@@ -646,7 +646,7 @@ module Sequel
646
646
  MATCH_AGAINST_BOOLEAN = ["MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE)".freeze].freeze
647
647
 
648
648
  Dataset.def_sql_method(self, :delete, %w'with delete from where order limit')
649
- Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update')
649
+ Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update returning')
650
650
  Dataset.def_sql_method(self, :select, %w'with select distinct calc_found_rows columns from join where group having window compounds order limit lock')
651
651
  Dataset.def_sql_method(self, :update, %w'with update ignore table set where order limit')
652
652
 
@@ -774,6 +774,21 @@ module Sequel
774
774
  clone(:insert_ignore=>true)
775
775
  end
776
776
 
777
+ # Support insert select for associations, so that the model code can use
778
+ # returning instead of a separate query.
779
+ def insert_select(*values)
780
+ return unless supports_insert_select?
781
+ # Handle case where query does not return a row
782
+ server?(:default).with_sql_first(insert_select_sql(*values)) || false
783
+ end
784
+
785
+ # The SQL to use for an insert_select, adds a RETURNING clause to the insert
786
+ # unless the RETURNING clause is already present.
787
+ def insert_select_sql(*values)
788
+ ds = opts[:returning] ? self : returning
789
+ ds.insert_sql(*values)
790
+ end
791
+
777
792
  # Sets up the insert methods to use ON DUPLICATE KEY UPDATE
778
793
  # If you pass no arguments, ALL fields will be
779
794
  # updated with the new values. If you pass the fields you
@@ -871,6 +886,11 @@ module Sequel
871
886
  true
872
887
  end
873
888
 
889
+ # MariaDB 10.5.0 supports INSERT RETURNING.
890
+ def supports_returning?(type)
891
+ (type == :insert && db.mariadb? && db.adapter_scheme != :jdbc) ? (db.server_version >= 100500) : false
892
+ end
893
+
874
894
  # MySQL 8+ supports SKIP LOCKED.
875
895
  def supports_skip_locked?
876
896
  !db.mariadb? && db.server_version >= 80000
@@ -498,6 +498,25 @@ module Sequel
498
498
  :postgres
499
499
  end
500
500
 
501
+ # For constraints that are deferrable, defer constraints until
502
+ # transaction commit. Options:
503
+ #
504
+ # :constraints :: An identifier of the constraint, or an array of
505
+ # identifiers for constraints, to apply this
506
+ # change to specific constraints.
507
+ # :server :: The server/shard on which to run the query.
508
+ #
509
+ # Examples:
510
+ #
511
+ # DB.defer_constraints
512
+ # # SET CONSTRAINTS ALL DEFERRED
513
+ #
514
+ # DB.defer_constraints(constraints: [:c1, Sequel[:sc][:c2]])
515
+ # # SET CONSTRAINTS "c1", "sc"."s2" DEFERRED
516
+ def defer_constraints(opts=OPTS)
517
+ _set_constraints(' DEFERRED', opts)
518
+ end
519
+
501
520
  # Use PostgreSQL's DO syntax to execute an anonymous code block. The code should
502
521
  # be the literal code string to use in the underlying procedural language. Options:
503
522
  #
@@ -611,6 +630,24 @@ module Sequel
611
630
  super
612
631
  end
613
632
 
633
+ # Immediately apply deferrable constraints.
634
+ #
635
+ # :constraints :: An identifier of the constraint, or an array of
636
+ # identifiers for constraints, to apply this
637
+ # change to specific constraints.
638
+ # :server :: The server/shard on which to run the query.
639
+ #
640
+ # Examples:
641
+ #
642
+ # DB.immediate_constraints
643
+ # # SET CONSTRAINTS ALL IMMEDIATE
644
+ #
645
+ # DB.immediate_constraints(constraints: [:c1, Sequel[:sc][:c2]])
646
+ # # SET CONSTRAINTS "c1", "sc"."s2" IMMEDIATE
647
+ def immediate_constraints(opts=OPTS)
648
+ _set_constraints(' IMMEDIATE', opts)
649
+ end
650
+
614
651
  # Use the pg_* system tables to determine indexes on a table
615
652
  def indexes(table, opts=OPTS)
616
653
  m = output_identifier_meth
@@ -1038,6 +1075,23 @@ module Sequel
1038
1075
  end
1039
1076
  end
1040
1077
 
1078
+ # Internals of defer_constraints/immediate_constraints
1079
+ def _set_constraints(type, opts)
1080
+ execute_ddl(_set_constraints_sql(type, opts), opts)
1081
+ end
1082
+
1083
+ # SQL to use for SET CONSTRAINTS
1084
+ def _set_constraints_sql(type, opts)
1085
+ sql = String.new
1086
+ sql << "SET CONSTRAINTS "
1087
+ if constraints = opts[:constraints]
1088
+ dataset.send(:source_list_append, sql, Array(constraints))
1089
+ else
1090
+ sql << "ALL"
1091
+ end
1092
+ sql << type
1093
+ end
1094
+
1041
1095
  def alter_table_add_column_sql(table, op)
1042
1096
  "ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
1043
1097
  end
@@ -504,7 +504,6 @@ module Sequel
504
504
  # table_xinfo PRAGMA used, remove hidden columns
505
505
  # that are not generated columns
506
506
  if row[:generated] = (row.delete(:hidden) != 0)
507
- next unless row[:type].end_with?(' GENERATED ALWAYS')
508
507
  row[:type] = row[:type].sub(' GENERATED ALWAYS', '')
509
508
  end
510
509
  end
@@ -32,8 +32,8 @@
32
32
  module Sequel
33
33
  module AnyNotEmpty
34
34
  # If a block is not given, return whether the dataset is not empty.
35
- def any?
36
- if defined?(yield)
35
+ def any?(*a)
36
+ if !a.empty? || defined?(yield)
37
37
  super
38
38
  else
39
39
  !empty?
@@ -159,6 +159,19 @@ module Sequel
159
159
  migration.up = block
160
160
  migration.down = MigrationReverser.new.reverse(&block)
161
161
  end
162
+
163
+ # Creates a revert migration. This is the same as creating
164
+ # the same block with +down+, but it also calls the block and attempts
165
+ # to create a +up+ block that will reverse the changes made by
166
+ # the block. This is designed to revert the changes in the
167
+ # provided block.
168
+ #
169
+ # There are no guarantees that this will work perfectly
170
+ # in all cases, but it works for some simple cases.
171
+ def revert(&block)
172
+ migration.down = block
173
+ migration.up = MigrationReverser.new.reverse(&block)
174
+ end
162
175
  end
163
176
 
164
177
  # Handles the reversing of reversible migrations. Basically records
@@ -680,6 +693,13 @@ module Sequel
680
693
  @migration_tuples = get_migration_tuples
681
694
  end
682
695
 
696
+ # Apply the migration in the given file path. See Migrator.run for the
697
+ # available options. Additionally, this method supports the :direction
698
+ # option for whether to run the migration up (default) or down.
699
+ def self.run_single(db, path, opts=OPTS)
700
+ new(db, File.dirname(path), opts).run_single(path, opts[:direction] || :up)
701
+ end
702
+
683
703
  # The timestamp migrator is current if there are no migrations to apply
684
704
  # in either direction.
685
705
  def is_current?
@@ -689,20 +709,39 @@ module Sequel
689
709
  # Apply all migration tuples on the database
690
710
  def run
691
711
  migration_tuples.each do |m, f, direction|
692
- t = Time.now
693
- db.log_info("Begin applying migration #{f}, direction: #{direction}")
694
- checked_transaction(m) do
695
- m.apply(db, direction)
696
- fi = f.downcase
697
- direction == :up ? ds.insert(column=>fi) : ds.where(column=>fi).delete
698
- end
699
- db.log_info("Finished applying migration #{f}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
712
+ apply_migration(m, f, direction)
700
713
  end
701
714
  nil
702
715
  end
703
716
 
717
+ # Apply single migration tuple at the given path with the given direction
718
+ # on the database.
719
+ def run_single(path, direction)
720
+ migration = load_migration_file(path)
721
+ file_name = File.basename(path)
722
+ already_applied = applied_migrations.include?(file_name.downcase)
723
+
724
+ return if direction == :up ? already_applied : !already_applied
725
+
726
+ apply_migration(migration, file_name, direction)
727
+ nil
728
+ end
729
+
704
730
  private
705
731
 
732
+ # Apply a single migration with the given filename in the given direction.
733
+ def apply_migration(migration, file_name, direction)
734
+ fi = file_name.downcase
735
+ t = Time.now
736
+
737
+ db.log_info("Begin applying migration #{file_name}, direction: #{direction}")
738
+ checked_transaction(migration) do
739
+ migration.apply(db, direction)
740
+ direction == :up ? ds.insert(column=>fi) : ds.where(column=>fi).delete
741
+ end
742
+ db.log_info("Finished applying migration #{file_name}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
743
+ end
744
+
706
745
  # Convert the schema_info table to the new schema_migrations table format,
707
746
  # using the version of the schema_info table and the current migration files.
708
747
  def convert_from_schema_info
@@ -123,6 +123,15 @@
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 16+, 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_not_json(type: :array) # j IS NOT JSON ARRAY
133
+ # j.is_not_json(unique: true) # j IS NOT JSON WITH UNIQUE
134
+ #
126
135
  # If you are also using the pg_json extension, you should load it before
127
136
  # loading this extension. Doing so will allow you to use the #op method on
128
137
  # JSONHash, JSONHarray, JSONBHash, and JSONBArray, allowing you to perform json/jsonb operations
@@ -151,6 +160,18 @@ module Sequel
151
160
  GET_PATH = ["(".freeze, " #> ".freeze, ")".freeze].freeze
152
161
  GET_PATH_TEXT = ["(".freeze, " #>> ".freeze, ")".freeze].freeze
153
162
 
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
+
154
175
  # Get JSON array element or object field as json. If an array is given,
155
176
  # gets the object at the specified path.
156
177
  #
@@ -233,6 +254,30 @@ module Sequel
233
254
  end
234
255
  end
235
256
 
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
+
236
281
  # Returns a set of keys AS text in the json object.
237
282
  #
238
283
  # json_op.keys # json_object_keys(json)
@@ -286,6 +331,13 @@ module Sequel
286
331
 
287
332
  private
288
333
 
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
+
289
341
  # Return a placeholder literal with the given str and args, wrapped
290
342
  # in an JSONOp or JSONBOp, used by operators that return json or jsonb.
291
343
  def json_op(str, args)
@@ -325,7 +325,7 @@ module Sequel
325
325
  # DB.alter_table(:ce_test) do
326
326
  # c = Sequel[:encrypted_column_name]
327
327
  # add_constraint(:enc_base64) do
328
- # octet_length(decode(regexp_replace(regexp_replace(c, '_', '/', 'g'), '-', '+', 'g'), 'base64')) >= 65}
328
+ # octet_length(decode(regexp_replace(regexp_replace(c, '_', '/', 'g'), '-', '+', 'g'), 'base64')) >= 65
329
329
  # end
330
330
  # end
331
331
  #
@@ -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 = 73
9
+ MINOR = 75
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.73.0
4
+ version: 5.75.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: 2023-10-01 00:00:00.000000000 Z
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -220,6 +220,8 @@ extra_rdoc_files:
220
220
  - doc/release_notes/5.71.0.txt
221
221
  - doc/release_notes/5.72.0.txt
222
222
  - doc/release_notes/5.73.0.txt
223
+ - doc/release_notes/5.74.0.txt
224
+ - doc/release_notes/5.75.0.txt
223
225
  - doc/release_notes/5.8.0.txt
224
226
  - doc/release_notes/5.9.0.txt
225
227
  files:
@@ -321,6 +323,8 @@ files:
321
323
  - doc/release_notes/5.71.0.txt
322
324
  - doc/release_notes/5.72.0.txt
323
325
  - doc/release_notes/5.73.0.txt
326
+ - doc/release_notes/5.74.0.txt
327
+ - doc/release_notes/5.75.0.txt
324
328
  - doc/release_notes/5.8.0.txt
325
329
  - doc/release_notes/5.9.0.txt
326
330
  - doc/schema_modification.rdoc