activerecord 6.1.7 → 7.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +520 -1385
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +404 -509
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +2 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +51 -49
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +377 -142
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +276 -251
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +170 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +163 -63
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +143 -159
- data/lib/active_record/nested_attributes.rb +48 -21
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +19 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +234 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +325 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +300 -111
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +842 -150
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +277 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +64 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- 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 +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +100 -14
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
+
# = Active Record Connection Handling
|
4
5
|
module ConnectionHandling
|
5
6
|
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
|
6
7
|
DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
|
@@ -38,26 +39,25 @@ module ActiveRecord
|
|
38
39
|
# )
|
39
40
|
#
|
40
41
|
# In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
|
41
|
-
# is set (Rails automatically loads the contents of config/database.yml into it),
|
42
|
+
# is set (\Rails automatically loads the contents of config/database.yml into it),
|
42
43
|
# a symbol can also be given as argument, representing a key in the
|
43
44
|
# configuration hash:
|
44
45
|
#
|
45
46
|
# ActiveRecord::Base.establish_connection(:production)
|
46
47
|
#
|
47
|
-
# The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
|
48
|
+
# The exceptions AdapterNotSpecified, AdapterNotFound, and +ArgumentError+
|
48
49
|
# may be returned on an error.
|
49
50
|
def establish_connection(config_or_env = nil)
|
50
51
|
config_or_env ||= DEFAULT_ENV.call.to_sym
|
51
|
-
db_config
|
52
|
-
connection_handler.establish_connection(db_config, owner_name:
|
52
|
+
db_config = resolve_config_for_connection(config_or_env)
|
53
|
+
connection_handler.establish_connection(db_config, owner_name: self, role: current_role, shard: current_shard)
|
53
54
|
end
|
54
55
|
|
55
56
|
# Connects a model to the databases specified. The +database+ keyword
|
56
57
|
# takes a hash consisting of a +role+ and a +database_key+.
|
57
58
|
#
|
58
|
-
# This will
|
59
|
-
#
|
60
|
-
# establishes a connection to that config.
|
59
|
+
# This will look up the database config using the +database_key+ and
|
60
|
+
# establish a connection to that config.
|
61
61
|
#
|
62
62
|
# class AnimalsModel < ApplicationRecord
|
63
63
|
# self.abstract_class = true
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
# end
|
67
67
|
#
|
68
68
|
# +connects_to+ also supports horizontal sharding. The horizontal sharding API
|
69
|
-
#
|
69
|
+
# supports read replicas as well. You can connect a model to a list of shards like this:
|
70
70
|
#
|
71
71
|
# class AnimalsModel < ApplicationRecord
|
72
72
|
# self.abstract_class = true
|
@@ -87,28 +87,25 @@ module ActiveRecord
|
|
87
87
|
|
88
88
|
connections = []
|
89
89
|
|
90
|
-
|
91
|
-
|
92
|
-
handler = lookup_connection_handler(role.to_sym)
|
93
|
-
|
94
|
-
self.connection_class = true
|
95
|
-
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
90
|
+
if shards.empty?
|
91
|
+
shards[:default] = database
|
96
92
|
end
|
97
93
|
|
94
|
+
self.default_shard = shards.keys.first
|
95
|
+
|
98
96
|
shards.each do |shard, database_keys|
|
99
97
|
database_keys.each do |role, database_key|
|
100
|
-
db_config
|
101
|
-
handler = lookup_connection_handler(role.to_sym)
|
98
|
+
db_config = resolve_config_for_connection(database_key)
|
102
99
|
|
103
100
|
self.connection_class = true
|
104
|
-
connections <<
|
101
|
+
connections << connection_handler.establish_connection(db_config, owner_name: self, role: role, shard: shard.to_sym)
|
105
102
|
end
|
106
103
|
end
|
107
104
|
|
108
105
|
connections
|
109
106
|
end
|
110
107
|
|
111
|
-
# Connects to a role (
|
108
|
+
# Connects to a role (e.g. writing, reading, or a custom role) and/or
|
112
109
|
# shard for the duration of the block. At the end of the block the
|
113
110
|
# connection will be returned to the original role / shard.
|
114
111
|
#
|
@@ -134,48 +131,20 @@ module ActiveRecord
|
|
134
131
|
# ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do
|
135
132
|
# Dog.first # finds first Dog record stored on the shard one replica
|
136
133
|
# end
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
if legacy_connection_handling
|
141
|
-
if self != Base
|
142
|
-
raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
|
143
|
-
end
|
144
|
-
else
|
145
|
-
if self != Base && !abstract_class
|
146
|
-
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
147
|
-
end
|
148
|
-
|
149
|
-
if name != connection_specification_name && !primary_class?
|
150
|
-
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
|
151
|
-
end
|
134
|
+
def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
|
135
|
+
if self != Base && !abstract_class
|
136
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
152
137
|
end
|
153
138
|
|
154
|
-
if
|
155
|
-
raise
|
156
|
-
|
157
|
-
ActiveSupport::Deprecation.warn("The database key in `connected_to` is deprecated. It will be removed in Rails 7.0.0 without replacement.")
|
158
|
-
|
159
|
-
if database.is_a?(Hash)
|
160
|
-
role, database = database.first
|
161
|
-
role = role.to_sym
|
162
|
-
end
|
163
|
-
|
164
|
-
db_config, owner_name = resolve_config_for_connection(database)
|
165
|
-
handler = lookup_connection_handler(role)
|
166
|
-
|
167
|
-
handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
168
|
-
|
169
|
-
with_handler(role, &blk)
|
170
|
-
elsif role || shard
|
171
|
-
unless role
|
172
|
-
raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
|
173
|
-
end
|
139
|
+
if !connection_class? && !primary_class?
|
140
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
|
141
|
+
end
|
174
142
|
|
175
|
-
|
176
|
-
else
|
143
|
+
unless role || shard
|
177
144
|
raise ArgumentError, "must provide a `shard` and/or `role`."
|
178
145
|
end
|
146
|
+
|
147
|
+
with_role_and_shard(role, shard, prevent_writes, &blk)
|
179
148
|
end
|
180
149
|
|
181
150
|
# Connects a role and/or shard to the provided connection names. Optionally +prevent_writes+
|
@@ -194,17 +163,13 @@ module ActiveRecord
|
|
194
163
|
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
|
195
164
|
classes = classes.flatten
|
196
165
|
|
197
|
-
if legacy_connection_handling
|
198
|
-
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
|
199
|
-
end
|
200
|
-
|
201
166
|
if self != Base || classes.include?(Base)
|
202
167
|
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
|
203
168
|
end
|
204
169
|
|
205
|
-
prevent_writes = true if role == reading_role
|
170
|
+
prevent_writes = true if role == ActiveRecord.reading_role
|
206
171
|
|
207
|
-
|
172
|
+
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
|
208
173
|
yield
|
209
174
|
ensure
|
210
175
|
connected_to_stack.pop
|
@@ -218,13 +183,28 @@ module ActiveRecord
|
|
218
183
|
# It is not recommended to use this method in a request since it
|
219
184
|
# does not yield to a block like +connected_to+.
|
220
185
|
def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
|
221
|
-
if
|
222
|
-
raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
|
223
|
-
end
|
186
|
+
prevent_writes = true if role == ActiveRecord.reading_role
|
224
187
|
|
225
|
-
|
188
|
+
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
189
|
+
end
|
226
190
|
|
227
|
-
|
191
|
+
# Prohibit swapping shards while inside of the passed block.
|
192
|
+
#
|
193
|
+
# In some cases you may want to be able to swap shards but not allow a
|
194
|
+
# nested call to connected_to or connected_to_many to swap again. This
|
195
|
+
# is useful in cases you're using sharding to provide per-request
|
196
|
+
# database isolation.
|
197
|
+
def prohibit_shard_swapping(enabled = true)
|
198
|
+
prev_value = ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping]
|
199
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = enabled
|
200
|
+
yield
|
201
|
+
ensure
|
202
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = prev_value
|
203
|
+
end
|
204
|
+
|
205
|
+
# Determine whether or not shard swapping is currently prohibited
|
206
|
+
def shard_swapping_prohibited?
|
207
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping]
|
228
208
|
end
|
229
209
|
|
230
210
|
# Prevent writing to the database regardless of role.
|
@@ -239,88 +219,114 @@ module ActiveRecord
|
|
239
219
|
# See +READ_QUERY+ for the queries that are blocked by this
|
240
220
|
# method.
|
241
221
|
def while_preventing_writes(enabled = true, &block)
|
242
|
-
|
243
|
-
connection_handler.while_preventing_writes(enabled, &block)
|
244
|
-
else
|
245
|
-
connected_to(role: current_role, prevent_writes: enabled, &block)
|
246
|
-
end
|
222
|
+
connected_to(role: current_role, prevent_writes: enabled, &block)
|
247
223
|
end
|
248
224
|
|
249
|
-
# Returns true if role is the current connected role
|
225
|
+
# Returns true if role is the current connected role and/or
|
226
|
+
# current connected shard. If no shard is passed, the default will be
|
227
|
+
# used.
|
250
228
|
#
|
251
229
|
# ActiveRecord::Base.connected_to(role: :writing) do
|
252
230
|
# ActiveRecord::Base.connected_to?(role: :writing) #=> true
|
253
231
|
# ActiveRecord::Base.connected_to?(role: :reading) #=> false
|
254
232
|
# end
|
233
|
+
#
|
234
|
+
# ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
|
235
|
+
# ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one) #=> true
|
236
|
+
# ActiveRecord::Base.connected_to?(role: :reading, shard: :default) #=> false
|
237
|
+
# ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one) #=> true
|
238
|
+
# end
|
255
239
|
def connected_to?(role:, shard: ActiveRecord::Base.default_shard)
|
256
240
|
current_role == role.to_sym && current_shard == shard.to_sym
|
257
241
|
end
|
258
242
|
|
259
|
-
def lookup_connection_handler(handler_key) # :nodoc:
|
260
|
-
if ActiveRecord::Base.legacy_connection_handling
|
261
|
-
handler_key ||= ActiveRecord::Base.writing_role
|
262
|
-
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
263
|
-
else
|
264
|
-
ActiveRecord::Base.connection_handler
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
243
|
# Clears the query cache for all connections associated with the current thread.
|
269
244
|
def clear_query_caches_for_current_thread
|
270
|
-
|
271
|
-
|
272
|
-
clear_on_handler(handler)
|
273
|
-
end
|
274
|
-
else
|
275
|
-
clear_on_handler(ActiveRecord::Base.connection_handler)
|
245
|
+
connection_handler.each_connection_pool do |pool|
|
246
|
+
pool.clear_query_cache
|
276
247
|
end
|
277
248
|
end
|
278
249
|
|
279
250
|
# Returns the connection currently associated with the class. This can
|
280
251
|
# also be used to "borrow" the connection to do database work unrelated
|
281
252
|
# to any of the specific Active Records.
|
253
|
+
# The connection will remain leased for the entire duration of the request
|
254
|
+
# or job, or until +#release_connection+ is called.
|
255
|
+
def lease_connection
|
256
|
+
connection_pool.lease_connection
|
257
|
+
end
|
258
|
+
|
259
|
+
# Soft deprecated. Use +#with_connection+ or +#lease_connection+ instead.
|
282
260
|
def connection
|
283
|
-
|
261
|
+
pool = connection_pool
|
262
|
+
if pool.permanent_lease?
|
263
|
+
case ActiveRecord.permanent_connection_checkout
|
264
|
+
when :deprecated
|
265
|
+
ActiveRecord.deprecator.warn <<~MESSAGE
|
266
|
+
Called deprecated `ActiveRecord::Base.connection` method.
|
267
|
+
|
268
|
+
Either use `with_connection` or `lease_connection`.
|
269
|
+
MESSAGE
|
270
|
+
when :disallowed
|
271
|
+
raise ActiveRecordError, <<~MESSAGE
|
272
|
+
Called deprecated `ActiveRecord::Base.connection` method.
|
273
|
+
|
274
|
+
Either use `with_connection` or `lease_connection`.
|
275
|
+
MESSAGE
|
276
|
+
end
|
277
|
+
pool.lease_connection
|
278
|
+
else
|
279
|
+
pool.active_connection
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# Return the currently leased connection into the pool
|
284
|
+
def release_connection
|
285
|
+
connection_pool.release_connection
|
286
|
+
end
|
287
|
+
|
288
|
+
# Checkouts a connection from the pool, yield it and then check it back in.
|
289
|
+
# If a connection was already leased via #lease_connection or a parent call to
|
290
|
+
# #with_connection, that same connection is yieled.
|
291
|
+
# If #lease_connection is called inside the block, the connection won't be checked
|
292
|
+
# back in.
|
293
|
+
# If #connection is called inside the block, the connection won't be checked back in
|
294
|
+
# unless the +prevent_permanent_checkout+ argument is set to +true+.
|
295
|
+
def with_connection(prevent_permanent_checkout: false, &block)
|
296
|
+
connection_pool.with_connection(prevent_permanent_checkout: prevent_permanent_checkout, &block)
|
284
297
|
end
|
285
298
|
|
286
299
|
attr_writer :connection_specification_name
|
287
300
|
|
288
|
-
#
|
301
|
+
# Returns the connection specification name from the current class or its parent.
|
289
302
|
def connection_specification_name
|
290
|
-
if
|
303
|
+
if @connection_specification_name.nil?
|
291
304
|
return self == Base ? Base.name : superclass.connection_specification_name
|
292
305
|
end
|
293
306
|
@connection_specification_name
|
294
307
|
end
|
295
308
|
|
296
309
|
def primary_class? # :nodoc:
|
297
|
-
self == Base ||
|
298
|
-
end
|
299
|
-
|
300
|
-
# Returns the configuration of the associated connection as a hash:
|
301
|
-
#
|
302
|
-
# ActiveRecord::Base.connection_config
|
303
|
-
# # => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}
|
304
|
-
#
|
305
|
-
# Please use only for reading.
|
306
|
-
def connection_config
|
307
|
-
connection_pool.db_config.configuration_hash
|
310
|
+
self == Base || application_record_class?
|
308
311
|
end
|
309
|
-
deprecate connection_config: "Use connection_db_config instead"
|
310
312
|
|
311
313
|
# Returns the db_config object from the associated connection:
|
312
314
|
#
|
313
315
|
# ActiveRecord::Base.connection_db_config
|
314
316
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
315
|
-
# @name="primary", @config={pool: 5, timeout: 5000, database: "
|
317
|
+
# @name="primary", @config={pool: 5, timeout: 5000, database: "storage/development.sqlite3", adapter: "sqlite3"}>
|
316
318
|
#
|
317
319
|
# Use only for reading.
|
318
320
|
def connection_db_config
|
319
321
|
connection_pool.db_config
|
320
322
|
end
|
321
323
|
|
324
|
+
def adapter_class # :nodoc:
|
325
|
+
connection_pool.db_config.adapter_class
|
326
|
+
end
|
327
|
+
|
322
328
|
def connection_pool
|
323
|
-
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard
|
329
|
+
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard, strict: true)
|
324
330
|
end
|
325
331
|
|
326
332
|
def retrieve_connection
|
@@ -332,8 +338,9 @@ module ActiveRecord
|
|
332
338
|
connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard)
|
333
339
|
end
|
334
340
|
|
335
|
-
def remove_connection
|
336
|
-
name
|
341
|
+
def remove_connection
|
342
|
+
name = @connection_specification_name if defined?(@connection_specification_name)
|
343
|
+
|
337
344
|
# if removing a connection that has a pool, we reset the
|
338
345
|
# connection_specification_name so it will use the parent
|
339
346
|
# pool.
|
@@ -344,62 +351,41 @@ module ActiveRecord
|
|
344
351
|
connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
|
345
352
|
end
|
346
353
|
|
347
|
-
def
|
348
|
-
|
354
|
+
def schema_cache # :nodoc:
|
355
|
+
connection_pool.schema_cache
|
349
356
|
end
|
350
357
|
|
351
|
-
|
352
|
-
|
358
|
+
def clear_cache! # :nodoc:
|
359
|
+
connection_pool.schema_cache.clear!
|
360
|
+
end
|
353
361
|
|
354
362
|
private
|
355
|
-
def clear_on_handler(handler)
|
356
|
-
handler.all_connection_pools.each do |pool|
|
357
|
-
pool.connection.clear_query_cache if pool.active_connection?
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
363
|
def resolve_config_for_connection(config_or_env)
|
362
364
|
raise "Anonymous class is not allowed." unless name
|
363
365
|
|
364
|
-
|
365
|
-
self.connection_specification_name =
|
366
|
-
|
367
|
-
db_config = Base.configurations.resolve(config_or_env)
|
368
|
-
[db_config, self]
|
369
|
-
end
|
366
|
+
connection_name = primary_class? ? Base.name : name
|
367
|
+
self.connection_specification_name = connection_name
|
370
368
|
|
371
|
-
|
372
|
-
handler = lookup_connection_handler(handler_key)
|
373
|
-
swap_connection_handler(handler, &blk)
|
369
|
+
Base.configurations.resolve(config_or_env)
|
374
370
|
end
|
375
371
|
|
376
372
|
def with_role_and_shard(role, shard, prevent_writes)
|
377
|
-
prevent_writes = true if role == reading_role
|
378
|
-
|
379
|
-
if ActiveRecord::Base.legacy_connection_handling
|
380
|
-
with_handler(role.to_sym) do
|
381
|
-
connection_handler.while_preventing_writes(prevent_writes) do
|
382
|
-
self.connected_to_stack << { shard: shard, klasses: [self] }
|
383
|
-
yield
|
384
|
-
end
|
385
|
-
end
|
386
|
-
else
|
387
|
-
self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
|
388
|
-
return_value = yield
|
389
|
-
return_value.load if return_value.is_a? ActiveRecord::Relation
|
390
|
-
return_value
|
391
|
-
end
|
392
|
-
ensure
|
393
|
-
self.connected_to_stack.pop
|
394
|
-
end
|
373
|
+
prevent_writes = true if role == ActiveRecord.reading_role
|
395
374
|
|
396
|
-
|
397
|
-
old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
|
375
|
+
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
398
376
|
return_value = yield
|
399
377
|
return_value.load if return_value.is_a? ActiveRecord::Relation
|
400
378
|
return_value
|
401
379
|
ensure
|
402
|
-
|
380
|
+
self.connected_to_stack.pop
|
381
|
+
end
|
382
|
+
|
383
|
+
def append_to_connected_to_stack(entry)
|
384
|
+
if shard_swapping_prohibited? && entry[:shard].present?
|
385
|
+
raise ArgumentError, "cannot swap `shard` while shard swapping is prohibited."
|
386
|
+
end
|
387
|
+
|
388
|
+
connected_to_stack << entry
|
403
389
|
end
|
404
390
|
end
|
405
391
|
end
|