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,10 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "mutex_m"
|
4
3
|
require "active_support/core_ext/module/delegation"
|
5
4
|
|
6
5
|
module ActiveRecord
|
7
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
|
+
|
8
24
|
module DelegateCache # :nodoc:
|
9
25
|
def relation_delegate_class(klass)
|
10
26
|
@relation_delegate_cache[klass]
|
@@ -12,11 +28,7 @@ module ActiveRecord
|
|
12
28
|
|
13
29
|
def initialize_relation_delegate_cache
|
14
30
|
@relation_delegate_cache = cache = {}
|
15
|
-
|
16
|
-
ActiveRecord::Relation,
|
17
|
-
ActiveRecord::Associations::CollectionProxy,
|
18
|
-
ActiveRecord::AssociationRelation
|
19
|
-
].each do |klass|
|
31
|
+
Delegation.delegated_classes.each do |klass|
|
20
32
|
delegate = Class.new(klass) {
|
21
33
|
include ClassSpecificRelation
|
22
34
|
}
|
@@ -54,24 +66,22 @@ module ActiveRecord
|
|
54
66
|
end
|
55
67
|
|
56
68
|
class GeneratedRelationMethods < Module # :nodoc:
|
57
|
-
|
69
|
+
MUTEX = Mutex.new
|
58
70
|
|
59
71
|
def generate_method(method)
|
60
|
-
synchronize do
|
72
|
+
MUTEX.synchronize do
|
61
73
|
return if method_defined?(method)
|
62
74
|
|
63
|
-
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) &&
|
64
|
-
definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
|
75
|
+
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !::ActiveSupport::Delegation::RESERVED_METHOD_NAMES.include?(method.to_s)
|
65
76
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
66
|
-
def #{method}(
|
67
|
-
scoping { klass.#{method}(
|
77
|
+
def #{method}(...)
|
78
|
+
scoping { klass.#{method}(...) }
|
68
79
|
end
|
69
80
|
RUBY
|
70
81
|
else
|
71
|
-
define_method(method) do |*args, &block|
|
72
|
-
scoping { klass.public_send(method, *args, &block) }
|
82
|
+
define_method(method) do |*args, **kwargs, &block|
|
83
|
+
scoping { klass.public_send(method, *args, **kwargs, &block) }
|
73
84
|
end
|
74
|
-
ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
|
75
85
|
end
|
76
86
|
end
|
77
87
|
end
|
@@ -85,12 +95,12 @@ module ActiveRecord
|
|
85
95
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
86
96
|
# for each different klass, and the delegations are compiled into that subclass only.
|
87
97
|
|
88
|
-
delegate :to_xml, :encode_with, :length, :each, :join,
|
98
|
+
delegate :to_xml, :encode_with, :length, :each, :join, :intersect?,
|
89
99
|
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
90
|
-
:to_sentence, :to_formatted_s, :as_json,
|
100
|
+
:to_sentence, :to_fs, :to_formatted_s, :as_json,
|
91
101
|
:shuffle, :split, :slice, :index, :rindex, to: :records
|
92
102
|
|
93
|
-
delegate :primary_key, :connection, to: :klass
|
103
|
+
delegate :primary_key, :lease_connection, :connection, :with_connection, :transaction, to: :klass
|
94
104
|
|
95
105
|
module ClassSpecificRelation # :nodoc:
|
96
106
|
extend ActiveSupport::Concern
|
@@ -102,15 +112,16 @@ module ActiveRecord
|
|
102
112
|
end
|
103
113
|
|
104
114
|
private
|
105
|
-
def method_missing(method,
|
115
|
+
def method_missing(method, ...)
|
106
116
|
if @klass.respond_to?(method)
|
107
|
-
|
108
|
-
|
117
|
+
unless Delegation.uncacheable_methods.include?(method)
|
118
|
+
@klass.generate_relation_method(method)
|
119
|
+
end
|
120
|
+
scoping { @klass.public_send(method, ...) }
|
109
121
|
else
|
110
122
|
super
|
111
123
|
end
|
112
124
|
end
|
113
|
-
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
114
125
|
end
|
115
126
|
|
116
127
|
module ClassMethods # :nodoc:
|
@@ -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
|
#
|
@@ -114,8 +171,6 @@ module ActiveRecord
|
|
114
171
|
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
|
115
172
|
#
|
116
173
|
def first(limit = nil)
|
117
|
-
check_reorder_deprecation unless loaded?
|
118
|
-
|
119
174
|
if limit
|
120
175
|
find_nth_with_limit(0, limit)
|
121
176
|
else
|
@@ -300,6 +355,8 @@ module ActiveRecord
|
|
300
355
|
# Person.exists?
|
301
356
|
# Person.where(name: 'Spartacus', rating: 4).exists?
|
302
357
|
def exists?(conditions = :none)
|
358
|
+
return false if @none
|
359
|
+
|
303
360
|
if Base === conditions
|
304
361
|
raise ArgumentError, <<-MSG.squish
|
305
362
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
@@ -317,7 +374,11 @@ module ActiveRecord
|
|
317
374
|
relation = construct_relation_for_exists(conditions)
|
318
375
|
return false if relation.where_clause.contradiction?
|
319
376
|
|
320
|
-
skip_query_cache_if_necessary
|
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
|
321
382
|
end
|
322
383
|
|
323
384
|
# Returns true if the relation contains the given record or false otherwise.
|
@@ -326,10 +387,20 @@ module ActiveRecord
|
|
326
387
|
# compared to the records in memory. If the relation is unloaded, an
|
327
388
|
# efficient existence query is performed, as in #exists?.
|
328
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
|
+
|
329
394
|
if loaded? || offset_value || limit_value || having_clause.any?
|
330
395
|
records.include?(record)
|
331
396
|
else
|
332
|
-
|
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
|
402
|
+
|
403
|
+
exists?(id)
|
333
404
|
end
|
334
405
|
end
|
335
406
|
|
@@ -364,17 +435,6 @@ module ActiveRecord
|
|
364
435
|
end
|
365
436
|
|
366
437
|
private
|
367
|
-
def check_reorder_deprecation
|
368
|
-
if !order_values.empty? && order_values.all?(&:blank?)
|
369
|
-
blank_value = order_values.first
|
370
|
-
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
371
|
-
`.reorder(#{blank_value.inspect})` with `.first` / `.first!` no longer
|
372
|
-
takes non-deterministic result in Rails 7.0.
|
373
|
-
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
374
|
-
MSG
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
438
|
def construct_relation_for_exists(conditions)
|
379
439
|
conditions = sanitize_forbidden_attributes(conditions)
|
380
440
|
|
@@ -400,7 +460,7 @@ module ActiveRecord
|
|
400
460
|
)
|
401
461
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
402
462
|
|
403
|
-
if eager_loading && !(
|
463
|
+
if eager_loading && has_limit_or_offset? && !(
|
404
464
|
using_limitable_reflections?(join_dependency.reflections) &&
|
405
465
|
using_limitable_reflections?(
|
406
466
|
construct_join_dependency(
|
@@ -409,12 +469,12 @@ module ActiveRecord
|
|
409
469
|
), nil
|
410
470
|
).reflections
|
411
471
|
)
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
472
|
+
)
|
473
|
+
relation = skip_query_cache_if_necessary do
|
474
|
+
klass.with_connection do |c|
|
475
|
+
c.distinct_relation_for_primary_key(relation)
|
476
|
+
end
|
416
477
|
end
|
417
|
-
relation.limit_value = relation.offset_value = nil
|
418
478
|
end
|
419
479
|
|
420
480
|
if block_given?
|
@@ -424,18 +484,6 @@ module ActiveRecord
|
|
424
484
|
end
|
425
485
|
end
|
426
486
|
|
427
|
-
def limited_ids_for(relation)
|
428
|
-
values = @klass.connection.columns_for_distinct(
|
429
|
-
connection.visitor.compile(table[primary_key]),
|
430
|
-
relation.order_values
|
431
|
-
)
|
432
|
-
|
433
|
-
relation = relation.except(:select).select(values).distinct!
|
434
|
-
|
435
|
-
id_rows = skip_query_cache_if_necessary { @klass.connection.select_rows(relation.arel, "SQL") }
|
436
|
-
id_rows.map(&:last)
|
437
|
-
end
|
438
|
-
|
439
487
|
def using_limitable_reflections?(reflections)
|
440
488
|
reflections.none?(&:collection?)
|
441
489
|
end
|
@@ -443,10 +491,17 @@ module ActiveRecord
|
|
443
491
|
def find_with_ids(*ids)
|
444
492
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
445
493
|
|
446
|
-
expects_array =
|
494
|
+
expects_array = if klass.composite_primary_key?
|
495
|
+
ids.first.first.is_a?(Array)
|
496
|
+
else
|
497
|
+
ids.first.is_a?(Array)
|
498
|
+
end
|
499
|
+
|
447
500
|
return [] if expects_array && ids.first.empty?
|
448
501
|
|
449
|
-
ids = ids.
|
502
|
+
ids = ids.first if expects_array
|
503
|
+
|
504
|
+
ids = ids.compact.uniq
|
450
505
|
|
451
506
|
model_name = @klass.name
|
452
507
|
|
@@ -470,7 +525,12 @@ module ActiveRecord
|
|
470
525
|
MSG
|
471
526
|
end
|
472
527
|
|
473
|
-
relation =
|
528
|
+
relation = if klass.composite_primary_key?
|
529
|
+
where(primary_key.zip(id).to_h)
|
530
|
+
else
|
531
|
+
where(primary_key => id)
|
532
|
+
end
|
533
|
+
|
474
534
|
record = relation.take
|
475
535
|
|
476
536
|
raise_record_not_found_exception!(id, 0, 1) unless record
|
@@ -481,7 +541,9 @@ module ActiveRecord
|
|
481
541
|
def find_some(ids)
|
482
542
|
return find_some_ordered(ids) unless order_values.present?
|
483
543
|
|
484
|
-
|
544
|
+
relation = where(primary_key => ids)
|
545
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
546
|
+
result = relation.to_a
|
485
547
|
|
486
548
|
expected_size =
|
487
549
|
if limit_value && ids.size > limit_value
|
@@ -505,13 +567,13 @@ module ActiveRecord
|
|
505
567
|
def find_some_ordered(ids)
|
506
568
|
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
507
569
|
|
508
|
-
|
570
|
+
relation = except(:limit, :offset)
|
571
|
+
relation = relation.where(primary_key => ids)
|
572
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
573
|
+
result = relation.records
|
509
574
|
|
510
575
|
if result.size == ids.size
|
511
|
-
|
512
|
-
|
513
|
-
records_by_id = result.index_by(&:id)
|
514
|
-
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
576
|
+
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
|
515
577
|
else
|
516
578
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
517
579
|
end
|
@@ -563,10 +625,10 @@ module ActiveRecord
|
|
563
625
|
else
|
564
626
|
relation = ordered_relation
|
565
627
|
|
566
|
-
if
|
628
|
+
if relation.order_values.empty? || relation.has_limit_or_offset?
|
567
629
|
relation.records[-index]
|
568
630
|
else
|
569
|
-
relation.
|
631
|
+
relation.reverse_order.offset(index - 1).first
|
570
632
|
end
|
571
633
|
end
|
572
634
|
end
|
@@ -576,15 +638,24 @@ module ActiveRecord
|
|
576
638
|
end
|
577
639
|
|
578
640
|
def ordered_relation
|
579
|
-
if order_values.empty? && (implicit_order_column || primary_key)
|
580
|
-
|
581
|
-
order(table[implicit_order_column].asc, table[primary_key].asc)
|
582
|
-
else
|
583
|
-
order(table[implicit_order_column || primary_key].asc)
|
584
|
-
end
|
641
|
+
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
642
|
+
order(_order_columns.map { |column| table[column].asc })
|
585
643
|
else
|
586
644
|
self
|
587
645
|
end
|
588
646
|
end
|
647
|
+
|
648
|
+
def _order_columns
|
649
|
+
oc = []
|
650
|
+
|
651
|
+
oc << implicit_order_column if implicit_order_column
|
652
|
+
oc << query_constraints_list if query_constraints_list
|
653
|
+
|
654
|
+
if primary_key && query_constraints_list.nil?
|
655
|
+
oc << primary_key
|
656
|
+
end
|
657
|
+
|
658
|
+
oc.flatten.uniq.compact
|
659
|
+
end
|
589
660
|
end
|
590
661
|
end
|
@@ -7,16 +7,15 @@ module ActiveRecord
|
|
7
7
|
class HashMerger # :nodoc:
|
8
8
|
attr_reader :relation, :hash
|
9
9
|
|
10
|
-
def initialize(relation, hash
|
10
|
+
def initialize(relation, hash)
|
11
11
|
hash.assert_valid_keys(*Relation::VALUE_METHODS)
|
12
12
|
|
13
13
|
@relation = relation
|
14
14
|
@hash = hash
|
15
|
-
@rewhere = rewhere
|
16
15
|
end
|
17
16
|
|
18
17
|
def merge
|
19
|
-
Merger.new(relation, other
|
18
|
+
Merger.new(relation, other).merge
|
20
19
|
end
|
21
20
|
|
22
21
|
# Applying values to a relation has some side effects. E.g.
|
@@ -44,37 +43,33 @@ module ActiveRecord
|
|
44
43
|
class Merger # :nodoc:
|
45
44
|
attr_reader :relation, :values, :other
|
46
45
|
|
47
|
-
def initialize(relation, other
|
46
|
+
def initialize(relation, other)
|
48
47
|
@relation = relation
|
49
48
|
@values = other.values
|
50
49
|
@other = other
|
51
|
-
@rewhere = rewhere
|
52
50
|
end
|
53
51
|
|
54
|
-
NORMAL_VALUES = Relation::VALUE_METHODS -
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
NORMAL_VALUES
|
60
|
-
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
|
+
]
|
61
57
|
|
62
58
|
def merge
|
63
|
-
|
59
|
+
NORMAL_VALUES.each do |name|
|
64
60
|
value = values[name]
|
65
61
|
# The unless clause is here mostly for performance reasons (since the `send` call might be moderately
|
66
62
|
# expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
|
67
63
|
# `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
|
68
64
|
# don't fall through the cracks.
|
69
65
|
unless value.nil? || (value.blank? && false != value)
|
70
|
-
|
71
|
-
relation._select!(*value)
|
72
|
-
else
|
73
|
-
relation.public_send("#{name}!", *value)
|
74
|
-
end
|
66
|
+
relation.public_send(:"#{name}!", *value)
|
75
67
|
end
|
76
68
|
end
|
77
69
|
|
70
|
+
relation.none! if other.null_relation?
|
71
|
+
|
72
|
+
merge_select_values
|
78
73
|
merge_multi_values
|
79
74
|
merge_single_values
|
80
75
|
merge_clauses
|
@@ -86,6 +81,18 @@ module ActiveRecord
|
|
86
81
|
end
|
87
82
|
|
88
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
|
95
|
+
|
89
96
|
def merge_preloads
|
90
97
|
return if other.preload_values.empty? && other.includes_values.empty?
|
91
98
|
|
@@ -169,7 +176,7 @@ module ActiveRecord
|
|
169
176
|
def merge_clauses
|
170
177
|
relation.from_clause = other.from_clause if replace_from_clause?
|
171
178
|
|
172
|
-
where_clause = relation.where_clause.merge(other.where_clause
|
179
|
+
where_clause = relation.where_clause.merge(other.where_clause)
|
173
180
|
relation.where_clause = where_clause unless where_clause.empty?
|
174
181
|
|
175
182
|
having_clause = relation.having_clause.merge(other.having_clause)
|
@@ -13,7 +13,7 @@ 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 =
|
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
23
23
|
else Arel::Nodes::HomogeneousIn.new(values, attribute, :in)
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
if nils
|
27
27
|
values_predicate = values_predicate.or(attribute.eq(nil))
|
28
28
|
end
|
29
29
|
|
@@ -9,7 +9,14 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def queries
|
12
|
-
|
12
|
+
if associated_table.join_foreign_key.is_a?(Array)
|
13
|
+
id_list = ids
|
14
|
+
id_list = id_list.pluck(primary_key) if id_list.is_a?(Relation)
|
15
|
+
|
16
|
+
id_list.map { |ids_set| associated_table.join_foreign_key.zip(ids_set).to_h }
|
17
|
+
else
|
18
|
+
[ associated_table.join_foreign_key => ids ]
|
19
|
+
end
|
13
20
|
end
|
14
21
|
|
15
22
|
private
|
@@ -18,11 +25,14 @@ module ActiveRecord
|
|
18
25
|
def ids
|
19
26
|
case value
|
20
27
|
when Relation
|
21
|
-
|
28
|
+
relation = value
|
29
|
+
relation = relation.select(primary_key) if select_clause?
|
30
|
+
relation = relation.where(primary_type => polymorphic_name) if polymorphic_clause?
|
31
|
+
relation
|
22
32
|
when Array
|
23
33
|
value.map { |v| convert_to_id(v) }
|
24
34
|
else
|
25
|
-
convert_to_id(value)
|
35
|
+
[convert_to_id(value)]
|
26
36
|
end
|
27
37
|
end
|
28
38
|
|
@@ -30,8 +40,32 @@ module ActiveRecord
|
|
30
40
|
associated_table.join_primary_key
|
31
41
|
end
|
32
42
|
|
43
|
+
def primary_type
|
44
|
+
associated_table.join_primary_type
|
45
|
+
end
|
46
|
+
|
47
|
+
def polymorphic_name
|
48
|
+
associated_table.polymorphic_name_association
|
49
|
+
end
|
50
|
+
|
51
|
+
def select_clause?
|
52
|
+
value.select_values.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def polymorphic_clause?
|
56
|
+
primary_type && !value.where_values_hash.has_key?(primary_type)
|
57
|
+
end
|
58
|
+
|
33
59
|
def convert_to_id(value)
|
34
|
-
if
|
60
|
+
if primary_key.is_a?(Array)
|
61
|
+
primary_key.map do |attribute|
|
62
|
+
if attribute == "id"
|
63
|
+
value.id_value
|
64
|
+
else
|
65
|
+
value.public_send(attribute)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
elsif value.respond_to?(primary_key)
|
35
69
|
value.public_send(primary_key)
|
36
70
|
else
|
37
71
|
value
|
@@ -34,19 +34,22 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def klass(value)
|
37
|
-
|
38
|
-
when Base
|
37
|
+
if value.is_a?(Base)
|
39
38
|
value.class
|
40
|
-
|
39
|
+
elsif value.is_a?(Relation)
|
41
40
|
value.klass
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
44
|
def convert_to_id(value)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
if value.is_a?(Base)
|
46
|
+
primary_key = primary_key(value)
|
47
|
+
if primary_key.is_a?(Array)
|
48
|
+
primary_key.map { |column| value._read_attribute(column) }
|
49
|
+
else
|
50
|
+
value._read_attribute(primary_key)
|
51
|
+
end
|
52
|
+
elsif value.is_a?(Relation)
|
50
53
|
value.select(primary_key(value))
|
51
54
|
else
|
52
55
|
value
|
@@ -9,7 +9,11 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
if value.select_values.empty?
|
12
|
-
|
12
|
+
if value.klass.composite_primary_key?
|
13
|
+
raise ArgumentError, "Cannot map composite primary key #{value.klass.primary_key} to #{attribute.name}"
|
14
|
+
else
|
15
|
+
value = value.select(value.table[value.klass.primary_key])
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
attribute.in(value.arel)
|