activerecord 7.2.2 → 8.0.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.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +239 -878
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/association_relation.rb +1 -0
  5. data/lib/active_record/associations/association.rb +34 -10
  6. data/lib/active_record/associations/builder/association.rb +7 -6
  7. data/lib/active_record/associations/collection_association.rb +10 -8
  8. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  9. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  10. data/lib/active_record/associations/preloader/association.rb +2 -2
  11. data/lib/active_record/associations/singular_association.rb +8 -3
  12. data/lib/active_record/associations.rb +34 -4
  13. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  14. data/lib/active_record/attribute_methods/primary_key.rb +2 -7
  15. data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
  16. data/lib/active_record/attribute_methods.rb +1 -1
  17. data/lib/active_record/autosave_association.rb +69 -27
  18. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  19. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  20. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  21. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +0 -9
  22. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  23. data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
  24. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  25. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  26. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -2
  27. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +33 -6
  28. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  29. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -26
  30. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +21 -39
  31. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  32. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  33. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
  34. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  35. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  36. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  37. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  38. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  39. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  40. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
  41. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +6 -12
  42. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
  43. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +59 -16
  44. data/lib/active_record/connection_adapters/postgresql_adapter.rb +45 -95
  45. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  46. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  47. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  48. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  49. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
  50. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
  51. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  52. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  53. data/lib/active_record/connection_adapters.rb +0 -56
  54. data/lib/active_record/connection_handling.rb +22 -0
  55. data/lib/active_record/core.rb +18 -14
  56. data/lib/active_record/database_configurations/database_config.rb +4 -0
  57. data/lib/active_record/database_configurations/hash_config.rb +8 -0
  58. data/lib/active_record/encryption/config.rb +3 -1
  59. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  60. data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
  61. data/lib/active_record/encryption/encryptor.rb +15 -8
  62. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  63. data/lib/active_record/encryption/scheme.rb +8 -1
  64. data/lib/active_record/enum.rb +9 -22
  65. data/lib/active_record/errors.rb +13 -5
  66. data/lib/active_record/fixtures.rb +0 -2
  67. data/lib/active_record/future_result.rb +14 -10
  68. data/lib/active_record/gem_version.rb +3 -3
  69. data/lib/active_record/insert_all.rb +1 -1
  70. data/lib/active_record/locking/optimistic.rb +1 -1
  71. data/lib/active_record/log_subscriber.rb +5 -11
  72. data/lib/active_record/migration/command_recorder.rb +27 -10
  73. data/lib/active_record/migration/compatibility.rb +5 -2
  74. data/lib/active_record/migration.rb +35 -38
  75. data/lib/active_record/model_schema.rb +3 -4
  76. data/lib/active_record/nested_attributes.rb +4 -6
  77. data/lib/active_record/persistence.rb +128 -130
  78. data/lib/active_record/query_logs.rb +102 -50
  79. data/lib/active_record/query_logs_formatter.rb +17 -28
  80. data/lib/active_record/querying.rb +8 -8
  81. data/lib/active_record/railtie.rb +2 -26
  82. data/lib/active_record/railties/databases.rake +2 -17
  83. data/lib/active_record/reflection.rb +18 -21
  84. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  85. data/lib/active_record/relation/batches.rb +132 -72
  86. data/lib/active_record/relation/calculations.rb +40 -39
  87. data/lib/active_record/relation/delegation.rb +25 -14
  88. data/lib/active_record/relation/finder_methods.rb +18 -18
  89. data/lib/active_record/relation/merger.rb +8 -8
  90. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  91. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  92. data/lib/active_record/relation/predicate_builder.rb +13 -0
  93. data/lib/active_record/relation/query_methods.rb +115 -65
  94. data/lib/active_record/relation/spawn_methods.rb +1 -1
  95. data/lib/active_record/relation.rb +79 -61
  96. data/lib/active_record/result.rb +66 -4
  97. data/lib/active_record/sanitization.rb +7 -6
  98. data/lib/active_record/schema_dumper.rb +5 -0
  99. data/lib/active_record/schema_migration.rb +2 -1
  100. data/lib/active_record/scoping/named.rb +5 -2
  101. data/lib/active_record/statement_cache.rb +12 -12
  102. data/lib/active_record/store.rb +7 -3
  103. data/lib/active_record/table_metadata.rb +1 -3
  104. data/lib/active_record/tasks/database_tasks.rb +48 -47
  105. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  106. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  107. data/lib/active_record/test_fixtures.rb +12 -0
  108. data/lib/active_record/token_for.rb +1 -1
  109. data/lib/active_record/validations/uniqueness.rb +8 -8
  110. data/lib/active_record.rb +15 -45
  111. data/lib/arel/collectors/bind.rb +1 -1
  112. data/lib/arel/table.rb +3 -7
  113. metadata +11 -12
  114. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -89,6 +89,7 @@ module ActiveRecord
