activerecord 7.2.2 → 8.0.0

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