sequel 5.93.0 → 5.94.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sequel/adapters/ado/access.rb +2 -2
  3. data/lib/sequel/adapters/ado.rb +1 -1
  4. data/lib/sequel/adapters/ibmdb.rb +1 -1
  5. data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
  6. data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
  7. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
  8. data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -1
  9. data/lib/sequel/adapters/jdbc.rb +21 -7
  10. data/lib/sequel/adapters/mysql.rb +1 -1
  11. data/lib/sequel/adapters/mysql2.rb +2 -2
  12. data/lib/sequel/adapters/odbc.rb +1 -1
  13. data/lib/sequel/adapters/shared/db2.rb +8 -3
  14. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  15. data/lib/sequel/adapters/shared/mysql.rb +2 -2
  16. data/lib/sequel/adapters/shared/postgres.rb +106 -13
  17. data/lib/sequel/adapters/shared/sqlite.rb +3 -3
  18. data/lib/sequel/adapters/tinytds.rb +1 -1
  19. data/lib/sequel/adapters/trilogy.rb +1 -1
  20. data/lib/sequel/connection_pool/timed_queue.rb +1 -1
  21. data/lib/sequel/core.rb +1 -1
  22. data/lib/sequel/database/misc.rb +3 -3
  23. data/lib/sequel/database/query.rb +1 -1
  24. data/lib/sequel/database/schema_generator.rb +24 -10
  25. data/lib/sequel/database/schema_methods.rb +60 -26
  26. data/lib/sequel/dataset/query.rb +10 -2
  27. data/lib/sequel/dataset/sql.rb +1 -1
  28. data/lib/sequel/extensions/async_thread_pool.rb +1 -1
  29. data/lib/sequel/extensions/caller_logging.rb +1 -3
  30. data/lib/sequel/extensions/eval_inspect.rb +1 -1
  31. data/lib/sequel/extensions/inflector.rb +2 -2
  32. data/lib/sequel/extensions/migration.rb +1 -1
  33. data/lib/sequel/extensions/pg_hstore.rb +1 -1
  34. data/lib/sequel/extensions/provenance.rb +1 -3
  35. data/lib/sequel/extensions/schema_dumper.rb +1 -1
  36. data/lib/sequel/plugins/constraint_validations.rb +1 -1
  37. data/lib/sequel/plugins/json_serializer.rb +3 -3
  38. data/lib/sequel/plugins/unused_associations.rb +4 -2
  39. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  40. data/lib/sequel/version.rb +1 -1
  41. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd35e8223b7f6d450cf4c1efeaad152236b4a1e360299aa46b03841bb45996c6
4
- data.tar.gz: '096a62cc241cf6f48d0c2b3e0799402f21aa24a1196a332e022ef53ebaaeea85'
3
+ metadata.gz: 05c58f7009f56c4891e863d95ccd90eeb7acdc03f192979ff0d4a203fa1924d4
4
+ data.tar.gz: 957d465eebddd41b7de48475af26b04f4ae6fb387662257b97b9bdbc682eb197
5
5
  SHA512:
6
- metadata.gz: 0b66c7e30dfb69468ad41bfe64de4e0442ad62590ea735b2e4bb591c46b949794a7a453c21532999c89296694f0136d9353041ec56fc470ab2ba0483f0534d61
7
- data.tar.gz: 978dcd457829ff39f1ae9769dc574049cf29d07a2dbc8e307aa806a7b1954cd72432257de37d9e5236269b5746f615f8d0f7feb4979e9b86b619f582344afc29
6
+ metadata.gz: eb72cd090c58b8246b4a679082f9426f9aecf2d4815dffa2d96fe3be5a15b3e41b9ae7dd17effee49bfab82ac54c11d5d7d6aa67ff2a8aa54040145f5c72a3b0
7
+ data.tar.gz: 031fcb089d79550e485be488ec6d4b0d84024e4f686ebe953a08189c5b9d6e490c2351246b4258d8b78e9efafd013db61738f19e40a04afbb9fb1ec1796e5e6a
@@ -281,7 +281,7 @@ module Sequel
281
281
  fetch_ado_schema(:columns, [nil,nil,table_name.to_s,nil]) do |row|
282
282
  rows << AdoSchema::Column.new(row)
283
283
  end
284
- rows.sort!{|a,b| a["ORDINAL_POSITION"] <=> b["ORDINAL_POSITION"]}
284
+ rows.sort_by! { |a| a["ORDINAL_POSITION"] }
285
285
  end
286
286
 
287
287
  def ado_schema_foreign_keys(table_name)
@@ -289,7 +289,7 @@ module Sequel
289
289
  fetch_ado_schema(:foreign_keys, [nil,nil,nil,nil,nil,table_name.to_s]) do |row|
290
290
  rows << row
291
291
  end
292
- rows.sort!{|a,b| a["ORDINAL"] <=> b["ORDINAL"]}
292
+ rows.sort_by! { |a| a["ORDINAL"] }
293
293
  end
294
294
 
295
295
  def fetch_ado_schema(type, criteria=[])
@@ -234,7 +234,7 @@ module Sequel
234
234
  end
235
235
 
236
236
  def disconnect_error?(e, opts)
237
- super || (e.is_a?(::WIN32OLERuntimeError) && e.message =~ /Communication link failure/)
237
+ super || (e.is_a?(::WIN32OLERuntimeError) && e.message.include?('Communication link failure'))
238
238
  end
239
239
 
240
240
  def rollback_transaction(conn, opts=OPTS)
@@ -324,7 +324,7 @@ module Sequel
324
324
  when Numeric
325
325
  v.to_s
326
326
  when Date, Time
327
- literal(v).gsub("'", '')
327
+ literal(v).delete("'")
328
328
  else
329
329
  v
330
330
  end
@@ -26,7 +26,7 @@ module Sequel
26
26
 