89
89
  class_attribute :belongs_to_required_by_default, instance_accessor: false
90
90
 
91
91
  class_attribute :strict_loading_by_default, instance_accessor: false, default: false
92
+ class_attribute :strict_loading_mode, instance_accessor: false, default: :all
92
93
 
93
94
  class_attribute :has_many_inversing, instance_accessor: false, default: false
94
95
 
@@ -381,7 +382,7 @@ module ActiveRecord
381
382
  end
382
383
 
383
384
  def predicate_builder # :nodoc:
384
- @predicate_builder ||= PredicateBuilder.new(table_metadata)
385
+ @predicate_builder ||= PredicateBuilder.new(TableMetadata.new(self, arel_table))
385
386
  end
386
387
 
387
388
  def type_caster # :nodoc:
@@ -426,10 +427,6 @@ module ActiveRecord
426
427
  end
427
428
  end
428
429
 
429
- def table_metadata
430
- TableMetadata.new(self, arel_table)
431
- end
432
-
433
430
  def cached_find_by(keys, values)
434
431
  with_connection do |connection|
435
432
  statement = cached_find_by_statement(connection, keys) { |params|
@@ -443,8 +440,8 @@ module ActiveRecord
443
440
  where(wheres).limit(1)
444
441
  }
445
442
 
446
- begin
447
- statement.execute(values.flatten, connection, allow_retry: true).first
443
+ statement.execute(values.flatten, connection, allow_retry: true).then do |r|
444
+ r.first
448
445
  rescue TypeError
449
446
  raise ActiveRecord::StatementInvalid
450
447
  end
@@ -540,12 +537,7 @@ module ActiveRecord
540
537
 
541
538
  ##
542
539
  def initialize_dup(other) # :nodoc:
543
- @attributes = @attributes.deep_dup
544
- if self.class.composite_primary_key?
545
- @primary_key.each { |key| @attributes.reset(key) }
546
- else
547
- @attributes.reset(@primary_key)
548
- end
540
+ @attributes = init_attributes(other)
549
541
 
550
542
  _run_initialize_callbacks
551
543
 
@@ -557,6 +549,18 @@ module ActiveRecord
557
549
  super
558
550
  end
559
551
 
552
+ def init_attributes(_) # :nodoc:
553
+ attrs = @attributes.deep_dup
554
+
555
+ if self.class.composite_primary_key?
556
+ @primary_key.each { |key| attrs.reset(key) }
557
+ else
558
+ attrs.reset(@primary_key)
559
+ end
560
+
561
+ attrs
562
+ end
563
+
560
564
  # Populate +coder+ with attributes about this record that should be
561
565
  # serialized. The structure of +coder+ defined in this method is
562
566
  # guaranteed to match the structure of +coder+ passed to the #init_with
@@ -810,7 +814,7 @@ module ActiveRecord
810
814
 
811
815
  @primary_key = klass.primary_key
812
816
  @strict_loading = klass.strict_loading_by_default
813
- @strict_loading_mode = :all
817
+ @strict_loading_mode = klass.strict_loading_mode
814
818
 
815
819
  klass.define_attribute_methods
816
820
  end
@@ -99,6 +99,10 @@ module ActiveRecord
99
99
  def use_metadata_table?
