activerecord 7.1.3.3 → 7.2.0.beta1

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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +507 -2128
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +1 -1
  6. data/lib/active_record/associations/alias_tracker.rb +25 -19
  7. data/lib/active_record/associations/association.rb +9 -8
  8. data/lib/active_record/associations/belongs_to_association.rb +18 -11
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  11. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +3 -4
  13. data/lib/active_record/associations/builder/has_one.rb +3 -4
  14. data/lib/active_record/associations/collection_association.rb +4 -2
  15. data/lib/active_record/associations/collection_proxy.rb +14 -1
  16. data/lib/active_record/associations/has_many_association.rb +3 -3
  17. data/lib/active_record/associations/has_one_association.rb +2 -2
  18. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  19. data/lib/active_record/associations/join_dependency.rb +5 -7
  20. data/lib/active_record/associations/nested_error.rb +47 -0
  21. data/lib/active_record/associations/preloader/association.rb +2 -1
  22. data/lib/active_record/associations/preloader/branch.rb +7 -1
  23. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  24. data/lib/active_record/associations/singular_association.rb +6 -0
  25. data/lib/active_record/associations/through_association.rb +1 -1
  26. data/lib/active_record/associations.rb +34 -11
  27. data/lib/active_record/attribute_assignment.rb +1 -11
  28. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  29. data/lib/active_record/attribute_methods/dirty.rb +1 -1
  30. data/lib/active_record/attribute_methods/primary_key.rb +23 -55
  31. data/lib/active_record/attribute_methods/read.rb +1 -13
  32. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  33. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
  34. data/lib/active_record/attribute_methods.rb +87 -58
  35. data/lib/active_record/attributes.rb +55 -42
  36. data/lib/active_record/autosave_association.rb +14 -30
  37. data/lib/active_record/base.rb +2 -3
  38. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
  39. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
  40. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +248 -58
  41. data/lib/active_record/connection_adapters/abstract/database_statements.rb +35 -18
  42. data/lib/active_record/connection_adapters/abstract/query_cache.rb +160 -75
  43. data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  45. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +22 -9
  46. data/lib/active_record/connection_adapters/abstract/transaction.rb +60 -57
  47. data/lib/active_record/connection_adapters/abstract_adapter.rb +32 -61
  48. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +69 -19
  49. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  50. data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
  51. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -0
  52. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +11 -5
  53. data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -32
  54. data/lib/active_record/connection_adapters/pool_config.rb +7 -6
  55. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
  56. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  57. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  58. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  59. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  60. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
  61. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
  62. data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
  63. data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
  64. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  65. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
  66. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
  67. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  68. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  69. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  70. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
  71. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +109 -77
  72. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +12 -6
  73. data/lib/active_record/connection_adapters/trilogy_adapter.rb +32 -65
  74. data/lib/active_record/connection_adapters.rb +121 -0
  75. data/lib/active_record/connection_handling.rb +56 -41
  76. data/lib/active_record/core.rb +59 -38
  77. data/lib/active_record/counter_cache.rb +23 -10
  78. data/lib/active_record/database_configurations/connection_url_resolver.rb +7 -2
  79. data/lib/active_record/database_configurations/database_config.rb +15 -4
  80. data/lib/active_record/database_configurations/hash_config.rb +44 -36
  81. data/lib/active_record/database_configurations/url_config.rb +20 -1
  82. data/lib/active_record/database_configurations.rb +1 -1
  83. data/lib/active_record/delegated_type.rb +30 -6
  84. data/lib/active_record/destroy_association_async_job.rb +1 -1
  85. data/lib/active_record/dynamic_matchers.rb +2 -2
  86. data/lib/active_record/encryption/encryptable_record.rb +2 -2
  87. data/lib/active_record/encryption/encrypted_attribute_type.rb +24 -4
  88. data/lib/active_record/encryption/encryptor.rb +17 -2
  89. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  90. data/lib/active_record/encryption/message_serializer.rb +4 -0
  91. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  92. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  93. data/lib/active_record/encryption/scheme.rb +8 -4
  94. data/lib/active_record/enum.rb +11 -2
  95. data/lib/active_record/errors.rb +16 -11
  96. data/lib/active_record/explain.rb +13 -24
  97. data/lib/active_record/fixtures.rb +37 -31
  98. data/lib/active_record/future_result.rb +17 -4
  99. data/lib/active_record/gem_version.rb +3 -3
  100. data/lib/active_record/inheritance.rb +4 -2
  101. data/lib/active_record/insert_all.rb +18 -15
  102. data/lib/active_record/integration.rb +4 -1
  103. data/lib/active_record/internal_metadata.rb +48 -34
  104. data/lib/active_record/locking/optimistic.rb +8 -7
  105. data/lib/active_record/log_subscriber.rb +0 -21
  106. data/lib/active_record/marshalling.rb +1 -1
  107. data/lib/active_record/message_pack.rb +2 -2
  108. data/lib/active_record/migration/command_recorder.rb +2 -3
  109. data/lib/active_record/migration/compatibility.rb +11 -3
  110. data/lib/active_record/migration/default_strategy.rb +4 -5
  111. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  112. data/lib/active_record/migration.rb +85 -76
  113. data/lib/active_record/model_schema.rb +34 -69
  114. data/lib/active_record/nested_attributes.rb +11 -3
  115. data/lib/active_record/normalization.rb +3 -7
  116. data/lib/active_record/persistence.rb +32 -354
  117. data/lib/active_record/query_cache.rb +18 -6
  118. data/lib/active_record/query_logs.rb +15 -0
  119. data/lib/active_record/query_logs_formatter.rb +1 -1
  120. data/lib/active_record/querying.rb +21 -9
  121. data/lib/active_record/railtie.rb +52 -64
  122. data/lib/active_record/railties/controller_runtime.rb +13 -4
  123. data/lib/active_record/railties/databases.rake +41 -44
  124. data/lib/active_record/reflection.rb +98 -37
  125. data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
  126. data/lib/active_record/relation/batches.rb +3 -3
  127. data/lib/active_record/relation/calculations.rb +94 -61
  128. data/lib/active_record/relation/delegation.rb +8 -11
  129. data/lib/active_record/relation/finder_methods.rb +16 -2
  130. data/lib/active_record/relation/merger.rb +4 -6
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  132. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
  133. data/lib/active_record/relation/predicate_builder.rb +3 -3
  134. data/lib/active_record/relation/query_methods.rb +196 -43
  135. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  136. data/lib/active_record/relation/spawn_methods.rb +2 -18
  137. data/lib/active_record/relation/where_clause.rb +7 -19
  138. data/lib/active_record/relation.rb +500 -66
  139. data/lib/active_record/result.rb +32 -45
  140. data/lib/active_record/runtime_registry.rb +39 -0
  141. data/lib/active_record/sanitization.rb +24 -19
  142. data/lib/active_record/schema.rb +8 -6
  143. data/lib/active_record/schema_dumper.rb +19 -9
  144. data/lib/active_record/schema_migration.rb +30 -14
  145. data/lib/active_record/signed_id.rb +11 -1
  146. data/lib/active_record/statement_cache.rb +7 -7
  147. data/lib/active_record/table_metadata.rb +1 -10
  148. data/lib/active_record/tasks/database_tasks.rb +70 -42
  149. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  150. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  151. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
  152. data/lib/active_record/test_fixtures.rb +82 -91
  153. data/lib/active_record/testing/query_assertions.rb +121 -0
  154. data/lib/active_record/timestamp.rb +4 -2
  155. data/lib/active_record/token_for.rb +22 -12
  156. data/lib/active_record/touch_later.rb +1 -1
  157. data/lib/active_record/transaction.rb +68 -0
  158. data/lib/active_record/transactions.rb +43 -14
  159. data/lib/active_record/translation.rb +0 -2
  160. data/lib/active_record/type/serialized.rb +1 -3
  161. data/lib/active_record/type_caster/connection.rb +4 -4
  162. data/lib/active_record/validations/associated.rb +9 -3
  163. data/lib/active_record/validations/uniqueness.rb +14 -10
  164. data/lib/active_record/validations.rb +4 -1
  165. data/lib/active_record.rb +149 -40
  166. data/lib/arel/alias_predication.rb +1 -1
  167. data/lib/arel/collectors/bind.rb +2 -0
  168. data/lib/arel/collectors/composite.rb +7 -0
  169. data/lib/arel/collectors/sql_string.rb +1 -1
  170. data/lib/arel/collectors/substitute_binds.rb +1 -1
  171. data/lib/arel/nodes/binary.rb +0 -6
  172. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  173. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  174. data/lib/arel/nodes/node.rb +4 -3
  175. data/lib/arel/nodes/sql_literal.rb +7 -0
  176. data/lib/arel/nodes.rb +2 -2
  177. data/lib/arel/predications.rb +1 -1
  178. data/lib/arel/select_manager.rb +1 -1
  179. data/lib/arel/tree_manager.rb +8 -3
  180. data/lib/arel/update_manager.rb +2 -1
  181. data/lib/arel/visitors/dot.rb +1 -0
  182. data/lib/arel/visitors/mysql.rb +9 -4
  183. data/lib/arel/visitors/postgresql.rb +1 -12
  184. data/lib/arel/visitors/to_sql.rb +31 -17
  185. data/lib/arel.rb +7 -3
  186. metadata +16 -11