27
27
  # Raise a disconnect error if the SQL state of the cause of the exception indicates so.
28
28
  def disconnect_error?(exception, opts)
29
- exception.message =~ /\ACommunications link failure/ || super
29
+ exception.message.start_with?("Communications link failure") || super
30
30
  end
31
31
 
32
32
  # Get the last inserted id using LAST_INSERT_ID().
@@ -64,7 +64,7 @@ module Sequel
64
64
 
65
65
  # Convert tinyint(1) type to boolean
66
66
  def schema_column_type(db_type)
67
- db_type =~ /\Atinyint\(1\)/ ? :boolean : super
67
+ db_type.start_with?("tinyint(1)") ? :boolean : super
68
68
  end
69
69
 
70
70
  # Run the default connection setting SQL statements.
@@ -55,7 +55,7 @@ module Sequel
55
55
  end
56
56
 
57
57
  def disconnect_error?(exception, opts)
58
- super || exception.message =~ /\AClosed Connection/
58
+ super || exception.message.start_with?("Closed Connection")
59
59
  end
60
60
 
61
61
  # Default the fetch size for statements to 100, similar to the oci8-based oracle adapter.
@@ -98,7 +98,7 @@ module Sequel
98
98
 
99
99
  # Whether the given exception is due to a foreign key error.
100
100
  def foreign_key_error?(exception)
101
- exception.message =~ /query does not return ResultSet/
101
+ exception.message.include?('query does not return ResultSet')
102
102
  end
103
103
 
104
104
  # Use getLong instead of getInt for converting integers on SQLite, since SQLite does not enforce a limit of 2**32.
@@ -84,7 +84,7 @@ module Sequel
84
84
  end
85
85
 
86
86
  def disconnect_error?(exception, opts)
87
- super || (exception.message =~ /connection is closed/)
87
+ super || (exception.message.include?('connection is closed'))
88
88
  end
89
89
  end
90
90
  end
@@ -305,17 +305,31 @@ module Sequel
305
305
  m = output_identifier_meth
306
306
  schema, table = metadata_schema_and_table(table, opts)
307
307
  foreign_keys = {}
308
+
308
309
  metadata(:getImportedKeys, nil, schema, table) do |r|
309
- if fk = foreign_keys[r[:fk_name]]
310
- fk[:columns] << [r[:key_seq], m.call(r[:fkcolumn_name])]
311
- fk[:key] << [r[:key_seq], m.call(r[:pkcolumn_name])]
312
- elsif r[:fk_name]
313
- foreign_keys[r[:fk_name]] = {:name=>m.call(r[:fk_name]), :columns=>[[r[:key_seq], m.call(r[:fkcolumn_name])]], :table=>m.call(r[:pktable_name]), :key=>[[r[:key_seq], m.call(r[:pkcolumn_name])]]}
310
+ next unless fk_name = r[:fk_name]
311
+
312
+ key_seq = r[:key_seq]
313
+ columns = [key_seq, m.call(r[:fkcolumn_name])]
314
+ key = [key_seq, m.call(r[:pkcolumn_name])]
315
+
316
+ if fk = foreign_keys[fk_name]
317
+ fk[:columns] << columns
318
+ fk[:key] << key
319
+ else
320
+ foreign_keys[fk_name] = {
321
+ :name=>m.call(fk_name),
322
+ :columns=>[columns],
323
+ :table=>m.call(r[:pktable_name]),
324
+ :key=>[key]
325
+ }
314
326
  end
315
327
  end
328
+
329
+ fk_keys = [:columns, :key]
316
330
  foreign_keys.values.each do |fk|
317
- [:columns, :key].each do |k|
318
- fk[k] = fk[k].sort.map{|_, v| v}
331
+ fk_keys.each do |k|
332
+ fk[k].sort!.map!{|_, v| v}
319
333
  end
320
334
  end
321
335
  end
@@ -290,7 +290,7 @@ module Sequel
290
290
 
291
291
  # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
292
292
  def schema_column_type(db_type)
293
- convert_tinyint_to_bool && db_type =~ /\Atinyint\(1\)/ ? :boolean : super
293
+ convert_tinyint_to_bool && db_type.start_with?("tinyint(1)") ? :boolean : super
294
294
  end
295
295
  end
296
296
 
@@ -221,13 +221,13 @@ module Sequel
221
221
  super ||
222
222
  ((conn = opts[:conn]) && !conn.ping) ||
223
223
  (e.is_a?(::Mysql2::Error) &&
224
- (e.sql_state =~ /\A08/ ||
224
+ ((e.sql_state && e.sql_state.start_with?("08")) ||
225
225
  MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)))
226
226
  end
227
227
 
228
228
  # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
229
229
  def schema_column_type(db_type)
230
- convert_tinyint_to_bool && db_type =~ /\Atinyint\(1\)/ ? :boolean : super
230
+ convert_tinyint_to_bool && db_type.start_with?("tinyint(1)") ? :boolean : super
231
231
  end
232
232
  end
233
233
 
@@ -81,7 +81,7 @@ module Sequel
81
81
  end
82
82
 
83
83
  def disconnect_error?(e, opts)
84
- super || (e.is_a?(::ODBC::Error) && /\A08S01/.match(e.message))
84
+ super || (e.is_a?(::ODBC::Error) && e.message.start_with?("08S01"))
85
85
  end
86
86
  end
87
87
 
@@ -108,7 +108,7 @@ module Sequel
108
108
  from(name).first
109
109
  true
110
110
  rescue DatabaseError => e
111
- if e.to_s =~ /Operation not allowed for reason code "7" on table/ && v == false
111
+ if e.to_s.include?('Operation not allowed for reason code "7" on table') && v == false
112
112
  # table probably needs reorg
113
113
  reorg(name)
114
114
  v = true