100
100
  raise NotImplementedError
101
101
  end
102
+
103
+ def seeds?
104
+ raise NotImplementedError
105
+ end
102
106
  end
103
107
  end
104
108
  end
@@ -130,6 +130,14 @@ module ActiveRecord
130
130
  Base.configurations.primary?(name)
131
131
  end
132
132
 
133
+ # Determines whether the db:prepare task should seed the database from db/seeds.rb.
134
+ #
135
+ # If the `seeds` key is present in the config, `seeds?` will return its value. Otherwise, it
136
+ # will return `true` for the primary database and `false` for all other configs.
137
+ def seeds?
138
+ configuration_hash.fetch(:seeds, primary?)
139
+ end
140
+
133
141
  # Determines whether to dump the schema/structure files and the filename that
134
142
  # should be used.
135
143
  #
@@ -8,7 +8,8 @@ module ActiveRecord
8
8
  class Config
9
9
  attr_accessor :primary_key, :deterministic_key, :store_key_references, :key_derivation_salt, :hash_digest_class,
10
10
  :support_unencrypted_data, :encrypt_fixtures, :validate_column_size, :add_to_filter_parameters,
11
- :excluded_from_filter_parameters, :extend_queries, :previous_schemes, :forced_encoding_for_deterministic_encryption
11
+ :excluded_from_filter_parameters, :extend_queries, :previous_schemes, :forced_encoding_for_deterministic_encryption,
12
+ :compressor
12
13
 
13
14
  def initialize
14
15
  set_defaults
@@ -55,6 +56,7 @@ module ActiveRecord
55
56
  self.previous_schemes = []
56
57
  self.forced_encoding_for_deterministic_encryption = Encoding::UTF_8
57
58
  self.hash_digest_class = OpenSSL::Digest::SHA1
59
+ self.compressor = Zlib
58
60
 
59
61
  # TODO: Setting to false for now as the implementation is a bit experimental
60
62
  self.extend_queries = false
@@ -46,11 +46,11 @@ module ActiveRecord
46
46
  # * <tt>:previous</tt> - List of previous encryption schemes. When provided, they will be used in order when trying to read
47
47
  # the attribute. Each entry of the list can contain the properties supported by #encrypts. Also, when deterministic
48
48
  # encryption is used, they will be used to generate additional ciphertexts to check in the queries.
49
- def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
49
+ def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
50
50
  self.encrypted_attributes ||= Set.new # not using :default because the instance would be shared across classes
51
51
 
52
52
  names.each do |name|
53
- encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
53
+ encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties
54
54
  end
55
55
  end
56
56
 
@@ -81,12 +81,12 @@ module ActiveRecord
81
81
  end
82
82
  end
83
83
 
84
- def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
84
+ def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
85
85
  encrypted_attributes << name.to_sym
86
86
 
87
87
  decorate_attributes([name]) do |name, cast_type|
88
88
  scheme = scheme_for key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, \
89
- downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
89
+ downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties
90
90
 
91
91
  ActiveRecord::Encryption::EncryptedAttributeType.new(scheme: scheme, cast_type: cast_type, default: columns_hash[name.to_s]&.default)
92
92
  end
@@ -100,7 +100,7 @@ module ActiveRecord
100
100
  end
101
101
 
102
102
  def decrypt(value)
103
- text_to_database_type decrypt_as_text(value)
103
+ text_to_database_type decrypt_as_text(database_type_to_text(value))
104
104
  end
105
105
 
106
106
  def try_to_deserialize_with_previous_encrypted_types(value)
@@ -170,6 +170,15 @@ module ActiveRecord
170
170
  value
171
171
  end
172
172
  end
173
+
174
+ def database_type_to_text(value)
175
+ if value && cast_type.binary?
176
+ binary_cast_type = cast_type.serialized? ? cast_type.subtype : cast_type
177
+ binary_cast_type.deserialize(value)
178
+ else
179
+ value
180
+ end
181
+ end
173
182
  end
174
183
  end
175
184
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openssl"
4
- require "zlib"
5
4
  require "active_support/core_ext/numeric"
6
5
 
7
6
  module ActiveRecord
@@ -12,12 +11,20 @@ module ActiveRecord
12
11
  # It interacts with a KeyProvider for getting the keys, and delegate to
13
12
  # ActiveRecord::Encryption::Cipher the actual encryption algorithm.
14
13
  class Encryptor
14
+ # The compressor to use for compressing the payload
15
+ attr_reader :compressor
16
+
15
17
  # === Options
16
18
  #
17
19
  # * <tt>:compress</tt> - Boolean indicating whether records should be compressed before encryption.
18
20
  # Defaults to +true+.
19
- def initialize(compress: true)
21
+ # * <tt>:compressor</tt> - The compressor to use.
22
+ # 1. If compressor is provided, it will be used.
23
+ # 2. If not, it will use ActiveRecord::Encryption.config.compressor which default value is +Zlib+.
24
+ # If you want to use a custom compressor, it must respond to +deflate+ and +inflate+.
25
+ def initialize(compress: true, compressor: nil)
20
26
  @compress = compress
27
+ @compressor = compressor || ActiveRecord::Encryption.config.compressor
21
28
  end
22
29
 
23
30
  # Encrypts +clean_text+ and returns the encrypted result
@@ -78,6 +85,10 @@ module ActiveRecord
78
85
  serializer.binary?
79
86
  end
80
87
 
88
+ def compress? # :nodoc:
89
+ @compress
90
+ end
91
+
81
92
  private
82
93
  DECRYPT_ERRORS = [OpenSSL::Cipher::CipherError, Errors::EncryptedContentIntegrity, Errors::Decryption]
83
94
  ENCODING_ERRORS = [EncodingError, Errors::Encoding]
@@ -130,12 +141,8 @@ module ActiveRecord
130
141
  end
131
142
  end
132
143
 
133
- def compress?
134
- @compress
135
- end
136
-
137
144
  def compress(data)
138
- Zlib::Deflate.deflate(data).tap do |compressed_data|
145
+ @compressor.deflate(data).tap do |compressed_data|
139
146
  compressed_data.force_encoding(data.encoding)
140
147
  end
141
148
  end
@@ -149,7 +156,7 @@ module ActiveRecord
149
156
  end
150
157
 
151
158
  def uncompress(data)
152
- Zlib::Inflate.inflate(data).tap do |uncompressed_data|
159
+ @compressor.inflate(data).tap do |uncompressed_data|
153
160
  uncompressed_data.force_encoding(data.encoding)
154
161
  end
155
162
  end
@@ -41,6 +41,8 @@ module ActiveRecord
41
41
  module EncryptedQuery # :nodoc:
42
42
  class << self
43
43
  def process_arguments(owner, args, check_for_additional_values)
44
+ owner = owner.model if owner.is_a?(Relation)
45
+
44
46
  return args if owner.deterministic_encrypted_attributes&.empty?
45
47
 
46
48
  if args.is_a?(Array) && (options = args.first).is_a?(Hash)
@@ -102,12 +104,12 @@ module ActiveRecord
102
104
  end
103
105
 
104
106
  def scope_for_create
105
- return super unless klass.deterministic_encrypted_attributes&.any?
107
+ return super unless model.deterministic_encrypted_attributes&.any?
106
108
 
107
109
  scope_attributes = super
108
110
  wheres = where_values_hash
109
111
 
110
- klass.deterministic_encrypted_attributes.each do |attribute_name|
112
+ model.deterministic_encrypted_attributes.each do |attribute_name|
111
113
  attribute_name = attribute_name.to_s
112
114
  values = wheres[attribute_name]
113
115
  if values.is_a?(Array) && values[1..].all?(AdditionalValue)
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  attr_accessor :previous_schemes
12
12
 
13
13
  def initialize(key_provider: nil, key: nil, deterministic: nil, support_unencrypted_data: nil, downcase: nil, ignore_case: nil,
14
- previous_schemes: nil, **context_properties)
14
+ previous_schemes: nil, compress: true, compressor: nil, **context_properties)
15
15
  # Initializing all attributes to +nil+ as we want to allow a "not set" semantics so that we
16
16
  # can merge schemes without overriding values with defaults. See +#merge+
17
17
 
@@ -24,8 +24,13 @@ module ActiveRecord
24
24
  @previous_schemes_param = previous_schemes
25
25
  @previous_schemes = Array.wrap(previous_schemes)
26
26
  @context_properties = context_properties
27
+ @compress = compress
28
+ @compressor = compressor
27
29
 
28
30
  validate_config!
31
+
32
+ @context_properties[:encryptor] = Encryptor.new(compress: @compress) unless @compress
33
+ @context_properties[:encryptor] = Encryptor.new(compressor: compressor) if compressor
29
34
  end
30
35
 
31
36
  def ignore_case?
@@ -78,6 +83,8 @@ module ActiveRecord
78
83
  def validate_config!
79
84
  raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
80
85
  raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
86
+ raise Errors::Configuration, "compressor: can't be used with compress: false" if !@compress && @compressor
87
+ raise Errors::Configuration, "compressor: can't be used with encryptor" if @compressor && @context_properties[:encryptor]
81
88
  end
82
89
 
83
90
  def key_provider_from_key
@@ -213,34 +213,16 @@ module ActiveRecord
213
213
  attr_reader :name, :mapping
214
214
  end
215
215
 
216
- def enum(name = nil, values = nil, **options)
217
- if name
218
- values, options = options, {} unless values
219
- return _enum(name, values, **options)
220
- end
221
-
222
- definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
223
- options.transform_keys! { |key| :"#{key[1..-1]}" }
224
-
225
- definitions.each { |name, values| _enum(name, values, **options) }
226
-
227
- ActiveRecord.deprecator.warn(<<~MSG)
228
- Defining enums with keyword arguments is deprecated and will be removed
229
- in Rails 8.0. Positional arguments should be used instead:
230
-
231
- #{definitions.map { |name, values| "enum :#{name}, #{values}" }.join("\n")}
232
- MSG
216
+ def enum(name, values = nil, **options)
217
+ values, options = options, {} unless values
218
+ _enum(name, values, **options)
233
219
  end
234
220
 
235
221
  private
236
- def inherited(base)
237
- base.defined_enums = defined_enums.deep_dup
238
- super
239
- end
240
-
241
222
  def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
242
223
  assert_valid_enum_definition_values(values)
243
224
  assert_valid_enum_options(options)
225
+
244
226
  # statuses = { }
245
227
  enum_values = ActiveSupport::HashWithIndifferentAccess.new
246
228
  name = name.to_s
@@ -304,6 +286,11 @@ module ActiveRecord
304
286
  enum_values.freeze
305
287
  end
306
288
 
289
+ def inherited(base)
290
+ base.defined_enums = defined_enums.deep_dup
291
+ super
292
+ end
293
+
307
294
  class EnumMethods < Module # :nodoc:
308
295
  def initialize(klass)
309
296
  @klass = klass
@@ -84,6 +84,19 @@ module ActiveRecord
84
84
  class ConnectionTimeoutError < ConnectionNotEstablished
85
85
  end
86
86
 
87
+ # Raised when a database connection pool is requested but
88
+ # has not been defined.
89
+ class ConnectionNotDefined < ConnectionNotEstablished
90
+ def initialize(message = nil, connection_name: nil, role: nil, shard: nil)
91
+ super(message)
92
+ @connection_name = connection_name
93
+ @role = role
94
+ @shard = shard
95
+ end
96
+
97
+ attr_reader :connection_name, :role, :shard
98
+ end
99
+
87
100
  # Raised when connection to the database could not been established because it was not
88
101
  # able to connect to the host or when the authorization failed.
89
102
  class DatabaseConnectionError < ConnectionNotEstablished
@@ -484,11 +497,6 @@ module ActiveRecord
484
497
  # relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
485
498
  class UnmodifiableRelation < ActiveRecordError
486
499
  end