@@ -55,9 +55,6 @@ module ActiveRecord
55
55
  # about the model. The model needs to pass a connection specification name to the handler,
56
56
  # in order to look up the correct connection pool.
57
57
  class ConnectionHandler
58
- FINALIZER = lambda { |_| ActiveSupport::ForkTracker.check! }
59
- private_constant :FINALIZER
60
-
61
58
  class StringConnectionName # :nodoc:
62
59
  attr_reader :name
63
60
 
@@ -77,9 +74,6 @@ module ActiveRecord
77
74
  def initialize
78
75
  # These caches are keyed by pool_config.connection_name (PoolConfig#connection_name).
79
76
  @connection_name_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)
80
-
81
- # Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
82
- ObjectSpace.define_finalizer self, FINALIZER
83
77
  end
84
78
 
85
79
  def prevent_writes # :nodoc:
@@ -94,22 +88,10 @@ module ActiveRecord
94
88
  connection_name_to_pool_manager.keys
95
89
  end
96
90
 
97
- def all_connection_pools
98
- ActiveRecord.deprecator.warn(<<-MSG.squish)
99
- The `all_connection_pools` method is deprecated in favor of `connection_pool_list`.
100
- Call `connection_pool_list(:all)` to get the same behavior as `all_connection_pools`.
101
- MSG
102
- connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
103
- end
104
-
105
- # Returns the pools for a connection handler and given role. If +:all+ is passed,
91
+ # Returns the pools for a connection handler and given role. If +:all+ is passed,
106
92
  # all pools belonging to the connection handler will be returned.
