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,9 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "active_support/core_ext/module/delegation"
|
|
4
4
|
|
|
5
5
|
module ActiveRecord
|
|
6
6
|
module Delegation # :nodoc:
|
|
7
|
+
class << self
|
|
8
|
+
def delegated_classes
|
|
9
|
+
[
|
|
10
|
+
ActiveRecord::Relation,
|
|
11
|
+
ActiveRecord::Associations::CollectionProxy,
|
|
12
|
+
ActiveRecord::AssociationRelation,
|
|
13
|
+
ActiveRecord::DisableJoinsAssociationRelation,
|
|
14
|
+
]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def uncacheable_methods
|
|
18
|
+
@uncacheable_methods ||= (
|
|
19
|
+
delegated_classes.flat_map(&:public_instance_methods) - ActiveRecord::Relation.public_instance_methods
|
|
20
|
+
).to_set.freeze
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
7
24
|
module DelegateCache # :nodoc:
|
|
8
25
|
def relation_delegate_class(klass)
|
|
9
26
|
@relation_delegate_cache[klass]
|
|
@@ -11,11 +28,7 @@ module ActiveRecord
|
|
|
11
28
|
|
|
12
29
|
def initialize_relation_delegate_cache
|
|
13
30
|
@relation_delegate_cache = cache = {}
|
|
14
|
-
|
|
15
|
-
ActiveRecord::Relation,
|
|
16
|
-
ActiveRecord::Associations::CollectionProxy,
|
|
17
|
-
ActiveRecord::AssociationRelation
|
|
18
|
-
].each do |klass|
|
|
31
|
+
Delegation.delegated_classes.each do |klass|
|
|
19
32
|
delegate = Class.new(klass) {
|
|
20
33
|
include ClassSpecificRelation
|
|
21
34
|
}
|
|
@@ -53,21 +66,21 @@ module ActiveRecord
|
|
|
53
66
|
end
|
|
54
67
|
|
|
55
68
|
class GeneratedRelationMethods < Module # :nodoc:
|
|
56
|
-
|
|
69
|
+
MUTEX = Mutex.new
|
|
57
70
|
|
|
58
71
|
def generate_method(method)
|
|
59
|
-
synchronize do
|
|
72
|
+
MUTEX.synchronize do
|
|
60
73
|
return if method_defined?(method)
|
|
61
74
|
|
|
62
|
-
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
|
|
75
|
+
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !::ActiveSupport::Delegation::RESERVED_METHOD_NAMES.include?(method.to_s)
|
|
63
76
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
64
|
-
def #{method}(
|
|
65
|
-
scoping { klass.#{method}(
|
|
77
|
+
def #{method}(...)
|
|
78
|
+
scoping { klass.#{method}(...) }
|
|
66
79
|
end
|
|
67
80
|
RUBY
|
|
68
81
|
else
|
|
69
|
-
define_method(method) do |*args, &block|
|
|
70
|
-
scoping { klass.public_send(method, *args, &block) }
|
|
82
|
+
define_method(method) do |*args, **kwargs, &block|
|
|
83
|
+
scoping { klass.public_send(method, *args, **kwargs, &block) }
|
|
71
84
|
end
|
|
72
85
|
end
|
|
73
86
|
end
|
|
@@ -82,12 +95,12 @@ module ActiveRecord
|
|
|
82
95
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
|
83
96
|
# for each different klass, and the delegations are compiled into that subclass only.
|
|
84
97
|
|
|
85
|
-
delegate :to_xml, :encode_with, :length, :each, :join,
|
|
98
|
+
delegate :to_xml, :encode_with, :length, :each, :join, :intersect?,
|
|
86
99
|
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
|
87
|
-
:to_sentence, :to_formatted_s, :as_json,
|
|
100
|
+
:to_sentence, :to_fs, :to_formatted_s, :as_json,
|
|
88
101
|
:shuffle, :split, :slice, :index, :rindex, to: :records
|
|
89
102
|
|
|
90
|
-
delegate :primary_key, :connection, to: :klass
|
|
103
|
+
delegate :primary_key, :lease_connection, :connection, :with_connection, :transaction, to: :klass
|
|
91
104
|
|
|
92
105
|
module ClassSpecificRelation # :nodoc:
|
|
93
106
|
extend ActiveSupport::Concern
|
|
@@ -99,11 +112,12 @@ module ActiveRecord
|
|
|
99
112
|
end
|
|
100
113
|
|
|
101
114
|
private
|
|
102
|
-
|
|
103
|
-
def method_missing(method, *args, &block)
|
|
115
|
+
def method_missing(method, ...)
|
|
104
116
|
if @klass.respond_to?(method)
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
unless Delegation.uncacheable_methods.include?(method)
|
|
118
|
+
@klass.generate_relation_method(method)
|
|
119
|
+
end
|
|
120
|
+
scoping { @klass.public_send(method, ...) }
|
|
107
121
|
else
|
|
108
122
|
super
|
|
109
123
|
end
|
|
@@ -111,12 +125,11 @@ module ActiveRecord
|
|
|
111
125
|
end
|
|
112
126
|
|
|
113
127
|
module ClassMethods # :nodoc:
|
|
114
|
-
def create(klass, *args)
|
|
115
|
-
relation_class_for(klass).new(klass, *args)
|
|
128
|
+
def create(klass, *args, **kwargs)
|
|
129
|
+
relation_class_for(klass).new(klass, *args, **kwargs)
|
|
116
130
|
end
|
|
117
131
|
|
|
118
132
|
private
|
|
119
|
-
|
|
120
133
|
def relation_class_for(klass)
|
|
121
134
|
klass.relation_delegate_class(self)
|
|
122
135
|
end
|
|
@@ -6,7 +6,9 @@ module ActiveRecord
|
|
|
6
6
|
module FinderMethods
|
|
7
7
|
ONE_AS_ONE = "1 AS one"
|
|
8
8
|
|
|
9
|
-
# Find by id - This can either be a specific id (
|
|
9
|
+
# Find by id - This can either be a specific id (ID), a list of ids (ID, ID, ID), or an array of ids ([ID, ID, ID]).
|
|
10
|
+
# `ID` refers to an "identifier". For models with a single-column primary key, `ID` will be a single value,
|
|
11
|
+
# and for models with a composite primary key, it will be an array of values.
|
|
10
12
|
# If one or more records cannot be found for the requested ids, then ActiveRecord::RecordNotFound will be raised.
|
|
11
13
|
# If the primary key is an integer, find by id coerces its arguments by using +to_i+.
|
|
12
14
|
#
|
|
@@ -14,10 +16,31 @@ module ActiveRecord
|
|
|
14
16
|
# Person.find("1") # returns the object for ID = 1
|
|
15
17
|
# Person.find("31-sarah") # returns the object for ID = 31
|
|
16
18
|
# Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
|
|
17
|
-
# Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
|
|
19
|
+
# Person.find([7, 17]) # returns an array for objects with IDs in (7, 17), or with composite primary key [7, 17]
|
|
18
20
|
# Person.find([1]) # returns an array for the object with ID = 1
|
|
19
21
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
|
20
22
|
#
|
|
23
|
+
# ==== Find a record for a composite primary key model
|
|
24
|
+
# TravelRoute.primary_key = [:origin, :destination]
|
|
25
|
+
#
|
|
26
|
+
# TravelRoute.find(["Ottawa", "London"])
|
|
27
|
+
# # => #<TravelRoute origin: "Ottawa", destination: "London">
|
|
28
|
+
#
|
|
29
|
+
# TravelRoute.find([["Paris", "Montreal"]])
|
|
30
|
+
# # => [#<TravelRoute origin: "Paris", destination: "Montreal">]
|
|
31
|
+
#
|
|
32
|
+
# TravelRoute.find(["New York", "Las Vegas"], ["New York", "Portland"])
|
|
33
|
+
# # => [
|
|
34
|
+
# # #<TravelRoute origin: "New York", destination: "Las Vegas">,
|
|
35
|
+
# # #<TravelRoute origin: "New York", destination: "Portland">
|
|
36
|
+
# # ]
|
|
37
|
+
#
|
|
38
|
+
# TravelRoute.find([["Berlin", "London"], ["Barcelona", "Lisbon"]])
|
|
39
|
+
# # => [
|
|
40
|
+
# # #<TravelRoute origin: "Berlin", destination: "London">,
|
|
41
|
+
# # #<TravelRoute origin: "Barcelona", destination: "Lisbon">
|
|
42
|
+
# # ]
|
|
43
|
+
#
|
|
21
44
|
# NOTE: The returned records are in the same order as the ids you provide.
|
|
22
45
|
# If you want the results to be sorted by database, you can use ActiveRecord::QueryMethods#where
|
|
23
46
|
# method and provide an explicit ActiveRecord::QueryMethods#order option.
|
|
@@ -64,6 +87,14 @@ module ActiveRecord
|
|
|
64
87
|
#
|
|
65
88
|
# Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
|
|
66
89
|
# # returns an Array of the required fields.
|
|
90
|
+
#
|
|
91
|
+
# ==== Edge Cases
|
|
92
|
+
#
|
|
93
|
+
# Person.find(37) # raises ActiveRecord::RecordNotFound exception if the record with the given ID does not exist.
|
|
94
|
+
# Person.find([37]) # raises ActiveRecord::RecordNotFound exception if the record with the given ID in the input array does not exist.
|
|
95
|
+
# Person.find(nil) # raises ActiveRecord::RecordNotFound exception if the argument is nil.
|
|
96
|
+
# Person.find([]) # returns an empty array if the argument is an empty array.
|
|
97
|
+
# Person.find # raises ActiveRecord::RecordNotFound exception if the argument is not provided.
|
|
67
98
|
def find(*args)
|
|
68
99
|
return super if block_given?
|
|
69
100
|
find_with_ids(*args)
|
|
@@ -104,6 +135,32 @@ module ActiveRecord
|
|
|
104
135
|
take || raise_record_not_found_exception!
|
|
105
136
|
end
|
|
106
137
|
|
|
138
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
|
139
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
|
140
|
+
# record is found.
|
|
141
|
+
#
|
|
142
|
+
# Product.where(["price = %?", price]).sole
|
|
143
|
+
def sole
|
|
144
|
+
found, undesired = first(2)
|
|
145
|
+
|
|
146
|
+
if found.nil?
|
|
147
|
+
raise_record_not_found_exception!
|
|
148
|
+
elsif undesired.present?
|
|
149
|
+
raise ActiveRecord::SoleRecordExceeded.new(self)
|
|
150
|
+
else
|
|
151
|
+
found
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
|
156
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
|
157
|
+
# record is found.
|
|
158
|
+
#
|
|
159
|
+
# Product.find_sole_by(["price = %?", price])
|
|
160
|
+
def find_sole_by(arg, *args)
|
|
161
|
+
where(arg, *args).sole
|
|
162
|
+
end
|
|
163
|
+
|
|
107
164
|
# Find the first record (or first N records if a parameter is supplied).
|
|
108
165
|
# If no order is defined it will order by primary key.
|
|
109
166
|
#
|
|
@@ -275,9 +332,9 @@ module ActiveRecord
|
|
|
275
332
|
# * Integer - Finds the record with this primary key.
|
|
276
333
|
# * String - Finds the record with a primary key corresponding to this
|
|
277
334
|
# string (such as <tt>'5'</tt>).
|
|
278
|
-
# * Array - Finds the record that matches these +
|
|
335
|
+
# * Array - Finds the record that matches these +where+-style conditions
|
|
279
336
|
# (such as <tt>['name LIKE ?', "%#{query}%"]</tt>).
|
|
280
|
-
# * Hash - Finds the record that matches these +
|
|
337
|
+
# * Hash - Finds the record that matches these +where+-style conditions
|
|
281
338
|
# (such as <tt>{name: 'David'}</tt>).
|
|
282
339
|
# * +false+ - Returns always +false+.
|
|
283
340
|
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
|
@@ -298,6 +355,8 @@ module ActiveRecord
|
|
|
298
355
|
# Person.exists?
|
|
299
356
|
# Person.where(name: 'Spartacus', rating: 4).exists?
|
|
300
357
|
def exists?(conditions = :none)
|
|
358
|
+
return false if @none
|
|
359
|
+
|
|
301
360
|
if Base === conditions
|
|
302
361
|
raise ArgumentError, <<-MSG.squish
|
|
303
362
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
|
@@ -313,10 +372,40 @@ module ActiveRecord
|
|
|
313
372
|
end
|
|
314
373
|
|
|
315
374
|
relation = construct_relation_for_exists(conditions)
|
|
375
|
+
return false if relation.where_clause.contradiction?
|
|
376
|
+
|
|
377
|
+
skip_query_cache_if_necessary do
|
|
378
|
+
with_connection do |c|
|
|
379
|
+
c.select_rows(relation.arel, "#{name} Exists?").size == 1
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Returns true if the relation contains the given record or false otherwise.
|
|
385
|
+
#
|
|
386
|
+
# No query is performed if the relation is loaded; the given record is
|
|
387
|
+
# compared to the records in memory. If the relation is unloaded, an
|
|
388
|
+
# efficient existence query is performed, as in #exists?.
|
|
389
|
+
def include?(record)
|
|
390
|
+
# The existing implementation relies on receiving an Active Record instance as the input parameter named record.
|
|
391
|
+
# Any non-Active Record object passed to this implementation is guaranteed to return `false`.
|
|
392
|
+
return false unless record.is_a?(klass)
|
|
393
|
+
|
|
394
|
+
if loaded? || offset_value || limit_value || having_clause.any?
|
|
395
|
+
records.include?(record)
|
|
396
|
+
else
|
|
397
|
+
id = if record.class.composite_primary_key?
|
|
398
|
+
record.class.primary_key.zip(record.id).to_h
|
|
399
|
+
else
|
|
400
|
+
record.id
|
|
401
|
+
end
|
|
316
402
|
|
|
317
|
-
|
|
403
|
+
exists?(id)
|
|
404
|
+
end
|
|
318
405
|
end
|
|
319
406
|
|
|
407
|
+
alias :member? :include?
|
|
408
|
+
|
|
320
409
|
# This method is called whenever no records are found with either a single
|
|
321
410
|
# id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
|
|
322
411
|
#
|
|
@@ -326,31 +415,27 @@ module ActiveRecord
|
|
|
326
415
|
# the expected number of results should be provided in the +expected_size+
|
|
327
416
|
# argument.
|
|
328
417
|
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
|
329
|
-
conditions = arel.where_sql(
|
|
330
|
-
|
|
418
|
+
conditions = " [#{arel.where_sql(klass)}]" unless where_clause.empty?
|
|
419
|
+
|
|
331
420
|
name = @klass.name
|
|
332
421
|
|
|
333
422
|
if ids.nil?
|
|
334
423
|
error = +"Couldn't find #{name}"
|
|
335
424
|
error << " with#{conditions}" if conditions
|
|
336
425
|
raise RecordNotFound.new(error, name, key)
|
|
337
|
-
elsif Array(ids).size == 1
|
|
338
|
-
|
|
426
|
+
elsif Array.wrap(ids).size == 1
|
|
427
|
+
id = Array.wrap(ids)[0]
|
|
428
|
+
error = "Couldn't find #{name} with '#{key}'=#{id.inspect}#{conditions}"
|
|
339
429
|
raise RecordNotFound.new(error, name, key, ids)
|
|
340
430
|
else
|
|
341
431
|
error = +"Couldn't find all #{name.pluralize} with '#{key}': "
|
|
342
|
-
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
|
343
|
-
error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
|
|
432
|
+
error << "(#{ids.map(&:inspect).join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
|
433
|
+
error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.map(&:inspect).join(', ')}." if not_found_ids
|
|
344
434
|
raise RecordNotFound.new(error, name, key, ids)
|
|
345
435
|
end
|
|
346
436
|
end
|
|
347
437
|
|
|
348
438
|
private
|
|
349
|
-
|
|
350
|
-
def offset_index
|
|
351
|
-
offset_value || 0
|
|
352
|
-
end
|
|
353
|
-
|
|
354
439
|
def construct_relation_for_exists(conditions)
|
|
355
440
|
conditions = sanitize_forbidden_attributes(conditions)
|
|
356
441
|
|
|
@@ -372,16 +457,25 @@ module ActiveRecord
|
|
|
372
457
|
|
|
373
458
|
def apply_join_dependency(eager_loading: group_values.empty?)
|
|
374
459
|
join_dependency = construct_join_dependency(
|
|
375
|
-
eager_load_values
|
|
460
|
+
eager_load_values | includes_values, Arel::Nodes::OuterJoin
|
|
376
461
|
)
|
|
377
462
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
|
378
463
|
|
|
379
|
-
if eager_loading && !
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
464
|
+
if eager_loading && has_limit_or_offset? && !(
|
|
465
|
+
using_limitable_reflections?(join_dependency.reflections) &&
|
|
466
|
+
using_limitable_reflections?(
|
|
467
|
+
construct_join_dependency(
|
|
468
|
+
select_association_list(joins_values).concat(
|
|
469
|
+
select_association_list(left_outer_joins_values)
|
|
470
|
+
), nil
|
|
471
|
+
).reflections
|
|
472
|
+
)
|
|
473
|
+
)
|
|
474
|
+
relation = skip_query_cache_if_necessary do
|
|
475
|
+
klass.with_connection do |c|
|
|
476
|
+
c.distinct_relation_for_primary_key(relation)
|
|
477
|
+
end
|
|
383
478
|
end
|
|
384
|
-
relation.limit_value = relation.offset_value = nil
|
|
385
479
|
end
|
|
386
480
|
|
|
387
481
|
if block_given?
|
|
@@ -391,18 +485,6 @@ module ActiveRecord
|
|
|
391
485
|
end
|
|
392
486
|
end
|
|
393
487
|
|
|
394
|
-
def limited_ids_for(relation)
|
|
395
|
-
values = @klass.connection.columns_for_distinct(
|
|
396
|
-
connection.visitor.compile(arel_attribute(primary_key)),
|
|
397
|
-
relation.order_values
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
relation = relation.except(:select).select(values).distinct!
|
|
401
|
-
|
|
402
|
-
id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
|
|
403
|
-
id_rows.map { |row| row[primary_key] }
|
|
404
|
-
end
|
|
405
|
-
|
|
406
488
|
def using_limitable_reflections?(reflections)
|
|
407
489
|
reflections.none?(&:collection?)
|
|
408
490
|
end
|
|
@@ -410,10 +492,17 @@ module ActiveRecord
|
|
|
410
492
|
def find_with_ids(*ids)
|
|
411
493
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
|
412
494
|
|
|
413
|
-
expects_array =
|
|
495
|
+
expects_array = if klass.composite_primary_key?
|
|
496
|
+
ids.first.first.is_a?(Array)
|
|
497
|
+
else
|
|
498
|
+
ids.first.is_a?(Array)
|
|
499
|
+
end
|
|
500
|
+
|
|
414
501
|
return [] if expects_array && ids.first.empty?
|
|
415
502
|
|
|
416
|
-
ids = ids.
|
|
503
|
+
ids = ids.first if expects_array
|
|
504
|
+
|
|
505
|
+
ids = ids.compact.uniq
|
|
417
506
|
|
|
418
507
|
model_name = @klass.name
|
|
419
508
|
|
|
@@ -437,7 +526,12 @@ module ActiveRecord
|
|
|
437
526
|
MSG
|
|
438
527
|
end
|
|
439
528
|
|
|
440
|
-
relation =
|
|
529
|
+
relation = if klass.composite_primary_key?
|
|
530
|
+
where(primary_key.zip(id).to_h)
|
|
531
|
+
else
|
|
532
|
+
where(primary_key => id)
|
|
533
|
+
end
|
|
534
|
+
|
|
441
535
|
record = relation.take
|
|
442
536
|
|
|
443
537
|
raise_record_not_found_exception!(id, 0, 1) unless record
|
|
@@ -448,7 +542,9 @@ module ActiveRecord
|
|
|
448
542
|
def find_some(ids)
|
|
449
543
|
return find_some_ordered(ids) unless order_values.present?
|
|
450
544
|
|
|
451
|
-
|
|
545
|
+
relation = where(primary_key => ids)
|
|
546
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
|
547
|
+
result = relation.to_a
|
|
452
548
|
|
|
453
549
|
expected_size =
|
|
454
550
|
if limit_value && ids.size > limit_value
|
|
@@ -472,13 +568,13 @@ module ActiveRecord
|
|
|
472
568
|
def find_some_ordered(ids)
|
|
473
569
|
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
|
474
570
|
|
|
475
|
-
|
|
571
|
+
relation = except(:limit, :offset)
|
|
572
|
+
relation = relation.where(primary_key => ids)
|
|
573
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
|
574
|
+
result = relation.records
|
|
476
575
|
|
|
477
576
|
if result.size == ids.size
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
records_by_id = result.index_by(&:id)
|
|
481
|
-
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
|
577
|
+
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
|
|
482
578
|
else
|
|
483
579
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
|
484
580
|
end
|
|
@@ -501,7 +597,8 @@ module ActiveRecord
|
|
|
501
597
|
end
|
|
502
598
|
|
|
503
599
|
def find_nth(index)
|
|
504
|
-
@offsets
|
|
600
|
+
@offsets ||= {}
|
|
601
|
+
@offsets[index] ||= find_nth_with_limit(index, 1).first
|
|
505
602
|
end
|
|
506
603
|
|
|
507
604
|
def find_nth_with_limit(index, limit)
|
|
@@ -515,7 +612,7 @@ module ActiveRecord
|
|
|
515
612
|
end
|
|
516
613
|
|
|
517
614
|
if limit > 0
|
|
518
|
-
relation = relation.offset(
|
|
615
|
+
relation = relation.offset((offset_value || 0) + index) unless index.zero?
|
|
519
616
|
relation.limit(limit).to_a
|
|
520
617
|
else
|
|
521
618
|
[]
|
|
@@ -529,10 +626,10 @@ module ActiveRecord
|
|
|
529
626
|
else
|
|
530
627
|
relation = ordered_relation
|
|
531
628
|
|
|
532
|
-
if
|
|
629
|
+
if relation.order_values.empty? || relation.has_limit_or_offset?
|
|
533
630
|
relation.records[-index]
|
|
534
631
|
else
|
|
535
|
-
relation.
|
|
632
|
+
relation.reverse_order.offset(index - 1).first
|
|
536
633
|
end
|
|
537
634
|
end
|
|
538
635
|
end
|
|
@@ -542,11 +639,24 @@ module ActiveRecord
|
|
|
542
639
|
end
|
|
543
640
|
|
|
544
641
|
def ordered_relation
|
|
545
|
-
if order_values.empty? && (implicit_order_column || primary_key)
|
|
546
|
-
order(
|
|
642
|
+
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
|
643
|
+
order(_order_columns.map { |column| table[column].asc })
|
|
547
644
|
else
|
|
548
645
|
self
|
|
549
646
|
end
|
|
550
647
|
end
|
|
648
|
+
|
|
649
|
+
def _order_columns
|
|
650
|
+
oc = []
|
|
651
|
+
|
|
652
|
+
oc << implicit_order_column if implicit_order_column
|
|
653
|
+
oc << query_constraints_list if query_constraints_list
|
|
654
|
+
|
|
655
|
+
if primary_key && query_constraints_list.nil?
|
|
656
|
+
oc << primary_key
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
oc.flatten.uniq.compact
|
|
660
|
+
end
|
|
551
661
|
end
|
|
552
662
|
end
|
|
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
|
14
14
|
@hash = hash
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def merge
|
|
17
|
+
def merge
|
|
18
18
|
Merger.new(relation, other).merge
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -28,19 +28,14 @@ module ActiveRecord
|
|
|
28
28
|
table: relation.table,
|
|
29
29
|
predicate_builder: relation.predicate_builder
|
|
30
30
|
)
|
|
31
|
-
hash.each
|
|
32
|
-
if k == :
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
else
|
|
36
|
-
other.joins!(*v)
|
|
37
|
-
end
|
|
38
|
-
elsif k == :select
|
|
39
|
-
other._select!(v)
|
|
31
|
+
hash.each do |k, v|
|
|
32
|
+
k = :_select if k == :select
|
|
33
|
+
if Array === v
|
|
34
|
+
other.public_send("#{k}!", *v)
|
|
40
35
|
else
|
|
41
|
-
other.
|
|
36
|
+
other.public_send("#{k}!", v)
|
|
42
37
|
end
|
|
43
|
-
|
|
38
|
+
end
|
|
44
39
|
other
|
|
45
40
|
end
|
|
46
41
|
end
|
|
@@ -54,30 +49,27 @@ module ActiveRecord
|
|
|
54
49
|
@other = other
|
|
55
50
|
end
|
|
56
51
|
|
|
57
|
-
NORMAL_VALUES = Relation::VALUE_METHODS -
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
NORMAL_VALUES
|
|
63
|
-
end
|
|
52
|
+
NORMAL_VALUES = Relation::VALUE_METHODS - Relation::CLAUSE_METHODS -
|
|
53
|
+
[
|
|
54
|
+
:select, :includes, :preload, :joins, :left_outer_joins,
|
|
55
|
+
:order, :reverse_order, :lock, :create_with, :reordering
|
|
56
|
+
]
|
|
64
57
|
|
|
65
58
|
def merge
|
|
66
|
-
|
|
59
|
+
NORMAL_VALUES.each do |name|
|
|
67
60
|
value = values[name]
|
|
68
61
|
# The unless clause is here mostly for performance reasons (since the `send` call might be moderately
|
|
69
62
|
# expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
|
|
70
63
|
# `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
|
|
71
64
|
# don't fall through the cracks.
|
|
72
65
|
unless value.nil? || (value.blank? && false != value)
|
|
73
|
-
|
|
74
|
-
relation._select!(*value)
|
|
75
|
-
else
|
|
76
|
-
relation.send("#{name}!", *value)
|
|
77
|
-
end
|
|
66
|
+
relation.public_send(:"#{name}!", *value)
|
|
78
67
|
end
|
|
79
68
|
end
|
|
80
69
|
|
|
70
|
+
relation.none! if other.null_relation?
|
|
71
|
+
|
|
72
|
+
merge_select_values
|
|
81
73
|
merge_multi_values
|
|
82
74
|
merge_single_values
|
|
83
75
|
merge_clauses
|
|
@@ -89,13 +81,24 @@ module ActiveRecord
|
|
|
89
81
|
end
|
|
90
82
|
|
|
91
83
|
private
|
|
84
|
+
def merge_select_values
|
|
85
|
+
return if other.select_values.empty?
|
|
86
|
+
|
|
87
|
+
if other.klass == relation.klass
|
|
88
|
+
relation.select_values |= other.select_values
|
|
89
|
+
else
|
|
90
|
+
relation.select_values |= other.instance_eval do
|
|
91
|
+
arel_columns(select_values)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
92
95
|
|
|
93
96
|
def merge_preloads
|
|
94
97
|
return if other.preload_values.empty? && other.includes_values.empty?
|
|
95
98
|
|
|
96
99
|
if other.klass == relation.klass
|
|
97
|
-
relation.
|
|
98
|
-
relation.
|
|
100
|
+
relation.preload_values |= other.preload_values unless other.preload_values.empty?
|
|
101
|
+
relation.includes_values |= other.includes_values unless other.includes_values.empty?
|
|
99
102
|
else
|
|
100
103
|
reflection = relation.klass.reflect_on_all_associations.find do |r|
|
|
101
104
|
r.class_name == other.klass.name
|
|
@@ -112,10 +115,10 @@ module ActiveRecord
|
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
def merge_joins
|
|
115
|
-
return if other.joins_values.
|
|
118
|
+
return if other.joins_values.empty?
|
|
116
119
|
|
|
117
120
|
if other.klass == relation.klass
|
|
118
|
-
relation.
|
|
121
|
+
relation.joins_values |= other.joins_values
|
|
119
122
|
else
|
|
120
123
|
associations, others = other.joins_values.partition do |join|
|
|
121
124
|
case join
|
|
@@ -131,16 +134,21 @@ module ActiveRecord
|
|
|
131
134
|
end
|
|
132
135
|
|
|
133
136
|
def merge_outer_joins
|
|
134
|
-
return if other.left_outer_joins_values.
|
|
137
|
+
return if other.left_outer_joins_values.empty?
|
|
135
138
|
|
|
136
139
|
if other.klass == relation.klass
|
|
137
|
-
relation.
|
|
140
|
+
relation.left_outer_joins_values |= other.left_outer_joins_values
|
|
138
141
|
else
|
|
139
|
-
associations = other.left_outer_joins_values
|
|
142
|
+
associations, others = other.left_outer_joins_values.partition do |join|
|
|
143
|
+
case join
|
|
144
|
+
when Hash, Symbol, Array; true
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
140
148
|
join_dependency = other.construct_join_dependency(
|
|
141
149
|
associations, Arel::Nodes::OuterJoin
|
|
142
150
|
)
|
|
143
|
-
relation.
|
|
151
|
+
relation.left_outer_joins!(join_dependency, *others)
|
|
144
152
|
end
|
|
145
153
|
end
|
|
146
154
|
|
|
@@ -13,27 +13,26 @@ module ActiveRecord
|
|
|
13
13
|
return attribute.in([]) if value.empty?
|
|
14
14
|
|
|
15
15
|
values = value.map { |x| x.is_a?(Base) ? x.id : x }
|
|
16
|
-
nils = values.
|
|
16
|
+
nils = values.compact!
|
|
17
17
|
ranges = values.extract! { |v| v.is_a?(Range) }
|
|
18
18
|
|
|
19
19
|
values_predicate =
|
|
20
20
|
case values.length
|
|
21
21
|
when 0 then NullPredicate
|
|
22
22
|
when 1 then predicate_builder.build(attribute, values.first)
|
|
23
|
-
else
|
|
24
|
-
values.map! do |v|
|
|
25
|
-
predicate_builder.build_bind_attribute(attribute.name, v)
|
|
26
|
-
end
|
|
27
|
-
values.empty? ? NullPredicate : attribute.in(values)
|
|
23
|
+
else Arel::Nodes::HomogeneousIn.new(values, attribute, :in)
|
|
28
24
|
end
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
values_predicate = values_predicate.or(
|
|
26
|
+
if nils
|
|
27
|
+
values_predicate = values_predicate.or(attribute.eq(nil))
|
|
32
28
|
end
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
if ranges.empty?
|
|
31
|
+
values_predicate
|
|
32
|
+
else
|
|
33
|
+
array_predicates = ranges.map! { |range| predicate_builder.build(attribute, range) }
|
|
34
|
+
array_predicates.inject(values_predicate, &:or)
|
|
35
|
+
end
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
private
|