487
- deprecate_constant(
488
- :ImmutableRelation,
489
- "ActiveRecord::UnmodifiableRelation",
490
- deprecator: ActiveRecord.deprecator
491
- )
492
500
 
493
501
  # TransactionIsolationError will be raised under the following conditions:
494
502
  #
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "erb"
4
4
  require "yaml"
5
- require "zlib"
6
- require "set"
7
5
  require "active_support/dependencies"
8
6
  require "active_support/core_ext/digest/uuid"
9
7
  require "active_record/test_fixtures"
@@ -100,17 +100,21 @@ module ActiveRecord
100
100
  def execute_or_skip
101
101
  return unless pending?
102
102
 
103
- @pool.with_connection do |connection|
104
- return unless @mutex.try_lock
105
- begin
106
- if pending?
107
- @event_buffer = EventBuffer.new(self, @instrumenter)
108
- connection.with_instrumenter(@event_buffer) do
109
- execute_query(connection, async: true)
103
+ @session.synchronize do
104
+ return unless pending?
105
+
106
+ @pool.with_connection do |connection|
107
+ return unless @mutex.try_lock
108
+ begin
109
+ if pending?
110
+ @event_buffer = EventBuffer.new(self, @instrumenter)
111
+ connection.with_instrumenter(@event_buffer) do
112
+ execute_query(connection, async: true)
113
+ end
110
114
  end
115
+ ensure
116
+ @mutex.unlock
111
117
  end
112
- ensure
113
- @mutex.unlock
114
118
  end
115
119
  end
116
120
  end
@@ -163,7 +167,7 @@ module ActiveRecord
163
167
  end
164
168
 
165
169
  def exec_query(connection, *args, **kwargs)
166
- connection.internal_exec_query(*args, **kwargs)
170
+ connection.raw_exec_query(*args, **kwargs)
167
171
  end
168
172
 
169
173
  class SelectAll < FutureResult # :nodoc:
@@ -7,9 +7,9 @@ module ActiveRecord
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 7
11
- MINOR = 2
12
- TINY = 2
10
+ MAJOR = 8
11
+ MINOR = 0
12
+ TINY = 0
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -240,7 +240,7 @@ module ActiveRecord
240
240
 
241
241
  values_list = insert_all.map_key_with_value do |key, value|
242
242
  next value if Arel::Nodes::SqlLiteral === value
243
- connection.with_yaml_fallback(types[key].serialize(value))
243
+ ActiveModel::Type::SerializeCastValue.serialize(type = types[key], type.cast(value))
244
244
  end
245
245
 
246
246
  connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  # it was opened, an ActiveRecord::StaleObjectError exception is thrown if that has occurred
10
10
  # and the update is ignored.
11
11
  #
12
- # Check out +ActiveRecord::Locking::Pessimistic+ for an alternative.
12
+ # Check out ActiveRecord::Locking::Pessimistic for an alternative.
13
13
  #
14
14
  # == Usage
15
15
  #
@@ -126,18 +126,12 @@ module ActiveRecord
126
126
  end
127
127
  end
128
128
 
129
- if Thread.respond_to?(:each_caller_location)
130
- def query_source_location
131
- Thread.each_caller_location do |location|
132
- frame = backtrace_cleaner.clean_frame(location)
133
- return frame if frame
134
- end
135
- nil
136
- end
137
- else
138
- def query_source_location
139
- backtrace_cleaner.clean(caller(1).lazy).first
129
+ def query_source_location
130
+ Thread.each_caller_location do |location|
131
+ frame = backtrace_cleaner.clean_frame(location)
132
+ return frame if frame
140
133
  end
134
+ nil
141
135
  end
142
136
 
143
137
  def filter(name, value)
@@ -22,10 +22,12 @@ module ActiveRecord
22
22
  # * change_table_comment (must supply a +:from+ and +:to+ option)
23
23
  # * create_enum
24
24
  # * create_join_table
25
+ # * create_virtual_table
25
26
  # * create_table
26
27
  # * disable_extension
27
28
  # * drop_enum (must supply a list of values)
28
29
  # * drop_join_table
30
+ # * drop_virtual_table (must supply options)
29
31
  # * drop_table (must supply a block)
30
32
  # * enable_extension
31
33
  # * remove_column (must supply a type)
@@ -38,7 +40,7 @@ module ActiveRecord
38
40
  # * remove_reference
39
41
  # * remove_timestamps
40
42
  # * rename_column
41
- # * rename_enum (must supply a +:to+ option)
43
+ # * rename_enum
42
44
  # * rename_enum_value (must supply a +:from+ and +:to+ option)
43
45
  # * rename_index
44
46
  # * rename_table
@@ -55,6 +57,8 @@ module ActiveRecord
55
57
  :add_exclusion_constraint, :remove_exclusion_constraint,
56
58
  :add_unique_constraint, :remove_unique_constraint,
57
59
  :create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
60
+ :create_schema, :drop_schema,
61
+ :create_virtual_table, :drop_virtual_table
58
62
  ]
59
63
  include JoinTable
60
64
 
@@ -163,7 +167,9 @@ module ActiveRecord
163
167
  add_exclusion_constraint: :remove_exclusion_constraint,
164
168
  add_unique_constraint: :remove_unique_constraint,
165
169
  enable_extension: :disable_extension,
166
- create_enum: :drop_enum
170
+ create_enum: :drop_enum,
171
+ create_schema: :drop_schema,
172
+ create_virtual_table: :drop_virtual_table
167
173
  }.each do |cmd, inv|
168
174
  [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
169
175
  class_eval <<-EOV, __FILE__, __LINE__ + 1
@@ -196,13 +202,18 @@ module ActiveRecord
196
202
  end
197
203
 
198
204
  def invert_drop_table(args, &block)
199
- if args.last.is_a?(Hash)
200
- args.last.delete(:if_exists)
205
+ options = args.extract_options!
206
+ options.delete(:if_exists)
207
+
208
+ if args.size > 1
209
+ raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given a single table name."
201
210
  end
202
- if args.size == 1 && block == nil
211
+
212
+ if args.size == 1 && options == {} && block == nil
203
213
  raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
204
214
  end
205
- super
215
+
216
+ super(args.push(options), &block)
206
217
  end
207
218
 
208
219
  def invert_rename_table(args)
@@ -353,13 +364,13 @@ module ActiveRecord
353
364
  end
354
365
 
355
366
  def invert_rename_enum(args)
356
- name, options = args
367
+ name, new_name, = args
357
368
 
358
- unless options.is_a?(Hash) && options.has_key?(:to)
359
- raise ActiveRecord::IrreversibleMigration, "rename_enum is only reversible if given a :to option."
369
+ if new_name.is_a?(Hash) && new_name.key?(:to)
370
+ new_name = new_name[:to]
360
371
  end
361
372
 
362
- [:rename_enum, [options[:to], to: name]]
373
+ [:rename_enum, [new_name, name]]
363
374
  end
364
375
 
365
376
  def invert_rename_enum_value(args)
@@ -372,6 +383,12 @@ module ActiveRecord
372
383
  [:rename_enum_value, [type_name, from: options[:to], to: options[:from]]]
373
384
  end
374
385
 
386
+ def invert_drop_virtual_table(args)
387
+ _enum, values = args.dup.tap(&:extract_options!)
388
+ raise ActiveRecord::IrreversibleMigration, "drop_virtual_table is only reversible if given options." unless values
389
+ super
390
+ end
391
+
375
392
  def respond_to_missing?(method, _)
376
393
  super || delegate.respond_to?(method)
377
394
  end
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
22
22
  #
23
23
  # There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
24
- # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2
24
+ # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0
25
25
  #
26
26
  # If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
27
27
  # find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
@@ -29,7 +29,10 @@ module ActiveRecord
29
29
  # For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
30
30
  # class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
31
31
  # for migrations written for 5.2, but will for migrations written for 6.0.
32
- V7_2 = Current
32
+ V8_0 = Current
33
+
34
+ class V7_2 < V8_0
35
+ end
33
36
 
34
37
  class V7_1 < V7_2
35
38
  end