@@ -175,8 +175,13 @@ module Sequel
175
175
  # Supply columns with NOT NULL if they are part of a composite
176
176
  # primary key or unique constraint
177
177
  def column_list_sql(g)
178
- ks = []
179
- g.constraints.each{|c| ks = c[:columns] if [:primary_key, :unique].include?(c[:type])}
178
+ ks = {}
179
+ g.constraints.each do |c|
180
+ case c[:type]
181
+ when :primary_key, :unique
182
+ c[:columns].each{|c| ks[c] = true}
183
+ end
184
+ end
180
185
  g.columns.each{|c| c[:null] = false if ks.include?(c[:name]) }
181
186
  super
182
187
  end
@@ -705,7 +705,7 @@ module Sequel
705
705
 
706
706
  # Allows you to do a dirty read of uncommitted data using WITH (NOLOCK).
707
707
  def nolock
708
- lock_style(:dirty)
708
+ cached_lock_style_dataset(:_nolock_ds, :dirty)
709
709
  end
710
710
 
711
711
  # Uses OUTER APPLY to join the given table into the current dataset.
@@ -456,7 +456,7 @@ module Sequel
456
456
  [pk]
457
457
  elsif !(pkc = generator.constraints.select{|con| con[:type] == :primary_key}).empty?
458
458
  pkc.first[:columns]
459
- elsif !(pkc = generator.columns.select{|con| con[:primary_key] == true}).empty?
459
+ elsif !(pkc = generator.columns.select{|con| con[:primary_key]}).empty?
460
460
  pkc.map{|c| c[:name]}
461
461
  end
462
462
  else
@@ -787,7 +787,7 @@ module Sequel
787
787
 
788
788
  # Return a cloned dataset which will use LOCK IN SHARE MODE to lock returned rows.
789
789
  def for_share
790
- lock_style(:share)
790
+ cached_lock_style_dataset(:_for_share_ds, :share)
791
791
  end
792
792
 
793
793
  # Adds full text filter
@@ -48,7 +48,7 @@ module Sequel
48
48
  TYPE_TRANSLATOR_DATE = date.freeze
49
49
  bytea = Object.new
50
50
  def bytea.call(str)
51
- str = if str =~ /\A\\x/
51
+ str = if str.start_with?('\\x')
52
52
  # PostgreSQL 9.0+ bytea hex format
53
53
  str[2..-1].gsub(/(..)/){|s| s.to_i(16).chr}
54
54
  else
@@ -141,6 +141,17 @@ module Sequel
141
141
  @operations << {:op => :add_constraint, :type => :exclude, :elements => elements}.merge!(opts)
142
142
  end
143
143
 
144
+ # Alter an existing constraint. Options:
145
+ # :deferrable :: Modify deferrable setting for constraint (PostgreSQL 9.4+):
146
+ # true :: DEFERRABLE INITIALLY DEFERRED
147
+ # false :: NOT DEFERRABLE
148
+ # :immediate :: DEFERRABLE INITIALLY IMMEDIATE
149
+ # :enforced :: Set true to use ENFORCED, or false to use NOT ENFORCED (PostgreSQL 18+)
150
+ # :inherit :: Set true to use INHERIT, or false to use NO INHERIT (PostgreSQL 18+)
151
+ def alter_constraint(name, opts=OPTS)
152
+ @operations << {:op => :alter_constraint, :name => name}.merge!(opts)
153
+ end
154
+
144
155
  # Validate the constraint with the given name, which should have
145
156
  # been added previously with NOT VALID.
146
157
  def validate_constraint(name)
@@ -335,7 +346,7 @@ module Sequel
335
346
  hash = {}
336
347
  _check_constraints_ds.where_each(:conrelid=>regclass_oid(table)) do |row|
337
348
  constraint = m.call(row[:constraint])
338
- entry = hash[constraint] ||= {:definition=>row[:definition], :columns=>[]}
349
+ entry = hash[constraint] ||= {:definition=>row[:definition], :columns=>[], :validated=>row[:validated], :enforced=>row[:enforced]}
339
350
  entry[:columns] << m.call(row[:column]) if row[:column]
340
351
  end
341
352
 
@@ -601,6 +612,8 @@ module Sequel
601
612
  :on_update=>fklod_map[row[:on_update]],
602
613
  :on_delete=>fklod_map[row[:on_delete]],
603
614
  :deferrable=>row[:deferrable],
615
+ :validated=>row[:validated],
616
+ :enforced=>row[:enforced],
604
617
  :table=>schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table]),
605
618
  }
606
619
 
@@ -898,11 +911,15 @@ module Sequel
898
911
 
899
912
  # Dataset used to retrieve CHECK constraint information
900
913
  def _check_constraints_ds
