activerecord 7.1.6 → 7.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +839 -2248
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +16 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +59 -292
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +5 -25
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods.rb +51 -60
- data/lib/active_record/attributes.rb +93 -68
- data/lib/active_record/autosave_association.rb +25 -32
- data/lib/active_record/base.rb +4 -5
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +294 -72
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -75
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +46 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +6 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +19 -18
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +30 -8
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +36 -26
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +133 -78
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +68 -49
- data/lib/active_record/core.rb +112 -44
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +42 -18
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +25 -5
- data/lib/active_record/encryption/encryptor.rb +35 -19
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/enum.rb +31 -13
- data/lib/active_record/errors.rb +49 -23
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +87 -77
- data/lib/active_record/model_schema.rb +31 -68
- data/lib/active_record/nested_attributes.rb +11 -3
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +19 -0
- data/lib/active_record/querying.rb +25 -13
- data/lib/active_record/railtie.rb +39 -57
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +42 -44
- data/lib/active_record/reflection.rb +98 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +127 -89
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +26 -12
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +238 -65
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +15 -21
- data/lib/active_record/relation.rb +508 -74
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +48 -20
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +27 -7
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +69 -41
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +8 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +86 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +73 -15
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +15 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +148 -39
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +3 -1
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +31 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +16 -10
|
@@ -4,14 +4,14 @@ module ActiveRecord
|
|
|
4
4
|
# Statement cache is used to cache a single statement in order to avoid creating the AST again.
|
|
5
5
|
# Initializing the cache is done by passing the statement in the create block:
|
|
6
6
|
#
|
|
7
|
-
# cache = StatementCache.create(
|
|
7
|
+
# cache = StatementCache.create(ClothingItem.lease_connection) do |params|
|
|
8
8
|
# Book.where(name: "my book").where("author_id > 3")
|
|
9
9
|
# end
|
|
10
10
|
#
|
|
11
11
|
# The cached statement is executed by using the
|
|
12
12
|
# {connection.execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute] method:
|
|
13
13
|
#
|
|
14
|
-
# cache.execute([],
|
|
14
|
+
# cache.execute([], ClothingItem.lease_connection)
|
|
15
15
|
#
|
|
16
16
|
# The relation returned by the block is cached, and for each
|
|
17
17
|
# {execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute]
|
|
@@ -20,13 +20,13 @@ module ActiveRecord
|
|
|
20
20
|
# If you want to cache the statement without the values you can use the +bind+ method of the
|
|
21
21
|
# block parameter.
|
|
22
22
|
#
|
|
23
|
-
# cache = StatementCache.create(
|
|
23
|
+
# cache = StatementCache.create(ClothingItem.lease_connection) do |params|
|
|
24
24
|
# Book.where(name: params.bind)
|
|
25
25
|
# end
|
|
26
26
|
#
|
|
27
27
|
# And pass the bind values as the first argument of +execute+ call.
|
|
28
28
|
#
|
|
29
|
-
# cache.execute(["my book"],
|
|
29
|
+
# cache.execute(["my book"], ClothingItem.lease_connection)
|
|
30
30
|
class StatementCache # :nodoc:
|
|
31
31
|
class Substitute; end # :nodoc:
|
|
32
32
|
|
|
@@ -62,7 +62,7 @@ module ActiveRecord
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
class PartialQueryCollector
|
|
65
|
-
attr_accessor :preparable
|
|
65
|
+
attr_accessor :preparable, :retryable
|
|
66
66
|
|
|
67
67
|
def initialize
|
|
68
68
|
@parts = []
|
|
@@ -142,12 +142,12 @@ module ActiveRecord
|
|
|
142
142
|
@klass = klass
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
-
def execute(params, connection, &block)
|
|
145
|
+
def execute(params, connection, allow_retry: false, &block)
|
|
146
146
|
bind_values = bind_map.bind params
|
|
147
147
|
|
|
148
148
|
sql = query_builder.sql_for bind_values, connection
|
|
149
149
|
|
|
150
|
-
klass.find_by_sql(sql, bind_values, preparable: true, &block)
|
|
150
|
+
klass.find_by_sql(sql, bind_values, preparable: true, allow_retry: allow_retry, &block)
|
|
151
151
|
rescue ::RangeError
|
|
152
152
|
[]
|
|
153
153
|
end
|
|
@@ -23,16 +23,7 @@ module ActiveRecord
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def associated_with?(table_name)
|
|
26
|
-
|
|
27
|
-
reflection
|
|
28
|
-
elsif ActiveRecord.allow_deprecated_singular_associations_name && reflection = klass&._reflect_on_association(table_name.singularize)
|
|
29
|
-
ActiveRecord.deprecator.warn(<<~MSG)
|
|
30
|
-
Referring to a singular association (e.g. `#{reflection.name}`) by its plural name (e.g. `#{reflection.plural_name}`) is deprecated.
|
|
31
|
-
|
|
32
|
-
To convert this deprecation warning to an error and enable more performant behavior, set config.active_record.allow_deprecated_singular_associations_name = false.
|
|
33
|
-
MSG
|
|
34
|
-
reflection
|
|
35
|
-
end
|
|
26
|
+
klass&._reflect_on_association(table_name)
|
|
36
27
|
end
|
|
37
28
|
|
|
38
29
|
def associated_table(table_name)
|
|
@@ -125,11 +125,11 @@ module ActiveRecord
|
|
|
125
125
|
end
|
|
126
126
|
|
|
127
127
|
def create_all
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
db_config = migration_connection.pool.db_config
|
|
129
|
+
|
|
130
|
+
each_local_configuration { |db_config| create(db_config) }
|
|
131
|
+
|
|
132
|
+
migration_class.establish_connection(db_config)
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
def setup_initial_database_yaml # :nodoc:
|
|
@@ -180,7 +180,7 @@ module ActiveRecord
|
|
|
180
180
|
each_current_configuration(env) do |db_config|
|
|
181
181
|
with_temporary_pool(db_config) do
|
|
182
182
|
begin
|
|
183
|
-
database_initialized =
|
|
183
|
+
database_initialized = migration_connection_pool.schema_migration.table_exists?
|
|
184
184
|
rescue ActiveRecord::NoDatabaseError
|
|
185
185
|
create(db_config)
|
|
186
186
|
retry
|
|
@@ -259,7 +259,7 @@ module ActiveRecord
|
|
|
259
259
|
|
|
260
260
|
check_target_version
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
migration_connection_pool.migration_context.migrate(target_version) do |migration|
|
|
263
263
|
if version.blank?
|
|
264
264
|
scope.blank? || scope == migration.scope
|
|
265
265
|
else
|
|
@@ -269,7 +269,7 @@ module ActiveRecord
|
|
|
269
269
|
Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
|
|
270
270
|
end
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
migration_connection_pool.schema_cache.clear!
|
|
273
273
|
ensure
|
|
274
274
|
Migration.verbose = verbose_was
|
|
275
275
|
end
|
|
@@ -277,9 +277,9 @@ module ActiveRecord
|
|
|
277
277
|
def db_configs_with_versions(environment = env) # :nodoc:
|
|
278
278
|
db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
|
|
279
279
|
|
|
280
|
-
|
|
281
|
-
db_config =
|
|
282
|
-
versions_to_run =
|
|
280
|
+
with_temporary_pool_for_each(env: environment) do |pool|
|
|
281
|
+
db_config = pool.db_config
|
|
282
|
+
versions_to_run = pool.migration_context.pending_migration_versions
|
|
283
283
|
target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
|
|
284
284
|
|
|
285
285
|
versions_to_run.each do |version|
|
|
@@ -292,15 +292,15 @@ module ActiveRecord
|
|
|
292
292
|
end
|
|
293
293
|
|
|
294
294
|
def migrate_status
|
|
295
|
-
unless
|
|
295
|
+
unless migration_connection_pool.schema_migration.table_exists?
|
|
296
296
|
Kernel.abort "Schema migrations table does not exist yet."
|
|
297
297
|
end
|
|
298
298
|
|
|
299
299
|
# output
|
|
300
|
-
puts "\ndatabase: #{
|
|
300
|
+
puts "\ndatabase: #{migration_connection_pool.db_config.database}\n\n"
|
|
301
301
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
|
302
302
|
puts "-" * 50
|
|
303
|
-
|
|
303
|
+
migration_connection_pool.migration_context.migrations_status.each do |status, version, name|
|
|
304
304
|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
|
305
305
|
end
|
|
306
306
|
puts
|
|
@@ -381,7 +381,7 @@ module ActiveRecord
|
|
|
381
381
|
raise ArgumentError, "unknown format #{format.inspect}"
|
|
382
382
|
end
|
|
383
383
|
|
|
384
|
-
|
|
384
|
+
migration_connection_pool.internal_metadata.create_table_and_set_flags(db_config.env_name, schema_sha1(file))
|
|
385
385
|
ensure
|
|
386
386
|
Migration.verbose = verbose_was
|
|
387
387
|
end
|
|
@@ -393,11 +393,12 @@ module ActiveRecord
|
|
|
393
393
|
|
|
394
394
|
return true unless file && File.exist?(file)
|
|
395
395
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
return false unless
|
|
396
|
+
with_temporary_pool(db_config) do |pool|
|
|
397
|
+
internal_metadata = pool.internal_metadata
|
|
398
|
+
return false unless internal_metadata.enabled?
|
|
399
|
+
return false unless internal_metadata.table_exists?
|
|
399
400
|
|
|
400
|
-
|
|
401
|
+
internal_metadata[:schema_sha1] == schema_sha1(file)
|
|
401
402
|
end
|
|
402
403
|
end
|
|
403
404
|
|
|
@@ -408,7 +409,7 @@ module ActiveRecord
|
|
|
408
409
|
|
|
409
410
|
with_temporary_pool(db_config, clobber: true) do
|
|
410
411
|
if schema_up_to_date?(db_config, format, file)
|
|
411
|
-
truncate_tables(db_config)
|
|
412
|
+
truncate_tables(db_config) unless ENV["SKIP_TEST_DATABASE_TRUNCATE"]
|
|
412
413
|
else
|
|
413
414
|
purge(db_config)
|
|
414
415
|
load_schema(db_config, format, file)
|
|
@@ -430,11 +431,11 @@ module ActiveRecord
|
|
|
430
431
|
case format
|
|
431
432
|
when :ruby
|
|
432
433
|
File.open(filename, "w:utf-8") do |file|
|
|
433
|
-
ActiveRecord::SchemaDumper.dump(
|
|
434
|
+
ActiveRecord::SchemaDumper.dump(migration_connection_pool, file)
|
|
434
435
|
end
|
|
435
436
|
when :sql
|
|
436
437
|
structure_dump(db_config, filename)
|
|
437
|
-
if
|
|
438
|
+
if migration_connection_pool.schema_migration.table_exists?
|
|
438
439
|
File.open(filename, "a") do |f|
|
|
439
440
|
f.puts migration_connection.dump_schema_information
|
|
440
441
|
f.print "\n"
|
|
@@ -456,14 +457,26 @@ module ActiveRecord
|
|
|
456
457
|
end
|
|
457
458
|
end
|
|
458
459
|
|
|
459
|
-
def cache_dump_filename(
|
|
460
|
-
|
|
461
|
-
|
|
460
|
+
def cache_dump_filename(db_config_or_name, schema_cache_path: nil)
|
|
461
|
+
if db_config_or_name.is_a?(DatabaseConfigurations::DatabaseConfig)
|
|
462
|
+
schema_cache_path ||
|
|
463
|
+
db_config_or_name.schema_cache_path ||
|
|
464
|
+
schema_cache_env ||
|
|
465
|
+
db_config_or_name.default_schema_cache_path(ActiveRecord::Tasks::DatabaseTasks.db_dir)
|
|
462
466
|
else
|
|
463
|
-
|
|
464
|
-
|
|
467
|
+
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
|
468
|
+
Passing a database name to `cache_dump_filename` is deprecated and will be removed in Rails 8.0. Pass a
|
|
469
|
+
`ActiveRecord::DatabaseConfigurations::DatabaseConfig` object instead.
|
|
470
|
+
MSG
|
|
465
471
|
|
|
466
|
-
|
|
472
|
+
filename = if ActiveRecord::Base.configurations.primary?(db_config_or_name)
|
|
473
|
+
"schema_cache.yml"
|
|
474
|
+
else
|
|
475
|
+
"#{db_config_or_name}_schema_cache.yml"
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
schema_cache_path || schema_cache_env || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
|
|
479
|
+
end
|
|
467
480
|
end
|
|
468
481
|
|
|
469
482
|
def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
|
|
@@ -495,29 +508,29 @@ module ActiveRecord
|
|
|
495
508
|
# Dumps the schema cache in YAML format for the connection into the file
|
|
496
509
|
#
|
|
497
510
|
# ==== Examples
|
|
498
|
-
# ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.
|
|
499
|
-
def dump_schema_cache(
|
|
500
|
-
|
|
511
|
+
# ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.lease_connection, "tmp/schema_dump.yaml")
|
|
512
|
+
def dump_schema_cache(conn_or_pool, filename)
|
|
513
|
+
conn_or_pool.schema_cache.dump_to(filename)
|
|
501
514
|
end
|
|
502
515
|
|
|
503
516
|
def clear_schema_cache(filename)
|
|
504
517
|
FileUtils.rm_f filename, verbose: false
|
|
505
518
|
end
|
|
506
519
|
|
|
507
|
-
def
|
|
520
|
+
def with_temporary_pool_for_each(env: ActiveRecord::Tasks::DatabaseTasks.env, name: nil, clobber: false, &block) # :nodoc:
|
|
508
521
|
if name
|
|
509
522
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: env, name: name)
|
|
510
|
-
|
|
523
|
+
with_temporary_pool(db_config, clobber: clobber, &block)
|
|
511
524
|
else
|
|
512
525
|
ActiveRecord::Base.configurations.configs_for(env_name: env, name: name).each do |db_config|
|
|
513
|
-
|
|
526
|
+
with_temporary_pool(db_config, clobber: clobber, &block)
|
|
514
527
|
end
|
|
515
528
|
end
|
|
516
529
|
end
|
|
517
530
|
|
|
518
|
-
def with_temporary_connection(db_config, clobber: false) # :nodoc:
|
|
531
|
+
def with_temporary_connection(db_config, clobber: false, &block) # :nodoc:
|
|
519
532
|
with_temporary_pool(db_config, clobber: clobber) do |pool|
|
|
520
|
-
|
|
533
|
+
pool.with_connection(&block)
|
|
521
534
|
end
|
|
522
535
|
end
|
|
523
536
|
|
|
@@ -526,10 +539,25 @@ module ActiveRecord
|
|
|
526
539
|
end
|
|
527
540
|
|
|
528
541
|
def migration_connection # :nodoc:
|
|
529
|
-
migration_class.
|
|
542
|
+
migration_class.lease_connection
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
def migration_connection_pool # :nodoc:
|
|
546
|
+
migration_class.connection_pool
|
|
530
547
|
end
|
|
531
548
|
|
|
532
549
|
private
|
|
550
|
+
def schema_cache_env
|
|
551
|
+
if ENV["SCHEMA_CACHE"]
|
|
552
|
+
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
|
553
|
+
Setting `ENV["SCHEMA_CACHE"]` is deprecated and will be removed in Rails 8.0.
|
|
554
|
+
Configure the `:schema_cache_path` in the database configuration instead.
|
|
555
|
+
MSG
|
|
556
|
+
|
|
557
|
+
nil
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
|
|
533
561
|
def with_temporary_pool(db_config, clobber: false)
|
|
534
562
|
original_db_config = migration_class.connection_db_config
|
|
535
563
|
pool = migration_class.connection_handler.establish_connection(db_config, clobber: clobber)
|
|
@@ -625,11 +653,11 @@ module ActiveRecord
|
|
|
625
653
|
|
|
626
654
|
def check_current_protected_environment!(db_config)
|
|
627
655
|
with_temporary_pool(db_config) do |pool|
|
|
628
|
-
|
|
629
|
-
current =
|
|
630
|
-
stored =
|
|
656
|
+
migration_context = pool.migration_context
|
|
657
|
+
current = migration_context.current_environment
|
|
658
|
+
stored = migration_context.last_stored_environment
|
|
631
659
|
|
|
632
|
-
if
|
|
660
|
+
if migration_context.protected_environment?
|
|
633
661
|
raise ActiveRecord::ProtectedEnvironmentError.new(stored)
|
|
634
662
|
end
|
|
635
663
|
|
|
@@ -88,7 +88,7 @@ module ActiveRecord
|
|
|
88
88
|
attr_reader :db_config, :configuration_hash
|
|
89
89
|
|
|
90
90
|
def connection
|
|
91
|
-
ActiveRecord::Base.
|
|
91
|
+
ActiveRecord::Base.lease_connection
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
def establish_connection(config = db_config)
|
|
@@ -132,6 +132,13 @@ module ActiveRecord
|
|
|
132
132
|
tempfile = Tempfile.open("uncommented_structure.sql")
|
|
133
133
|
begin
|
|
134
134
|
File.foreach(filename) do |line|
|
|
135
|
+
next if line.start_with?("\\restrict ")
|
|
136
|
+
|
|
137
|
+
if line.start_with?("\\unrestrict ")
|
|
138
|
+
removing_comments = true
|
|
139
|
+
next
|
|
140
|
+
end
|
|
141
|
+
|
|
135
142
|
unless removing_comments && (line.start_with?(SQL_COMMENT_BEGIN) || line.blank?)
|
|
136
143
|
tempfile << line
|
|
137
144
|
removing_comments = false
|
|
@@ -66,11 +66,12 @@ module ActiveRecord
|
|
|
66
66
|
attr_reader :db_config, :root
|
|
67
67
|
|
|
68
68
|
def connection
|
|
69
|
-
ActiveRecord::Base.
|
|
69
|
+
ActiveRecord::Base.lease_connection
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def establish_connection(config = db_config)
|
|
73
73
|
ActiveRecord::Base.establish_connection(config)
|
|
74
|
+
connection.connect!
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
def run_cmd(cmd, args, out)
|
|
@@ -53,20 +53,6 @@ module ActiveRecord
|
|
|
53
53
|
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
def fixture_path # :nodoc:
|
|
57
|
-
ActiveRecord.deprecator.warn(<<~WARNING)
|
|
58
|
-
TestFixtures.fixture_path is deprecated and will be removed in Rails 7.2. Use .fixture_paths instead.
|
|
59
|
-
If multiple fixture paths have been configured with .fixture_paths, then .fixture_path will just return
|
|
60
|
-
the first path.
|
|
61
|
-
WARNING
|
|
62
|
-
fixture_paths.first
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def fixture_path=(path) # :nodoc:
|
|
66
|
-
ActiveRecord.deprecator.warn("TestFixtures.fixture_path= is deprecated and will be removed in Rails 7.2. Use .fixture_paths= instead.")
|
|
67
|
-
self.fixture_paths = Array(path)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
56
|
def fixtures(*fixture_set_names)
|
|
71
57
|
if fixture_set_names.first == :all
|
|
72
58
|
raise StandardError, "No fixture path found. Please set `#{self}.fixture_paths`." if fixture_paths.blank?
|
|
@@ -79,7 +65,7 @@ module ActiveRecord
|
|
|
79
65
|
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
|
80
66
|
end
|
|
81
67
|
|
|
82
|
-
self.fixture_table_names
|
|
68
|
+
self.fixture_table_names = (fixture_table_names | fixture_set_names).sort
|
|
83
69
|
setup_fixture_accessors(fixture_set_names)
|
|
84
70
|
end
|
|
85
71
|
|
|
@@ -110,45 +96,76 @@ module ActiveRecord
|
|
|
110
96
|
end
|
|
111
97
|
end
|
|
112
98
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
fixture_paths.first
|
|
99
|
+
# Generic fixture accessor for fixture names that may conflict with other methods.
|
|
100
|
+
#
|
|
101
|
+
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
|
|
102
|
+
# assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
|
|
103
|
+
def fixture(fixture_set_name, *fixture_names)
|
|
104
|
+
active_record_fixture(fixture_set_name, *fixture_names)
|
|
120
105
|
end
|
|
121
106
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def setup_fixtures(config = ActiveRecord::Base)
|
|
128
|
-
if pre_loaded_fixtures && !use_transactional_tests
|
|
129
|
-
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
|
107
|
+
private
|
|
108
|
+
def run_in_transaction?
|
|
109
|
+
use_transactional_tests &&
|
|
110
|
+
!self.class.uses_transaction?(name)
|
|
130
111
|
end
|
|
131
112
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
113
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
|
114
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
|
115
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
@fixture_cache = {}
|
|
119
|
+
@fixture_cache_key = [self.class.fixture_table_names.dup, self.class.fixture_paths.dup, self.class.fixture_class_names.dup]
|
|
120
|
+
@fixture_connection_pools = []
|
|
121
|
+
@@already_loaded_fixtures ||= {}
|
|
122
|
+
@connection_subscriber = nil
|
|
123
|
+
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
|
124
|
+
|
|
125
|
+
if run_in_transaction?
|
|
126
|
+
# Load fixtures once and begin transaction.
|
|
127
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key]
|
|
128
|
+
unless @loaded_fixtures
|
|
129
|
+
@@already_loaded_fixtures.clear
|
|
130
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key] = load_fixtures(config)
|
|
131
|
+
end
|
|
137
132
|
|
|
138
|
-
|
|
139
|
-
if run_in_transaction?
|
|
140
|
-
if @@already_loaded_fixtures[self.class]
|
|
141
|
-
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
|
133
|
+
setup_transactional_fixtures
|
|
142
134
|
else
|
|
135
|
+
# Load fixtures for every test.
|
|
136
|
+
ActiveRecord::FixtureSet.reset_cache
|
|
137
|
+
invalidate_already_loaded_fixtures
|
|
143
138
|
@loaded_fixtures = load_fixtures(config)
|
|
144
|
-
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
|
145
139
|
end
|
|
146
140
|
|
|
141
|
+
# Instantiate fixtures for every test if requested.
|
|
142
|
+
instantiate_fixtures if use_instantiated_fixtures
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def teardown_fixtures
|
|
146
|
+
# Rollback changes if a transaction is active.
|
|
147
|
+
if run_in_transaction?
|
|
148
|
+
teardown_transactional_fixtures
|
|
149
|
+
else
|
|
150
|
+
ActiveRecord::FixtureSet.reset_cache
|
|
151
|
+
invalidate_already_loaded_fixtures
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def invalidate_already_loaded_fixtures
|
|
158
|
+
@@already_loaded_fixtures.clear
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def setup_transactional_fixtures
|
|
162
|
+
setup_shared_connection_pool
|
|
163
|
+
|
|
147
164
|
# Begin transactions for connections already established
|
|
148
|
-
@
|
|
149
|
-
@
|
|
150
|
-
|
|
151
|
-
|
|
165
|
+
@fixture_connection_pools = ActiveRecord::Base.connection_handler.connection_pool_list(:writing)
|
|
166
|
+
@fixture_connection_pools.each do |pool|
|
|
167
|
+
pool.pin_connection!(lock_threads)
|
|
168
|
+
pool.lease_connection
|
|
152
169
|
end
|
|
153
170
|
|
|
154
171
|
# When connections are established in the future, begin a transaction too
|
|
@@ -157,59 +174,31 @@ module ActiveRecord
|
|
|
157
174
|
shard = payload[:shard] if payload.key?(:shard)
|
|
158
175
|
|
|
159
176
|
if connection_name
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
rescue ConnectionNotEstablished
|
|
163
|
-
connection = nil
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
if connection
|
|
177
|
+
pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(connection_name, shard: shard)
|
|
178
|
+
if pool
|
|
167
179
|
setup_shared_connection_pool
|
|
168
180
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
@
|
|
181
|
+
unless @fixture_connection_pools.include?(pool)
|
|
182
|
+
pool.pin_connection!(lock_threads)
|
|
183
|
+
pool.lease_connection
|
|
184
|
+
@fixture_connection_pools << pool
|
|
173
185
|
end
|
|
174
186
|
end
|
|
175
187
|
end
|
|
176
188
|
end
|
|
177
|
-
|
|
178
|
-
# Load fixtures for every test.
|
|
179
|
-
else
|
|
180
|
-
ActiveRecord::FixtureSet.reset_cache
|
|
181
|
-
@@already_loaded_fixtures[self.class] = nil
|
|
182
|
-
@loaded_fixtures = load_fixtures(config)
|
|
183
189
|
end
|
|
184
190
|
|
|
185
|
-
|
|
186
|
-
instantiate_fixtures if use_instantiated_fixtures
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def teardown_fixtures
|
|
190
|
-
# Rollback changes if a transaction is active.
|
|
191
|
-
if run_in_transaction?
|
|
191
|
+
def teardown_transactional_fixtures
|
|
192
192
|
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
|
193
|
-
@
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
unless @fixture_connection_pools.map(&:unpin_connection!).all?
|
|
194
|
+
# Something caused the transaction to be committed or rolled back
|
|
195
|
+
# We can no longer trust the database is in a clean state.
|
|
196
|
+
@@already_loaded_fixtures.clear
|
|
196
197
|
end
|
|
197
|
-
@
|
|
198
|
+
@fixture_connection_pools.clear
|
|
198
199
|
teardown_shared_connection_pool
|
|
199
|
-
else
|
|
200
|
-
ActiveRecord::FixtureSet.reset_cache
|
|
201
200
|
end
|
|
202
201
|
|
|
203
|
-
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
def enlist_fixture_connections
|
|
207
|
-
setup_shared_connection_pool
|
|
208
|
-
|
|
209
|
-
ActiveRecord::Base.connection_handler.connection_pool_list(:writing).map(&:connection)
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
private
|
|
213
202
|
# Shares the writing connection pool with connections on
|
|
214
203
|
# other handlers.
|
|
215
204
|
#
|
|
@@ -272,22 +261,30 @@ module ActiveRecord
|
|
|
272
261
|
use_instantiated_fixtures != :no_instances
|
|
273
262
|
end
|
|
274
263
|
|
|
275
|
-
def method_missing(
|
|
276
|
-
if
|
|
277
|
-
|
|
264
|
+
def method_missing(method, ...)
|
|
265
|
+
if fixture_sets.key?(method.name)
|
|
266
|
+
active_record_fixture(method, ...)
|
|
278
267
|
else
|
|
279
268
|
super
|
|
280
269
|
end
|
|
281
270
|
end
|
|
282
271
|
|
|
283
|
-
def respond_to_missing?(
|
|
284
|
-
if include_private && fixture_sets.key?(name
|
|
272
|
+
def respond_to_missing?(method, include_private = false)
|
|
273
|
+
if include_private && fixture_sets.key?(method.name)
|
|
285
274
|
true
|
|
286
275
|
else
|
|
287
276
|
super
|
|
288
277
|
end
|
|
289
278
|
end
|
|
290
279
|
|
|
280
|
+
def active_record_fixture(fixture_set_name, *fixture_names)
|
|
281
|
+
if fs_name = fixture_sets[fixture_set_name.name]
|
|
282
|
+
access_fixture(fs_name, *fixture_names)
|
|
283
|
+
else
|
|
284
|
+
raise StandardError, "No fixture set named '#{fixture_set_name.inspect}'"
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
291
288
|
def access_fixture(fs_name, *fixture_names)
|
|
292
289
|
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
|
293
290
|
return_single_record = fixture_names.size == 1
|