107
93
  def connection_pool_list(role = nil)
108
- if role.nil?
109
- deprecation_for_pool_handling(__method__)
110
- role = ActiveRecord::Base.current_role
111
- connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
112
- elsif role == :all
94
+ if role.nil? || role == :all
113
95
  connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
114
96
  else
115
97
  connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
@@ -171,11 +153,6 @@ module ActiveRecord
171
153
  # Returns true if there are any active connections among the connection
172
154
  # pools that the ConnectionHandler is managing.
173
155
  def active_connections?(role = nil)
174
- if role.nil?
175
- deprecation_for_pool_handling(__method__)
176
- role = ActiveRecord::Base.current_role
177
- end
178
-
179
156
  each_connection_pool(role).any?(&:active_connection?)
180
157
  end
181
158
 
@@ -183,32 +160,20 @@ module ActiveRecord
183
160
  # and also returns connections to the pool cached by threads that are no
184
161
  # longer alive.
185
162
  def clear_active_connections!(role = nil)
186
- if role.nil?
187
- deprecation_for_pool_handling(__method__)
188
- role = ActiveRecord::Base.current_role
163
+ each_connection_pool(role).each do |pool|
164
+ pool.release_connection
165
+ pool.disable_query_cache!
189
166
  end
190
-
191
- each_connection_pool(role).each(&:release_connection)
192
167
  end
193
168
 
194
169
  # Clears the cache which maps classes.
195
170
  #
196
171
  # See ConnectionPool#clear_reloadable_connections! for details.
197
172
  def clear_reloadable_connections!(role = nil)
198
- if role.nil?
199
- deprecation_for_pool_handling(__method__)
200
- role = ActiveRecord::Base.current_role
201
- end
202
-
203
173
  each_connection_pool(role).each(&:clear_reloadable_connections!)
204
174
  end
205
175
 
206
176
  def clear_all_connections!(role = nil)
207
- if role.nil?
208
- deprecation_for_pool_handling(__method__)
209
- role = ActiveRecord::Base.current_role
210
- end
211
-
212
177
  each_connection_pool(role).each(&:disconnect!)
213
178
  end
214
179
 
@@ -216,11 +181,6 @@ module ActiveRecord
216
181
  #
217
182
  # See ConnectionPool#flush! for details.
218
183
  def flush_idle_connections!(role = nil)
219
- if role.nil?
220
- deprecation_for_pool_handling(__method__)
221
- role = ActiveRecord::Base.current_role
222
- end
223
-
224
184
  each_connection_pool(role).each(&:flush!)
225
185
  end
226
186
 
@@ -229,21 +189,8 @@ module ActiveRecord
229
189
  # opened and set as the active connection for the class it was defined
230
190
  # for (not necessarily the current class).
231
191
  def retrieve_connection(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) # :nodoc:
232
- pool = retrieve_connection_pool(connection_name, role: role, shard: shard)
233
-
234
- unless pool
235
- if shard != ActiveRecord::Base.default_shard
236
- message = "No connection pool for '#{connection_name}' found for the '#{shard}' shard."
237
- elsif role != ActiveRecord::Base.default_role
238
- message = "No connection pool for '#{connection_name}' found for the '#{role}' role."
239
- else
240
- message = "No connection pool for '#{connection_name}' found."
241
- end
242
-
243
- raise ConnectionNotEstablished, message
244
- end
245
-
246
- pool.connection
192
+ pool = retrieve_connection_pool(connection_name, role: role, shard: shard, strict: true)
193
+ pool.lease_connection
247
194
  end
248
195
 
249
196
  # Returns true if a connection that's accessible to this class has
@@ -262,9 +209,22 @@ module ActiveRecord
262
209
  # Retrieving the connection pool happens a lot, so we cache it in @connection_name_to_pool_manager.
263
210
  # This makes retrieving the connection pool O(1) once the process is warm.
264
211
  # When a connection is established or removed, we invalidate the cache.
265
- def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
266
- pool_config = get_pool_manager(connection_name)&.get_pool_config(role, shard)
267
- pool_config&.pool
212
+ def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false)
213
+ pool = get_pool_manager(connection_name)&.get_pool_config(role, shard)&.pool
214
+
215
+ if strict && !pool
216
+ if shard != ActiveRecord::Base.default_shard
217
+ message = "No connection pool for '#{connection_name}' found for the '#{shard}' shard."
218
+ elsif role != ActiveRecord::Base.default_role
219
+ message = "No connection pool for '#{connection_name}' found for the '#{role}' role."
220
+ else
221
+ message = "No connection pool for '#{connection_name}' found."
222
+ end
223
+
224
+ raise ConnectionNotEstablished, message
225
+ end
226
+
227
+ pool
268
228
  end
269
229
 
270
230
  private
@@ -284,23 +244,6 @@ module ActiveRecord
284
244
  connection_name_to_pool_manager.values
285
245
  end
286
246
 
287
- def deprecation_for_pool_handling(method)
288
- roles = []
289
- pool_managers.each do |pool_manager|
290
- roles << pool_manager.role_names
291
- end
292
-
293
- if roles.flatten.uniq.count > 1
294
- ActiveRecord.deprecator.warn(<<-MSG.squish)
295
- `#{method}` currently only applies to connection pools in the current
296
- role (`#{ActiveRecord::Base.current_role}`). In Rails 7.2, this method
297
- will apply to all known pools, regardless of role. To affect only those
298
- connections belonging to a specific role, pass the role name as an
299
- argument. To switch to the new behavior, pass `:all` as the role name.
300
- MSG
301
- end
302
- end
303
-
304
247
  def disconnect_pool_from_pool_manager(pool_manager, role, shard)
305
248
  pool_config = pool_manager.remove_pool_config(role, shard)
306
249
 
@@ -322,34 +265,8 @@ module ActiveRecord
322
265
  #
323
266
  def resolve_pool_config(config, connection_name, role, shard)
324
267
  db_config = Base.configurations.resolve(config)
325
-
268
+ db_config.validate!
326
269
  raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db_config.adapter
327
-
328
- # Require the adapter itself and give useful feedback about
329
- # 1. Missing adapter gems and
330
- # 2. Adapter gems' missing dependencies.
331
- path_to_adapter = "active_record/connection_adapters/#{db_config.adapter}_adapter"
332
- begin
333
- require path_to_adapter
334
- rescue LoadError => e
335
- # We couldn't require the adapter itself. Raise an exception that
336
- # points out config typos and missing gems.
337
- if e.path == path_to_adapter
338
- # We can assume that a non-builtin adapter was specified, so it's
339
- # either misspelled or missing from Gemfile.
340
- raise LoadError, "Could not load the '#{db_config.adapter}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
341
-
342
- # Bubbled up from the adapter require. Prefix the exception message
343
- # with some guidance about how to address it and reraise.
344
- else
345
- raise LoadError, "Error loading the '#{db_config.adapter}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
346
- end
347
- end
348
-
349
- unless ActiveRecord::Base.respond_to?(db_config.adapter_method)
350
- raise AdapterNotFound, "database configuration specifies nonexistent #{db_config.adapter} adapter"
351
- end
352
-
353
270
  ConnectionAdapters::PoolConfig.new(connection_name, db_config, role, shard)
354
271
  end
355
272
 
@@ -43,6 +43,7 @@ module ActiveRecord
43
43
  # Advise multi-threaded app servers to ignore this thread for
44
44
  # the purposes of fork safety warnings
45
45
  Thread.current.thread_variable_set(:fork_safe, true)
46
+ Thread.current.name = "AR Pool Reaper"
46
47
  running = true
47
48
  while running
48
49
  sleep t