901
- @_check_constraints_ds ||= metadata_dataset.
902
- from{pg_constraint.as(:co)}.
903
- left_join(Sequel[:pg_attribute].as(:att), :attrelid=>:conrelid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
904
- where(:contype=>'c').
905
- select{[co[:conname].as(:constraint), att[:attname].as(:column), pg_get_constraintdef(co[:oid]).as(:definition)]}
914
+ @_check_constraints_ds ||= begin
915
+ ds = metadata_dataset.
916
+ from{pg_constraint.as(:co)}.
917
+ left_join(Sequel[:pg_attribute].as(:att), :attrelid=>:conrelid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
918
+ where(:contype=>'c').
919
+ select{[co[:conname].as(:constraint), att[:attname].as(:column), pg_get_constraintdef(co[:oid]).as(:definition)]}
920
+
921
+ _add_validated_enforced_constraint_columns(ds)
922
+ end
906
923
  end
907
924
 
908
925
  # Dataset used to retrieve foreign keys referenced by a table
@@ -968,6 +985,28 @@ module Sequel
968
985
  ds = ds.order_append(Sequel[:nsp][:nspname], Sequel[:cl2][:relname])
969
986
  end
970
987
 
988
+ _add_validated_enforced_constraint_columns(ds)
989
+ end
990
+
991
+ def _add_validated_enforced_constraint_columns(ds)
992
+ validated_cond = if server_version >= 90100
993
+ Sequel[:convalidated]
994
+ # :nocov:
995
+ else
996
+ Sequel.cast(true, TrueClass)
997
+ # :nocov:
998
+ end
999
+ ds = ds.select_append(validated_cond.as(:validated))
1000
+
1001
+ enforced_cond = if server_version >= 180000
1002
+ Sequel[:conenforced]
1003
+ # :nocov:
1004
+ else
1005
+ Sequel.cast(true, TrueClass)
1006
+ # :nocov:
1007
+ end
1008
+ ds = ds.select_append(enforced_cond.as(:enforced))
1009
+
971
1010
  ds
972
1011
  end
973
1012
 
@@ -1140,6 +1179,31 @@ module Sequel
1140
1179
  "ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
1141
1180
  end
1142
1181
 
1182
+ def alter_table_alter_constraint_sql(table, op)
1183
+ sql = String.new
1184
+ sql << "ALTER CONSTRAINT #{quote_identifier(op[:name])}"
1185
+
1186
+ constraint_deferrable_sql_append(sql, op[:deferrable])
1187
+
1188
+ case op[:enforced]
1189
+ when nil
1190
+ when false
1191
+ sql << " NOT ENFORCED"
1192
+ else
1193
+ sql << " ENFORCED"
1194
+ end
1195
+
1196
+ case op[:inherit]
1197
+ when nil
1198
+ when false
1199
+ sql << " NO INHERIT"
1200
+ else
1201
+ sql << " INHERIT"
1202
+ end
1203
+
1204
+ sql
1205
+ end
1206
+
1143
1207
  def alter_table_generator_class
1144
1208
  Postgres::AlterTableGenerator
1145
1209
  end
@@ -1233,9 +1297,9 @@ module Sequel
1233
1297
  end
1234
1298
 
1235
1299
  # PostgreSQL can't combine rename_column operations, and it can combine
1236
- # the custom validate_constraint operation.
1300
+ # validate_constraint and alter_constraint operations.
1237
1301
  def combinable_alter_table_op?(op)
1238
- (super || op[:op] == :validate_constraint) && op[:op] != :rename_column
1302
+ (super || op[:op] == :validate_constraint || op[:op] == :alter_constraint) && op[:op] != :rename_column
1239
1303
  end
1240
1304
 
1241
1305
  VALID_CLIENT_MIN_MESSAGES = %w'DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC'.freeze.each(&:freeze)
@@ -1269,7 +1333,7 @@ module Sequel
1269
1333
  sqls
1270
1334
  end
1271
1335
 
1272
- # Handle exclusion constraints.
1336
+ # Handle PostgreSQL-specific constraint features.
1273
1337
  def constraint_definition_sql(constraint)
1274
1338
  case type = constraint[:type]
1275
1339
  when :exclude
@@ -1293,6 +1357,9 @@ module Sequel
1293
1357
  end
1294
1358
  else # when :foreign_key, :check
1295
1359
  sql = super
1360
+ if constraint[:not_enforced]
1361
+ sql << " NOT ENFORCED"
1362
+ end
1296
1363
  if constraint[:not_valid]
1297
1364
  sql << " NOT VALID"
1298
1365
  end
@@ -1300,6 +1367,13 @@ module Sequel
1300
1367
  end
1301
1368
  end
1302
1369
 
1370
+ def column_definition_add_references_sql(sql, column)
1371
+ super
1372
+ if column[:not_enforced]
1373
+ sql << " NOT ENFORCED"
1374
+ end
1375
+ end
1376
+
1303
1377
  def database_specific_error_class_from_sqlstate(sqlstate)
1304
1378
  if sqlstate == '23P01'
1305
1379
  ExclusionConstraintViolation
@@ -1369,7 +1443,8 @@ module Sequel
1369
1443
  # SQL statement to create database function.
1370
1444
  def create_function_sql(name, definition, opts=OPTS)
1371
1445
  args = opts[:args]
1372
- if !opts[:args].is_a?(Array) || !opts[:args].any?{|a| Array(a).length == 3 and %w'OUT INOUT'.include?(a[2].to_s)}
1446
+ in_out = %w'OUT INOUT'
1447
+ if (!opts[:args].is_a?(Array) || !opts[:args].any?{|a| Array(a).length == 3 && in_out.include?(a[2].to_s)})
1373
1448
  returns = opts[:returns] || 'void'
1374
1449
  end
1375
1450
  language = opts[:language] || 'SQL'
@@ -1932,9 +2007,22 @@ module Sequel
1932
2007
  end
1933
2008
  end
1934
2009
 
2010
+ # Return a cloned dataset which will use FOR KEY SHARE to lock returned rows.
2011
+ # Supported on PostgreSQL 9.3+.
2012
+ def for_key_share
2013
+ cached_lock_style_dataset(:_for_key_share_ds, :key_share)
2014
+ end
2015
+
2016
+ # Return a cloned dataset which will use FOR NO KEY UPDATE to lock returned rows.
2017
+ # This is generally a better choice than using for_update on PostgreSQL, unless
2018
+ # you will be deleting the row or modifying a key column. Supported on PostgreSQL 9.3+.
2019
+ def for_no_key_update
2020
+ cached_lock_style_dataset(:_for_no_key_update_ds, :no_key_update)
2021
+ end
2022
+
1935
2023
  # Return a cloned dataset which will use FOR SHARE to lock returned rows.
1936
2024
  def for_share
1937
- lock_style(:share)
2025
+ cached_lock_style_dataset(:_for_share_ds, :share)
1938
2026
  end
1939
2027
 
1940
2028
  # Run a full text search on PostgreSQL. By default, searching for the inclusion
@@ -2710,8 +2798,13 @@ module Sequel
2710
2798
  # Use SKIP LOCKED if skipping locked rows.
2711
2799
  def select_lock_sql(sql)
2712
2800
  lock = @opts[:lock]
2713
- if lock == :share
2801
+ case lock
2802
+ when :share
2714
2803
  sql << ' FOR SHARE'
2804
+ when :no_key_update
2805
+ sql << ' FOR NO KEY UPDATE'
2806
+ when :key_share
2807
+ sql << ' FOR KEY SHARE'
2715
2808
  else
2716
2809
  super
2717
2810
  end
@@ -95,14 +95,14 @@ module Sequel
95
95
  metadata_dataset.with_sql("PRAGMA index_list(?)", im.call(table)).each do |r|
96
96
  if opts[:only_autocreated]
97
97
  # If specifically asked for only autocreated indexes, then return those an only those
98
- next unless r[:name] =~ /\Asqlite_autoindex_/
98
+ next unless r[:name].start_with?('sqlite_autoindex_')
99
99
  elsif r.has_key?(:origin)
100
100
  # If origin is set, then only exclude primary key indexes and partial indexes
101
101
  next if r[:origin] == 'pk'
102
102
  next if r[:partial].to_i == 1
103
103
  else
104
104
  # When :origin key not present, assume any autoindex could be a primary key one and exclude it
105
- next if r[:name] =~ /\Asqlite_autoindex_/
105
+ next if r[:name].start_with?('sqlite_autoindex_')
106
106
  end
107
107
 
108
108
  indexes[m.call(r[:name])] = {:unique=>r[:unique].to_i==1}
@@ -302,7 +302,7 @@ module Sequel
302
302
 
303
303
  # A name to use for the backup table
304
304
  def backup_table_name(table, opts=OPTS)
305
- table = table.gsub('`', '')
305
+ table = table.delete('`')
306
306
  (opts[:times]||1000).times do |i|
307
307
  table_name = "#{table}_backup#{i}"
308
308
  return table_name unless table_exists?(table_name)
@@ -14,7 +14,7 @@ module Sequel
14
14
  opts = server_opts(server)
15
15
  opts[:username] = opts[:user]
16
16
  c = TinyTds::Client.new(opts)
17
- c.query_options.merge!(:cache_rows=>false)
17
+ c.query_options[:cache_rows] = false
18
18
 
19
19
  # SEQUEL6: Default to ansi: true
20
20
  if opts[:ansi]
@@ -83,7 +83,7 @@ module Sequel
83
83
 
84
84
  # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
85
85
  def schema_column_type(db_type)
86
- db_type =~ /\Atinyint\(1\)/ ? :boolean : super
86
+ db_type.start_with?("tinyint(1)") ? :boolean : super
87
87
  end
88
88
  end
89
89
 
@@ -236,7 +236,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
236
236
  def preconnect(concurrent = false)
237
237
  if concurrent
238
238
  if times = sync{@max_size > (size = @size[0]) ? @max_size - size : false}
239
- times.times.map{Thread.new{if conn = try_make_new; @queue.push(conn) end}}.map(&:value)
239
+ Array.new(times){Thread.new{if conn = try_make_new; @queue.push(conn) end}}.map(&:value)
240
240
  end
241
241
  else
242
242
  while conn = try_make_new
data/lib/sequel/core.rb CHANGED
@@ -403,7 +403,7 @@ module Sequel
403
403
  when -1, 0
404
404
  vr.instance_exec(&block)
405
405
  else
406
- block.call(vr)
406
+ yield(vr)
407
407
  end
408
408
  end
409
409
 
@@ -36,13 +36,13 @@ module Sequel
36
36
 
37
37
  # Register a hook that will be run when a new Database is instantiated. It is
38
38
  # called with the new database handle.
39
- def self.after_initialize(&block)
40
- raise Error, "must provide block to after_initialize" unless block
39
+ def self.after_initialize
40
+ raise Error, "must provide block to after_initialize" unless defined?(yield)
41
41
  Sequel.synchronize do
42
42
  previous = @initialize_hook
43
43
  @initialize_hook = proc do |db|
44
44
  previous.call(db)
45
- block.call(db)
45
+ yield(db)
46
46
  end
47
47
  end
48
48
  end
@@ -269,7 +269,7 @@ module Sequel
269
269
  def column_schema_to_ruby_default(default, type)
270
270
  return default unless default.is_a?(String)
271
271
  if COLUMN_SCHEMA_DATETIME_TYPES.include?(type)
272
- if /now|today|CURRENT|getdate|\ADate\(\)\z/i.match(default)
272
+ if /now|today|CURRENT|getdate|\ADate\(\)\z/i =~ default
273
273
  if type == :date
274
274
  return Sequel::CURRENT_DATE
275
275
  else
@@ -126,17 +126,21 @@ module Sequel
126
126
  # (:restrict, :cascade, :set_null, :set_default, :no_action).
127
127
  # :primary_key :: Make the column as a single primary key column. This should not
128
128
  # be used if you want a single autoincrementing primary key column
129
- # (use the primary_key method in that case).
130
- # :primary_key_constraint_name :: The name to give the primary key constraint
131
- # :primary_key_deferrable :: Similar to :deferrable, but for the primary key constraint
132
- # if :primary_key is used.
129
+ # (use the primary_key method in that case). Can be a hash to provide
130
+ # options for the constraint:
131
+ # :name :: The name to give the primary key constraint.
132
+ # :deferrable :: Sets whether the primary key constraint is deferrable.
133
+ # :primary_key_constraint_name :: Older option to name primary key constraint.
134
+ # :primary_key_deferrable :: Older option to set primary key constraint as deferrable.
133
135
  # :type :: Overrides the type given as the argument. Generally not used by column
134
136
  # itself, but can be passed as an option to other methods that call column.
135
137
  # :unique :: Mark the column as unique, generally has the same effect as
136
- # creating a unique index on the column.
137
- # :unique_constraint_name :: The name to give the unique key constraint
138
- # :unique_deferrable :: Similar to :deferrable, but for the unique constraint if :unique
139
- # is used.
138
+ # creating a unique index on the column. Can be a hash to provide options for
139
+ # the constraint:
140
+ # :name :: The name to give the unique constraint.
141
+ # :deferrable :: Sets whether the unique constraint is deferrable.
142
+ # :unique_constraint_name :: Older option to name unique constraint.
143
+ # :unique_deferrable :: Older option to set unique constraint as deferrable.
140
144
  #
141
145
  # PostgreSQL specific options:
142
146
  #
@@ -178,6 +182,7 @@ module Sequel
178
182
  # :deferrable :: Whether the CHECK constraint should be marked DEFERRABLE.
179
183
  #
180
184
  # PostgreSQL specific options:
185
+ # :not_enforced :: Whether the CHECK constraint should be marked NOT ENFORCED.
181
186
  # :not_valid :: Whether the CHECK constraint should be marked NOT VALID.
182
187
  def constraint(name, *args, &block)
183
188
  opts = name.is_a?(Hash) ? name : {:name=>name}
@@ -197,9 +202,18 @@ module Sequel
197
202
  #
198
203
  # :foreign_key_constraint_name :: The name to give the foreign key constraint
199
204
  #
205
+ # PostgreSQL specific options:
206
+ #
207
+ # :not_enforced :: Whether the foreign key constraint should be marked NOT ENFORCED.
208
+ #
200
209
  # If you want a foreign key constraint without adding a column (usually because it is a
201
- # composite foreign key), you can provide an array of columns as the first argument, and
202
- # you can provide the :name option to name the constraint:
210
+ # composite foreign key), you can provide an array of columns as the first argument.
211
+ # This changes the method to accept constraint options instead of column options.
212
+ # You can provide the :name option to name the constraint.
213
+ #
214
+ # PostgreSQL specific options:
215
+ #
216
+ # :not_enforced :: Whether the foreign key constraint should be marked NOT ENFORCED.
203
217
  #
204
218
  # foreign_key([:artist_name, :artist_location], :artists, name: :artist_fk)
205
219
  # # ADD CONSTRAINT artist_fk FOREIGN KEY (artist_name, artist_location) REFERENCES artists
@@ -605,36 +605,63 @@ module Sequel
605
605
  end
606
606
  end
607
607
 
608
- # Add primary key SQL fragment to column creation SQL.
608
+ # Add primary key SQL fragment to column creation SQL if column is a primary key.
609
609
  def column_definition_primary_key_sql(sql, column)
610
- if column[:primary_key]
611
- if name = column[:primary_key_constraint_name]
612
- sql << " CONSTRAINT #{quote_identifier(name)}"
613
- end
614
- sql << " " << primary_key_constraint_sql_fragment(column)
615
- constraint_deferrable_sql_append(sql, column[:primary_key_deferrable])
616
- end
610
+ column_definition_add_primary_key_sql(sql, column) if column[:primary_key]
611
+ end
612
+
613
+ # Add primary key SQL fragment to column creation SQL (column should be a primary key).
614
+ def column_definition_add_primary_key_sql(sql, column)
615
+ constraint = column_definition_constraint_hash(column, :primary_key)
616
+ append_named_constraint_prefix_sql(sql, constraint[:name])
617
+ sql << " " << primary_key_constraint_sql_fragment(constraint)
618
+ constraint_deferrable_sql_append(sql, constraint[:deferrable])
617
619
  end
618
620
 
619
- # Add foreign key reference SQL fragment to column creation SQL.
621
+ # Add foreign key reference SQL fragment to column creation SQL if column is a foreign key.
620
622
  def column_definition_references_sql(sql, column)
621
- if column[:table]
622
- if name = column[:foreign_key_constraint_name]
623
- sql << " CONSTRAINT #{quote_identifier(name)}"
624
- end
625
- sql << column_references_column_constraint_sql(column)
626
- end
623
+ column_definition_add_references_sql(sql, column) if column[:table]
624
+ end
625
+
626
+ # Add foreign key reference SQL fragment to column creation SQL (column should be a foreign key).
627
+ def column_definition_add_references_sql(sql, column)
628
+ append_named_constraint_prefix_sql(sql, column[:foreign_key_constraint_name])
629
+ sql << column_references_column_constraint_sql(column)
627
630
  end
628
631
 
629
- # Add unique constraint SQL fragment to column creation SQL.
632
+ # Add unique constraint SQL fragment to column creation SQL if column has a unique constraint.
630
633
  def column_definition_unique_sql(sql, column)
631
- if column[:unique]
632
- if name = column[:unique_constraint_name]
633
- sql << " CONSTRAINT #{quote_identifier(name)}"
634
- end
635
- sql << ' ' << unique_constraint_sql_fragment(column)
636
- constraint_deferrable_sql_append(sql, column[:unique_deferrable])
634
+ column_definition_add_unique_sql(sql, column) if column[:unique]
635
+ end
636
+
637
+ # Add unique constraint SQL fragment to column creation SQL (column should have unique constraint).
638
+ def column_definition_add_unique_sql(sql, column)
639
+ constraint = column_definition_constraint_hash(column, :unique)
640
+ append_named_constraint_prefix_sql(sql, constraint[:name])
641
+ sql << ' ' << unique_constraint_sql_fragment(constraint)
642
+ constraint_deferrable_sql_append(sql, constraint[:deferrable])
643
+ end
644
+
645
+ # Add the name of the constraint to the column creation SQL.
646
+ def append_named_constraint_prefix_sql(sql, name)
647
+ sql << " CONSTRAINT #{quote_identifier(name)}" if name
648
+ end
649
+
650
+ # Return a hash of constraint options for the primary key or column
651
+ # unique constraint.
652
+ def column_definition_constraint_hash(column, prefix)
653
+ constraint = column[prefix]
654
+ constraint = constraint.is_a?(Hash) ? constraint.dup : {}
655
+
656
+ if name = column[:"#{prefix}_constraint_name"]
657
+ constraint[:name] = name
637
658
  end
659
+
660
+ if column.has_key?(:"#{prefix}_deferrable")
661
+ constraint[:deferrable] = column[:"#{prefix}_deferrable"]
662
+ end
663
+
664
+ constraint
638
665
  end
639
666
 
640
667
  # SQL for all given columns, used inside a CREATE TABLE block.
@@ -677,7 +704,7 @@ module Sequel
677
704
  check = constraint[:check]
678
705
  check = check.first if check.is_a?(Array) && check.length == 1
679
706
  check = filter_expr(check)
680
- check = "(#{check})" unless check[0..0] == '(' && check[-1..-1] == ')'
707
+ check = "(#{check})" unless check.start_with?('(') && check.end_with?(')')
681
708
  sql << "CHECK #{check}"
682
709
  when :primary_key
683
710
  sql << "#{primary_key_constraint_sql_fragment(constraint)} #{literal(constraint[:columns])}"
@@ -733,17 +760,24 @@ module Sequel
733
760
  def create_table_sql(name, generator, options)
734
761
  unless supports_named_column_constraints?
735
762
  # Split column constraints into table constraints if they have a name
763
+ fk_opt_keys = [:key, :on_delete, :on_update, :deferrable]
736
764
  generator.columns.each do |c|
737
765
  if (constraint_name = c.delete(:foreign_key_constraint_name)) && (table = c.delete(:table))
738
766
  opts = {}
739
767
  opts[:name] = constraint_name
740
- [:key, :on_delete, :on_update, :deferrable].each{|k| opts[k] = c[k]}
768
+ fk_opt_keys.each{|k| opts[k] = c[k]}
741
769
  generator.foreign_key([c[:name]], table, opts)
742
770
  end
743
- if (constraint_name = c.delete(:unique_constraint_name)) && c.delete(:unique)
771
+
772
+ if c[:unique].is_a?(Hash) && c[:unique][:name]
773
+ generator.unique(c[:name], c.delete(:unique))
774
+ elsif (constraint_name = c.delete(:unique_constraint_name)) && c.delete(:unique)
744
775
  generator.unique(c[:name], :name=>constraint_name)
745
776
  end
746
- if (constraint_name = c.delete(:primary_key_constraint_name)) && c.delete(:primary_key)
777
+
778
+ if c[:primary_key].is_a?(Hash) && c[:primary_key][:name]
779
+ generator.primary_key([c[:name]], c.delete(:primary_key))
780
+ elsif (constraint_name = c.delete(:primary_key_constraint_name)) && c.delete(:primary_key)
747
781
  generator.primary_key([c[:name]], :name=>constraint_name)
748
782
  end
749
783
  end
@@ -231,8 +231,7 @@ module Sequel
231
231
  #
232
232
  # DB[:table].for_update # SELECT * FROM table FOR UPDATE
233
233
  def for_update
234
- return self if opts[:lock] == :update
235
- cached_dataset(:_for_update_ds){lock_style(:update)}
234
+ cached_lock_style_dataset(:_for_update_ds, :update)
236
235
  end
237
236
 
238
237
  # Returns a copy of the dataset with the source changed. If no
@@ -1462,6 +1461,15 @@ module Sequel
1462
1461
  end
1463
1462
  end
1464
1463
 
1464
+ # Internals of for_update and adapter-specific lock methods.
1465
+ # Returns receiver if it already uses this lock style, and a cached
1466
+ # dataset using the given key otherwise. The key could be derived from
1467
+ # the style, but doing so would require allocation, so pass it in as
1468
+ # an argument.
1469
+ def cached_lock_style_dataset(key, style)
1470
+ opts[:lock] == style ? self : cached_dataset(key){lock_style(style)}
1471
+ end
1472
+
1465
1473
  # The default :qualify option to use for join tables if one is not specified.
1466
1474
  def default_join_table_qualification
1467
1475
  :symbol
@@ -1339,7 +1339,7 @@ module Sequel
1339
1339
  # SQL fragment specifying a JOIN type, converts underscores to
1340
1340
  # spaces and upcases.
1341
1341
  def join_type_sql(join_type)
1342
- "#{join_type.to_s.gsub('_', ' ').upcase} JOIN"
1342
+ "#{join_type.to_s.tr('_', ' ').upcase} JOIN"
1343
1343
  end
1344
1344
 
1345
1345
  # Append USING clause for JOIN USING
@@ -357,7 +357,7 @@ module Sequel
357
357
  define_singleton_method(:async_job_class){proxy_klass}
358
358
 
359
359
  queue = @async_thread_queue = Queue.new
360
- pool = @async_thread_pool = num_async_threads.times.map{JobProcessor.new(queue)}
360
+ pool = @async_thread_pool = Array.new(num_async_threads){JobProcessor.new(queue)}
361
361
  ObjectSpace.define_finalizer(db, JobProcessor.create_finalizer(queue, pool))
362
362
 
363
363
  extend_datasets(DatasetMethods)
@@ -60,9 +60,7 @@ module Sequel
60
60
  def external_caller_for_log
61
61
  ignore = caller_logging_ignore
62
62
  c = caller.find do |line|
63
- !(line.start_with?(SEQUEL_LIB_PATH) ||
64
- line.start_with?(RUBY_STDLIB) ||
65
- line.start_with?(INTERNAL) ||
63
+ !(line.start_with?(SEQUEL_LIB_PATH, RUBY_STDLIB, INTERNAL) ||
66
64
  (ignore && line =~ ignore))
67
65
  end
68
66
 
@@ -66,7 +66,7 @@ module Sequel
66
66
  # in the order they were defined.
67
67
  klass = self.class
68
68
  args = inspect_args.map do |arg|
69
- if arg.is_a?(String) && arg =~ /\A\*/
69
+ if arg.is_a?(String) && arg.start_with?('*')
70
70
  # Special case string arguments starting with *, indicating that
71
71
  # they should return an array to be splatted as the remaining arguments.
72
72
  # Allow calling private methods to get inspect output.
@@ -159,7 +159,7 @@ class String
159
159
  # Example
160
160
  # "puni_puni".dasherize #=> "puni-puni"
161
161
  def dasherize
162
- gsub('_', '-')
162
+ tr('_', '-')
163
163
  end
164
164
 
165
165
  # Removes the module part from the expression in the string
@@ -189,7 +189,7 @@ class String
189
189
  # "employee_salary" #=> "Employee salary"
190
190
  # "author_id" #=> "Author"
191
191
  def humanize
192
- gsub(/_id$/, "").gsub('_', " ").capitalize
192
+ gsub(/_id$/, "").tr('_', " ").capitalize
193
193
  end
194
194
 
195
195
  # Returns the plural form of the word in the string.
@@ -845,7 +845,7 @@ module Sequel
845
845
  begin
846
846
  db.create_table(table){String c, :primary_key=>true}
847
847
  rescue Sequel::DatabaseError => e
848
- if db.database_type == :mysql && e.message =~ /max key length/
848
+ if db.database_type == :mysql && e.message.include?('max key length')
849
849
  # Handle case where MySQL is used with utf8mb4 charset default, which
850
850
  # only allows a maximum length of about 190 characters for string
851
851
  # primary keys due to InnoDB limitations.
@@ -136,7 +136,7 @@ module Sequel
136
136
  module DatabaseMethods
137
137
  def self.extended(db)
138
138
  db.instance_exec do
139
- add_named_conversion_proc(:hstore, &HStore.method(:parse))
139
+ add_named_conversion_proc(:hstore){|v| HStore.parse(v)}
140
140
  @schema_type_classes[:hstore] = HStore
141
141
  end
142
142
  end
@@ -97,9 +97,7 @@ module Sequel
97
97
  def provenance_source
98
98
  ignore = db.opts[:provenance_caller_ignore]
99
99
  caller.find do |line|
100
- !(line.start_with?(SEQUEL_LIB_PATH) ||
101
- line.start_with?(RUBY_STDLIB) ||
102
- line.start_with?(INTERNAL) ||
100
+ !(line.start_with?(SEQUEL_LIB_PATH, RUBY_STDLIB, INTERNAL) ||
103
101
  (ignore && line =~ ignore))
104
102
  end
105
103
  end
@@ -221,7 +221,7 @@ END_MIG
221
221
  else
222
222
  col_opts = if options[:same_db]
223
223
  h = {:type=>schema[:db_type]}
224
- if database_type == :mysql && h[:type] =~ /\Atimestamp/
224
+ if database_type == :mysql && h[:type].start_with?("timestamp")
225
225
  h[:null] = true
226
226
  end
227
227
  if database_type == :mssql && schema[:max_length]
@@ -164,7 +164,7 @@ module Sequel
164
164
  arg = constraint_validation_int_range(arg)
165
165
  type = :includes
166
166
  when *OPERATOR_MAP.keys
167
- arg = arg.to_i if type.to_s =~ /\Aint_/
167
+ arg = arg.to_i if type.to_s.start_with?('int_')
168
168
  operator = OPERATOR_MAP[type]
169
169
  type = :operator
170
170
  end
@@ -370,9 +370,9 @@ module Sequel
370
370
  end
371
371
 
372
372
  # Convert the receiver to a JSON data structure using the given arguments.
373
- def to_json_data(*args, &block)
374
- if block
375
- to_json(*args){|x| return block.call(x)}
373
+ def to_json_data(*args)
374
+ if defined?(yield)
375
+ to_json(*args){|x| return yield(x)}
376
376
  else
377
377
  to_json(*args){|x| return x}
378
378
  end
@@ -347,6 +347,8 @@ module Sequel
347
347
  coverage_data = options[:coverage_data] || Sequel.parse_json(File.binread(@unused_associations_coverage_file))
348
348
 
349
349
  unused_associations_data = {}
350
+ to_many_modification_methods = [:adder, :remover, :clearer]
351
+ modification_methods = [:setter, :adder, :remover, :clearer]
350
352
 
351
353
  ([self] + descendants).each do |sc|
352
354
  next unless cov_data = coverage_data[sc.name]
@@ -383,8 +385,8 @@ module Sequel
383
385
  if !info[:used]
384
386
  (unused_associations_data[sc.name] ||= {})[assoc.to_s] = 'unused'
385
387
  elsif unused = info[:unused]
386
- if unused.include?(:setter) || [:adder, :remover, :clearer].all?{|k| unused.include?(k)}
387
- [:setter, :adder, :remover, :clearer].each do |k|
388
+ if unused.include?(:setter) || to_many_modification_methods.all?{|k| unused.include?(k)}
389
+ modification_methods.each do |k|
388
390
  unused.delete(k)
389
391
  end
390
392
  unused << :read_only
@@ -208,7 +208,7 @@ module Sequel
208
208
  next if an && Array(v).all?(&:nil?)
209
209
  next if ab && Array(v).all?(&blank_meth)
210
210
  next if am && Array(a).all?{|x| !o.values.has_key?(x)}
211
- block.call(o,a,v)
211
+ yield(o, a, v)
212
212
  end
213
213
  else
214
214
  block
@@ -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 = 93
9
+ MINOR = 94
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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.93.0
4
+ version: 5.94.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans