activerecord 6.0.0 → 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 +996 -594
- data/MIT-LICENSE +1 -1
- data/README.rdoc +34 -34
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +22 -20
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +41 -30
- data/lib/active_record/associations/association.rb +106 -41
- data/lib/active_record/associations/association_scope.rb +30 -21
- data/lib/active_record/associations/belongs_to_association.rb +69 -14
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
- data/lib/active_record/associations/builder/association.rb +39 -6
- data/lib/active_record/associations/builder/belongs_to.rb +47 -17
- data/lib/active_record/associations/builder/collection_association.rb +14 -6
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
- data/lib/active_record/associations/builder/has_many.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +13 -16
- data/lib/active_record/associations/builder/singular_association.rb +7 -3
- data/lib/active_record/associations/collection_association.rb +90 -53
- data/lib/active_record/associations/collection_proxy.rb +54 -19
- 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 +21 -1
- data/lib/active_record/associations/has_many_association.rb +41 -10
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +33 -9
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +97 -54
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +237 -54
- 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 +51 -17
- data/lib/active_record/associations/preloader.rb +55 -121
- data/lib/active_record/associations/singular_association.rb +16 -4
- data/lib/active_record/associations/through_association.rb +26 -15
- data/lib/active_record/associations.rb +454 -440
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +11 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +75 -34
- data/lib/active_record/attribute_methods/primary_key.rb +53 -31
- data/lib/active_record/attribute_methods/query.rb +31 -22
- data/lib/active_record/attribute_methods/read.rb +16 -17
- data/lib/active_record/attribute_methods/serialization.rb +177 -35
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
- data/lib/active_record/attribute_methods/write.rb +16 -28
- data/lib/active_record/attribute_methods.rb +227 -100
- data/lib/active_record/attributes.rb +94 -56
- data/lib/active_record/autosave_association.rb +119 -73
- data/lib/active_record/base.rb +31 -21
- data/lib/active_record/callbacks.rb +168 -55
- 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 -25
- 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 +367 -565
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
- data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
- data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
- data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
- data/lib/active_record/connection_adapters/column.rb +28 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
- data/lib/active_record/connection_adapters/pool_config.rb +83 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- 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 +23 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
- data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
- 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 +102 -24
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
- 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 +176 -0
- data/lib/active_record/connection_handling.rb +243 -115
- data/lib/active_record/core.rb +481 -199
- data/lib/active_record/counter_cache.rb +69 -32
- data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
- data/lib/active_record/database_configurations/database_config.rb +77 -10
- data/lib/active_record/database_configurations/hash_config.rb +148 -26
- data/lib/active_record/database_configurations/url_config.rb +44 -45
- data/lib/active_record/database_configurations.rb +190 -114
- data/lib/active_record/delegated_type.rb +279 -0
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +38 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +5 -6
- 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 +171 -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 +58 -0
- data/lib/active_record/enum.rb +224 -73
- data/lib/active_record/errors.rb +254 -36
- data/lib/active_record/explain.rb +30 -17
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +22 -15
- data/lib/active_record/fixture_set/model_metadata.rb +15 -6
- data/lib/active_record/fixture_set/render_context.rb +3 -1
- data/lib/active_record/fixture_set/table_row.rb +88 -16
- data/lib/active_record/fixture_set/table_rows.rb +4 -5
- data/lib/active_record/fixtures.rb +229 -116
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +121 -48
- data/lib/active_record/insert_all.rb +178 -29
- data/lib/active_record/integration.rb +16 -14
- data/lib/active_record/internal_metadata.rb +132 -21
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +64 -33
- data/lib/active_record/locking/pessimistic.rb +21 -8
- data/lib/active_record/log_subscriber.rb +61 -30
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
- data/lib/active_record/middleware/database_selector.rb +25 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +160 -55
- data/lib/active_record/migration/compatibility.rb +286 -43
- 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 -2
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +421 -193
- data/lib/active_record/model_schema.rb +217 -125
- data/lib/active_record/nested_attributes.rb +62 -27
- data/lib/active_record/no_touching.rb +4 -4
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +322 -319
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -15
- data/lib/active_record/query_logs.rb +193 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +54 -14
- data/lib/active_record/railtie.rb +250 -72
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +312 -197
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +45 -3
- data/lib/active_record/reflection.rb +389 -146
- data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
- data/lib/active_record/relation/batches.rb +214 -73
- data/lib/active_record/relation/calculations.rb +379 -124
- data/lib/active_record/relation/delegation.rb +36 -23
- data/lib/active_record/relation/finder_methods.rb +159 -49
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +41 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +79 -53
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +1156 -279
- data/lib/active_record/relation/record_fetch_warning.rb +12 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -9
- data/lib/active_record/relation/where_clause.rb +100 -66
- data/lib/active_record/relation.rb +829 -194
- data/lib/active_record/result.rb +76 -56
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +86 -47
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +140 -33
- data/lib/active_record/schema_migration.rb +74 -29
- data/lib/active_record/scoping/default.rb +73 -19
- data/lib/active_record/scoping/named.rb +10 -28
- data/lib/active_record/scoping.rb +65 -35
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +34 -8
- data/lib/active_record/serialization.rb +11 -4
- data/lib/active_record/signed_id.rb +138 -0
- data/lib/active_record/statement_cache.rb +26 -10
- data/lib/active_record/store.rb +19 -14
- data/lib/active_record/suppressor.rb +15 -17
- data/lib/active_record/table_metadata.rb +46 -36
- data/lib/active_record/tasks/database_tasks.rb +371 -205
- data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +189 -104
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +35 -25
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +31 -27
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +131 -99
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +33 -18
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +11 -6
- data/lib/active_record/type/time.rb +14 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +7 -2
- data/lib/active_record/type_caster/connection.rb +4 -5
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -8
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +88 -18
- data/lib/active_record/validations.rb +15 -8
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +446 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +4 -8
- data/lib/arel/collectors/bind.rb +8 -1
- data/lib/arel/collectors/composite.rb +15 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/crud.rb +30 -22
- data/lib/arel/delete_manager.rb +23 -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 +82 -9
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +22 -10
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +14 -13
- data/lib/arel/nodes/equality.rb +6 -9
- 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/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/join_source.rb +1 -1
- 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 +122 -11
- data/lib/arel/nodes/ordering.rb +27 -0
- 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 +16 -0
- data/lib/arel/nodes/table_alias.rb +11 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes/update_statement.rb +11 -4
- data/lib/arel/nodes.rb +10 -3
- data/lib/arel/predications.rb +31 -28
- data/lib/arel/select_manager.rb +18 -9
- data/lib/arel/table.rb +21 -10
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +25 -5
- data/lib/arel/visitors/dot.rb +94 -90
- data/lib/arel/visitors/mysql.rb +34 -6
- data/lib/arel/visitors/postgresql.rb +5 -16
- data/lib/arel/visitors/sqlite.rb +25 -1
- data/lib/arel/visitors/to_sql.rb +227 -81
- data/lib/arel/visitors/visitor.rb +2 -3
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +37 -15
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +9 -3
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- 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 +117 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/null_relation.rb +0 -68
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module Associations
|
|
7
|
+
# = Active Record \Preloader
|
|
8
|
+
#
|
|
5
9
|
# Implements the details of eager loading of Active Record associations.
|
|
6
10
|
#
|
|
7
11
|
# Suppose that you have the following two Active Record models:
|
|
@@ -20,8 +24,8 @@ module ActiveRecord
|
|
|
20
24
|
#
|
|
21
25
|
# Author.includes(:books).where(name: ['bell hooks', 'Homer']).to_a
|
|
22
26
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
27
|
+
# # SELECT `authors`.* FROM `authors` WHERE `name` IN ('bell hooks', 'Homer')
|
|
28
|
+
# # SELECT `books`.* FROM `books` WHERE `author_id` IN (2, 5)
|
|
25
29
|
#
|
|
26
30
|
# Active Record saves the ids of the records from the first query to use in
|
|
27
31
|
# the second. Depending on the number of associations involved there can be
|
|
@@ -31,23 +35,26 @@ module ActiveRecord
|
|
|
31
35
|
# Record will fall back to a slightly more resource-intensive single query:
|
|
32
36
|
#
|
|
33
37
|
# Author.includes(:books).where(books: {title: 'Illiad'}).to_a
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
38
|
+
# # SELECT `authors`.`id` AS t0_r0, `authors`.`name` AS t0_r1, `authors`.`age` AS t0_r2,
|
|
39
|
+
# # `books`.`id` AS t1_r0, `books`.`title` AS t1_r1, `books`.`sales` AS t1_r2
|
|
40
|
+
# # FROM `authors`
|
|
41
|
+
# # LEFT OUTER JOIN `books` ON `authors`.`id` = `books`.`author_id`
|
|
42
|
+
# # WHERE `books`.`title` = 'Illiad'
|
|
39
43
|
#
|
|
40
44
|
# This could result in many rows that contain redundant data and it performs poorly at scale
|
|
41
45
|
# and is therefore only used when necessary.
|
|
42
|
-
#
|
|
43
|
-
class Preloader #:nodoc:
|
|
46
|
+
class Preloader # :nodoc:
|
|
44
47
|
extend ActiveSupport::Autoload
|
|
45
48
|
|
|
46
49
|
eager_autoload do
|
|
47
50
|
autoload :Association, "active_record/associations/preloader/association"
|
|
51
|
+
autoload :Batch, "active_record/associations/preloader/batch"
|
|
52
|
+
autoload :Branch, "active_record/associations/preloader/branch"
|
|
48
53
|
autoload :ThroughAssociation, "active_record/associations/preloader/through_association"
|
|
49
54
|
end
|
|
50
55
|
|
|
56
|
+
attr_reader :records, :associations, :scope, :associate_by_default
|
|
57
|
+
|
|
51
58
|
# Eager loads the named associations for the given Active Record record(s).
|
|
52
59
|
#
|
|
53
60
|
# In this description, 'association name' shall refer to the name passed
|
|
@@ -58,7 +65,7 @@ module ActiveRecord
|
|
|
58
65
|
# == Parameters
|
|
59
66
|
# +records+ is an array of ActiveRecord::Base. This array needs not be flat,
|
|
60
67
|
# i.e. +records+ itself may also contain arrays of records. In any case,
|
|
61
|
-
# +preload_associations+ will preload
|
|
68
|
+
# +preload_associations+ will preload all associations records by
|
|
62
69
|
# flattening +records+.
|
|
63
70
|
#
|
|
64
71
|
# +associations+ specifies one or more associations that you want to
|
|
@@ -68,134 +75,61 @@ module ActiveRecord
|
|
|
68
75
|
# for an Author.
|
|
69
76
|
# - an Array which specifies multiple association names. This array
|
|
70
77
|
# is processed recursively. For example, specifying <tt>[:avatar, :books]</tt>
|
|
71
|
-
# allows this method to preload an author's avatar as well as all of
|
|
78
|
+
# allows this method to preload an author's avatar as well as all of their
|
|
72
79
|
# books.
|
|
73
80
|
# - a Hash which specifies multiple association names, as well as
|
|
74
81
|
# association names for the to-be-preloaded association objects. For
|
|
75
82
|
# example, specifying <tt>{ author: :avatar }</tt> will preload a
|
|
76
83
|
# book's author, as well as that author's avatar.
|
|
77
84
|
#
|
|
78
|
-
# +:associations+ has the same format as the
|
|
79
|
-
#
|
|
85
|
+
# +:associations+ has the same format as the arguments to
|
|
86
|
+
# ActiveRecord::QueryMethods#includes. So +associations+ could look like
|
|
87
|
+
# this:
|
|
80
88
|
#
|
|
81
89
|
# :books
|
|
82
90
|
# [ :books, :author ]
|
|
83
91
|
# { author: :avatar }
|
|
84
92
|
# [ :books, { author: :avatar } ]
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
#
|
|
94
|
+
# +available_records+ is an array of ActiveRecord::Base. The Preloader
|
|
95
|
+
# will try to use the objects in this array to preload the requested
|
|
96
|
+
# associations before querying the database. This can save database
|
|
97
|
+
# queries by reusing in-memory objects. The optimization is only applied
|
|
98
|
+
# to single associations (i.e. :belongs_to, :has_one) with no scopes.
|
|
99
|
+
def initialize(records:, associations:, scope: nil, available_records: [], associate_by_default: true)
|
|
100
|
+
@records = records
|
|
101
|
+
@associations = associations
|
|
102
|
+
@scope = scope
|
|
103
|
+
@available_records = available_records || []
|
|
104
|
+
@associate_by_default = associate_by_default
|
|
105
|
+
|
|
106
|
+
@tree = Branch.new(
|
|
107
|
+
parent: nil,
|
|
108
|
+
association: nil,
|
|
109
|
+
children: @associations,
|
|
110
|
+
associate_by_default: @associate_by_default,
|
|
111
|
+
scope: @scope
|
|
112
|
+
)
|
|
113
|
+
@tree.preloaded_records = @records
|
|
95
114
|
end
|
|
96
115
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def preloaders_on(association, records, scope, polymorphic_parent = false)
|
|
101
|
-
case association
|
|
102
|
-
when Hash
|
|
103
|
-
preloaders_for_hash(association, records, scope, polymorphic_parent)
|
|
104
|
-
when Symbol, String
|
|
105
|
-
preloaders_for_one(association, records, scope, polymorphic_parent)
|
|
106
|
-
else
|
|
107
|
-
raise ArgumentError, "#{association.inspect} was not recognized for preload"
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def preloaders_for_hash(association, records, scope, polymorphic_parent)
|
|
112
|
-
association.flat_map { |parent, child|
|
|
113
|
-
grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
|
|
114
|
-
loaders = preloaders_for_reflection(reflection, reflection_records, scope)
|
|
115
|
-
recs = loaders.flat_map(&:preloaded_records)
|
|
116
|
-
child_polymorphic_parent = reflection && reflection.options[:polymorphic]
|
|
117
|
-
loaders.concat Array.wrap(child).flat_map { |assoc|
|
|
118
|
-
preloaders_on assoc, recs, scope, child_polymorphic_parent
|
|
119
|
-
}
|
|
120
|
-
loaders
|
|
121
|
-
end
|
|
122
|
-
}
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Loads all the given data into +records+ for a singular +association+.
|
|
126
|
-
#
|
|
127
|
-
# Functions by instantiating a preloader class such as Preloader::Association and
|
|
128
|
-
# call the +run+ method for each passed in class in the +records+ argument.
|
|
129
|
-
#
|
|
130
|
-
# Not all records have the same class, so group then preload group on the reflection
|
|
131
|
-
# itself so that if various subclass share the same association then we do not split
|
|
132
|
-
# them unnecessarily
|
|
133
|
-
#
|
|
134
|
-
# Additionally, polymorphic belongs_to associations can have multiple associated
|
|
135
|
-
# classes, depending on the polymorphic_type field. So we group by the classes as
|
|
136
|
-
# well.
|
|
137
|
-
def preloaders_for_one(association, records, scope, polymorphic_parent)
|
|
138
|
-
grouped_records(association, records, polymorphic_parent)
|
|
139
|
-
.flat_map do |reflection, reflection_records|
|
|
140
|
-
preloaders_for_reflection reflection, reflection_records, scope
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def preloaders_for_reflection(reflection, records, scope)
|
|
145
|
-
records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
|
|
146
|
-
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope).run
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def grouped_records(association, records, polymorphic_parent)
|
|
151
|
-
h = {}
|
|
152
|
-
records.each do |record|
|
|
153
|
-
reflection = record.class._reflect_on_association(association)
|
|
154
|
-
next if polymorphic_parent && !reflection || !record.association(association).klass
|
|
155
|
-
(h[reflection] ||= []) << record
|
|
156
|
-
end
|
|
157
|
-
h
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
class AlreadyLoaded # :nodoc:
|
|
161
|
-
def initialize(klass, owners, reflection, preload_scope)
|
|
162
|
-
@owners = owners
|
|
163
|
-
@reflection = reflection
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def run
|
|
167
|
-
self
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def preloaded_records
|
|
171
|
-
@preloaded_records ||= records_by_owner.flat_map(&:last)
|
|
172
|
-
end
|
|
116
|
+
def empty?
|
|
117
|
+
associations.nil? || records.length == 0
|
|
118
|
+
end
|
|
173
119
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
result[owner] = Array(owner.association(reflection.name).target)
|
|
177
|
-
end
|
|
178
|
-
end
|
|
120
|
+
def call
|
|
121
|
+
Batch.new([self], available_records: @available_records).call
|
|
179
122
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
end
|
|
123
|
+
loaders
|
|
124
|
+
end
|
|
183
125
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def preloader_for(reflection, owners)
|
|
188
|
-
if owners.first.association(reflection.name).loaded?
|
|
189
|
-
return AlreadyLoaded
|
|
190
|
-
end
|
|
191
|
-
reflection.check_preloadable!
|
|
126
|
+
def branches
|
|
127
|
+
@tree.children
|
|
128
|
+
end
|
|
192
129
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Association
|
|
197
|
-
end
|
|
198
|
-
end
|
|
130
|
+
def loaders
|
|
131
|
+
branches.flat_map(&:loaders)
|
|
132
|
+
end
|
|
199
133
|
end
|
|
200
134
|
end
|
|
201
135
|
end
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
module Associations
|
|
5
|
-
class SingularAssociation < Association
|
|
5
|
+
class SingularAssociation < Association # :nodoc:
|
|
6
6
|
# Implements the reader method, e.g. foo.bar for Foo.has_one :bar
|
|
7
7
|
def reader
|
|
8
|
+
ensure_klass_exists!
|
|
9
|
+
|
|
8
10
|
if !loaded? || stale_target?
|
|
9
11
|
reload
|
|
10
12
|
end
|
|
@@ -12,12 +14,18 @@ module ActiveRecord
|
|
|
12
14
|
target
|
|
13
15
|
end
|
|
14
16
|
|
|
17
|
+
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
|
|
18
|
+
def reset
|
|
19
|
+
super
|
|
20
|
+
@target = nil
|
|
21
|
+
end
|
|
22
|
+
|
|
15
23
|
# Implements the writer method, e.g. foo.bar= for Foo.belongs_to :bar
|
|
16
24
|
def writer(record)
|
|
17
25
|
replace(record)
|
|
18
26
|
end
|
|
19
27
|
|
|
20
|
-
def build(attributes =
|
|
28
|
+
def build(attributes = nil, &block)
|
|
21
29
|
record = build_record(attributes, &block)
|
|
22
30
|
set_new_record(record)
|
|
23
31
|
record
|
|
@@ -32,11 +40,15 @@ module ActiveRecord
|
|
|
32
40
|
|
|
33
41
|
private
|
|
34
42
|
def scope_for_create
|
|
35
|
-
super.except!(klass.primary_key)
|
|
43
|
+
super.except!(*Array(klass.primary_key))
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
def find_target
|
|
39
|
-
|
|
47
|
+
if disable_joins
|
|
48
|
+
scope.first
|
|
49
|
+
else
|
|
50
|
+
super.first
|
|
51
|
+
end
|
|
40
52
|
end
|
|
41
53
|
|
|
42
54
|
def replace(record)
|
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
module Associations
|
|
5
5
|
# = Active Record Through Association
|
|
6
|
-
module ThroughAssociation
|
|
6
|
+
module ThroughAssociation # :nodoc:
|
|
7
7
|
delegate :source_reflection, to: :reflection
|
|
8
8
|
|
|
9
9
|
private
|
|
10
|
+
def transaction(&block)
|
|
11
|
+
through_reflection.klass.transaction(&block)
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
def through_reflection
|
|
11
15
|
@through_reflection ||= begin
|
|
12
16
|
refl = reflection.through_reflection
|
|
@@ -32,7 +36,7 @@ module ActiveRecord
|
|
|
32
36
|
reflection.chain.drop(1).each do |reflection|
|
|
33
37
|
relation = reflection.klass.scope_for_association
|
|
34
38
|
scope.merge!(
|
|
35
|
-
relation.except(:select, :create_with, :includes, :preload, :joins, :
|
|
39
|
+
relation.except(:select, :create_with, :includes, :preload, :eager_load, :joins, :left_outer_joins)
|
|
36
40
|
)
|
|
37
41
|
end
|
|
38
42
|
scope
|
|
@@ -55,12 +59,11 @@ module ActiveRecord
|
|
|
55
59
|
|
|
56
60
|
association_primary_key = source_reflection.association_primary_key(reflection.klass)
|
|
57
61
|
|
|
58
|
-
if association_primary_key == reflection.klass.
|
|
62
|
+
if Array(association_primary_key) == reflection.klass.composite_query_constraints_list && !options[:source_type]
|
|
59
63
|
join_attributes = { source_reflection.name => records }
|
|
60
64
|
else
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
65
|
+
assoc_pk_values = records.map { |record| record._read_attribute(association_primary_key) }
|
|
66
|
+
join_attributes = { source_reflection.foreign_key => assoc_pk_values }
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
if options[:source_type]
|
|
@@ -74,16 +77,20 @@ module ActiveRecord
|
|
|
74
77
|
end
|
|
75
78
|
end
|
|
76
79
|
|
|
77
|
-
# Note: this does not capture all cases, for example it would be
|
|
78
|
-
# properly support stale-checking for nested associations.
|
|
80
|
+
# Note: this does not capture all cases, for example it would be impractical
|
|
81
|
+
# to try to properly support stale-checking for nested associations.
|
|
79
82
|
def stale_state
|
|
80
83
|
if through_reflection.belongs_to?
|
|
81
|
-
|
|
84
|
+
Array(through_reflection.foreign_key).filter_map do |foreign_key_column|
|
|
85
|
+
owner[foreign_key_column]
|
|
86
|
+
end.presence
|
|
82
87
|
end
|
|
83
88
|
end
|
|
84
89
|
|
|
85
90
|
def foreign_key_present?
|
|
86
|
-
through_reflection.belongs_to? &&
|
|
91
|
+
through_reflection.belongs_to? && Array(through_reflection.foreign_key).all? do |foreign_key_column|
|
|
92
|
+
!owner[foreign_key_column].nil?
|
|
93
|
+
end
|
|
87
94
|
end
|
|
88
95
|
|
|
89
96
|
def ensure_mutable
|
|
@@ -107,11 +114,15 @@ module ActiveRecord
|
|
|
107
114
|
end
|
|
108
115
|
|
|
109
116
|
def build_record(attributes)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
if source_reflection.collection?
|
|
118
|
+
inverse = source_reflection.inverse_of
|
|
119
|
+
target = through_association.target
|
|
120
|
+
|
|
121
|
+
if inverse && target && !target.is_a?(Array)
|
|
122
|
+
Array(target.id).zip(Array(inverse.foreign_key)).map do |primary_key_value, foreign_key_column|
|
|
123
|
+
attributes[foreign_key_column] = primary_key_value
|
|
124
|
+
end
|
|
125
|
+
end
|
|
115
126
|
end
|
|
116
127
|
|
|
117
128
|
super
|