activerecord 6.1.7 → 7.1.5
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 +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- 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 +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- 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 +367 -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 +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- 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 +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- 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 +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- 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 +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- 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 +89 -52
- 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/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.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- 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 +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- 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 +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -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 +1 -1
- 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 +155 -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 +155 -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_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- 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 +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- 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.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 +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -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 +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- 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 +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- 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 +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- 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 +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- 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 +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- 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 -5
- 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/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- 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 +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- 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/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -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/node.rb +111 -2
- 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 +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- 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.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 +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -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.
|
@@ -104,6 +127,32 @@ module ActiveRecord
|
|
104
127
|
take || raise_record_not_found_exception!
|
105
128
|
end
|
106
129
|
|
130
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
131
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
132
|
+
# record is found.
|
133
|
+
#
|
134
|
+
# Product.where(["price = %?", price]).sole
|
135
|
+
def sole
|
136
|
+
found, undesired = first(2)
|
137
|
+
|
138
|
+
if found.nil?
|
139
|
+
raise_record_not_found_exception!
|
140
|
+
elsif undesired.present?
|
141
|
+
raise ActiveRecord::SoleRecordExceeded.new(self)
|
142
|
+
else
|
143
|
+
found
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
148
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
149
|
+
# record is found.
|
150
|
+
#
|
151
|
+
# Product.find_sole_by(["price = %?", price])
|
152
|
+
def find_sole_by(arg, *args)
|
153
|
+
where(arg, *args).sole
|
154
|
+
end
|
155
|
+
|
107
156
|
# Find the first record (or first N records if a parameter is supplied).
|
108
157
|
# If no order is defined it will order by primary key.
|
109
158
|
#
|
@@ -114,8 +163,6 @@ module ActiveRecord
|
|
114
163
|
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
|
115
164
|
#
|
116
165
|
def first(limit = nil)
|
117
|
-
check_reorder_deprecation unless loaded?
|
118
|
-
|
119
166
|
if limit
|
120
167
|
find_nth_with_limit(0, limit)
|
121
168
|
else
|
@@ -300,6 +347,8 @@ module ActiveRecord
|
|
300
347
|
# Person.exists?
|
301
348
|
# Person.where(name: 'Spartacus', rating: 4).exists?
|
302
349
|
def exists?(conditions = :none)
|
350
|
+
return false if @none
|
351
|
+
|
303
352
|
if Base === conditions
|
304
353
|
raise ArgumentError, <<-MSG.squish
|
305
354
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
@@ -326,10 +375,20 @@ module ActiveRecord
|
|
326
375
|
# compared to the records in memory. If the relation is unloaded, an
|
327
376
|
# efficient existence query is performed, as in #exists?.
|
328
377
|
def include?(record)
|
378
|
+
# The existing implementation relies on receiving an Active Record instance as the input parameter named record.
|
379
|
+
# Any non-Active Record object passed to this implementation is guaranteed to return `false`.
|
380
|
+
return false unless record.is_a?(klass)
|
381
|
+
|
329
382
|
if loaded? || offset_value || limit_value || having_clause.any?
|
330
383
|
records.include?(record)
|
331
384
|
else
|
332
|
-
|
385
|
+
id = if record.class.composite_primary_key?
|
386
|
+
record.class.primary_key.zip(record.id).to_h
|
387
|
+
else
|
388
|
+
record.id
|
389
|
+
end
|
390
|
+
|
391
|
+
exists?(id)
|
333
392
|
end
|
334
393
|
end
|
335
394
|
|
@@ -364,17 +423,6 @@ module ActiveRecord
|
|
364
423
|
end
|
365
424
|
|
366
425
|
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
426
|
def construct_relation_for_exists(conditions)
|
379
427
|
conditions = sanitize_forbidden_attributes(conditions)
|
380
428
|
|
@@ -400,7 +448,7 @@ module ActiveRecord
|
|
400
448
|
)
|
401
449
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
402
450
|
|
403
|
-
if eager_loading && !(
|
451
|
+
if eager_loading && has_limit_or_offset? && !(
|
404
452
|
using_limitable_reflections?(join_dependency.reflections) &&
|
405
453
|
using_limitable_reflections?(
|
406
454
|
construct_join_dependency(
|
@@ -409,12 +457,10 @@ module ActiveRecord
|
|
409
457
|
), nil
|
410
458
|
).reflections
|
411
459
|
)
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
460
|
+
)
|
461
|
+
relation = skip_query_cache_if_necessary do
|
462
|
+
klass.connection.distinct_relation_for_primary_key(relation)
|
416
463
|
end
|
417
|
-
relation.limit_value = relation.offset_value = nil
|
418
464
|
end
|
419
465
|
|
420
466
|
if block_given?
|
@@ -424,18 +470,6 @@ module ActiveRecord
|
|
424
470
|
end
|
425
471
|
end
|
426
472
|
|
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
473
|
def using_limitable_reflections?(reflections)
|
440
474
|
reflections.none?(&:collection?)
|
441
475
|
end
|
@@ -443,10 +477,17 @@ module ActiveRecord
|
|
443
477
|
def find_with_ids(*ids)
|
444
478
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
445
479
|
|
446
|
-
expects_array =
|
480
|
+
expects_array = if klass.composite_primary_key?
|
481
|
+
ids.first.first.is_a?(Array)
|
482
|
+
else
|
483
|
+
ids.first.is_a?(Array)
|
484
|
+
end
|
485
|
+
|
447
486
|
return [] if expects_array && ids.first.empty?
|
448
487
|
|
449
|
-
ids = ids.
|
488
|
+
ids = ids.first if expects_array
|
489
|
+
|
490
|
+
ids = ids.compact.uniq
|
450
491
|
|
451
492
|
model_name = @klass.name
|
452
493
|
|
@@ -470,7 +511,12 @@ module ActiveRecord
|
|
470
511
|
MSG
|
471
512
|
end
|
472
513
|
|
473
|
-
relation =
|
514
|
+
relation = if klass.composite_primary_key?
|
515
|
+
where(primary_key.zip(id).to_h)
|
516
|
+
else
|
517
|
+
where(primary_key => id)
|
518
|
+
end
|
519
|
+
|
474
520
|
record = relation.take
|
475
521
|
|
476
522
|
raise_record_not_found_exception!(id, 0, 1) unless record
|
@@ -481,7 +527,9 @@ module ActiveRecord
|
|
481
527
|
def find_some(ids)
|
482
528
|
return find_some_ordered(ids) unless order_values.present?
|
483
529
|
|
484
|
-
|
530
|
+
relation = where(primary_key => ids)
|
531
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
532
|
+
result = relation.to_a
|
485
533
|
|
486
534
|
expected_size =
|
487
535
|
if limit_value && ids.size > limit_value
|
@@ -505,13 +553,13 @@ module ActiveRecord
|
|
505
553
|
def find_some_ordered(ids)
|
506
554
|
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
507
555
|
|
508
|
-
|
556
|
+
relation = except(:limit, :offset)
|
557
|
+
relation = relation.where(primary_key => ids)
|
558
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
559
|
+
result = relation.records
|
509
560
|
|
510
561
|
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)) }
|
562
|
+
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
|
515
563
|
else
|
516
564
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
517
565
|
end
|
@@ -563,10 +611,10 @@ module ActiveRecord
|
|
563
611
|
else
|
564
612
|
relation = ordered_relation
|
565
613
|
|
566
|
-
if
|
614
|
+
if relation.order_values.empty? || relation.has_limit_or_offset?
|
567
615
|
relation.records[-index]
|
568
616
|
else
|
569
|
-
relation.
|
617
|
+
relation.reverse_order.offset(index - 1).first
|
570
618
|
end
|
571
619
|
end
|
572
620
|
end
|
@@ -576,15 +624,24 @@ module ActiveRecord
|
|
576
624
|
end
|
577
625
|
|
578
626
|
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
|
627
|
+
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
628
|
+
order(_order_columns.map { |column| table[column].asc })
|
585
629
|
else
|
586
630
|
self
|
587
631
|
end
|
588
632
|
end
|
633
|
+
|
634
|
+
def _order_columns
|
635
|
+
oc = []
|
636
|
+
|
637
|
+
oc << implicit_order_column if implicit_order_column
|
638
|
+
oc << query_constraints_list if query_constraints_list
|
639
|
+
|
640
|
+
if primary_key && query_constraints_list.nil?
|
641
|
+
oc << primary_key
|
642
|
+
end
|
643
|
+
|
644
|
+
oc.flatten.uniq.compact
|
645
|
+
end
|
589
646
|
end
|
590
647
|
end
|
@@ -51,30 +51,27 @@ module ActiveRecord
|
|
51
51
|
@rewhere = rewhere
|
52
52
|
end
|
53
53
|
|
54
|
-
NORMAL_VALUES = Relation::VALUE_METHODS -
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
NORMAL_VALUES
|
60
|
-
end
|
54
|
+
NORMAL_VALUES = Relation::VALUE_METHODS - Relation::CLAUSE_METHODS -
|
55
|
+
[
|
56
|
+
:select, :includes, :preload, :joins, :left_outer_joins,
|
57
|
+
:order, :reverse_order, :lock, :create_with, :reordering
|
58
|
+
]
|
61
59
|
|
62
60
|
def merge
|
63
|
-
|
61
|
+
NORMAL_VALUES.each do |name|
|
64
62
|
value = values[name]
|
65
63
|
# The unless clause is here mostly for performance reasons (since the `send` call might be moderately
|
66
64
|
# expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
|
67
65
|
# `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
|
68
66
|
# don't fall through the cracks.
|
69
67
|
unless value.nil? || (value.blank? && false != value)
|
70
|
-
|
71
|
-
relation._select!(*value)
|
72
|
-
else
|
73
|
-
relation.public_send("#{name}!", *value)
|
74
|
-
end
|
68
|
+
relation.public_send(:"#{name}!", *value)
|
75
69
|
end
|
76
70
|
end
|
77
71
|
|
72
|
+
relation.none! if other.null_relation?
|
73
|
+
|
74
|
+
merge_select_values
|
78
75
|
merge_multi_values
|
79
76
|
merge_single_values
|
80
77
|
merge_clauses
|
@@ -86,6 +83,18 @@ module ActiveRecord
|
|
86
83
|
end
|
87
84
|
|
88
85
|
private
|
86
|
+
def merge_select_values
|
87
|
+
return if other.select_values.empty?
|
88
|
+
|
89
|
+
if other.klass == relation.klass
|
90
|
+
relation.select_values |= other.select_values
|
91
|
+
else
|
92
|
+
relation.select_values |= other.instance_eval do
|
93
|
+
arel_columns(select_values)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
89
98
|
def merge_preloads
|
90
99
|
return if other.preload_values.empty? && other.includes_values.empty?
|
91
100
|
|
@@ -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,7 +40,25 @@ 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)
|
60
|
+
return primary_key.map { |pk| value.public_send(pk) } if primary_key.is_a?(Array)
|
61
|
+
|
34
62
|
if value.respond_to?(primary_key)
|
35
63
|
value.public_send(primary_key)
|
36
64
|
else
|
@@ -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)
|
@@ -9,10 +9,6 @@ module ActiveRecord
|
|
9
9
|
require "active_record/relation/predicate_builder/association_query_value"
|
10
10
|
require "active_record/relation/predicate_builder/polymorphic_array_value"
|
11
11
|
|
12
|
-
# No-op BaseHandler to work Mashal.load(File.read("legacy_relation.dump")).
|
13
|
-
# TODO: Remove the constant alias once Rails 6.1 has released.
|
14
|
-
BaseHandler = BasicObjectHandler
|
15
|
-
|
16
12
|
def initialize(table)
|
17
13
|
@table = table
|
18
14
|
@handlers = []
|
@@ -33,8 +29,8 @@ module ActiveRecord
|
|
33
29
|
attributes.each_with_object([]) do |(key, value), result|
|
34
30
|
if value.is_a?(Hash)
|
35
31
|
result << Arel.sql(key)
|
36
|
-
elsif key.
|
37
|
-
result << Arel.sql(key
|
32
|
+
elsif (idx = key.rindex("."))
|
33
|
+
result << Arel.sql(key[0, idx])
|
38
34
|
end
|
39
35
|
end
|
40
36
|
end
|
@@ -69,8 +65,7 @@ module ActiveRecord
|
|
69
65
|
end
|
70
66
|
|
71
67
|
def build_bind_attribute(column_name, value)
|
72
|
-
|
73
|
-
Arel::Nodes::BindParam.new(attr)
|
68
|
+
Relation::QueryAttribute.new(column_name, value, table.type(column_name))
|
74
69
|
end
|
75
70
|
|
76
71
|
def resolve_arel_attribute(table_name, column_name, &block)
|
@@ -82,7 +77,13 @@ module ActiveRecord
|
|
82
77
|
return ["1=0"] if attributes.empty?
|
83
78
|
|
84
79
|
attributes.flat_map do |key, value|
|
85
|
-
if
|
80
|
+
if key.is_a?(Array)
|
81
|
+
queries = Array(value).map do |ids_set|
|
82
|
+
raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
|
83
|
+
expand_from_hash(key.zip(ids_set).to_h)
|
84
|
+
end
|
85
|
+
grouping_queries(queries)
|
86
|
+
elsif value.is_a?(Hash) && !table.has_column?(key)
|
86
87
|
table.associated_table(key, &block)
|
87
88
|
.predicate_builder.expand_from_hash(value.stringify_keys)
|
88
89
|
elsif table.associated_with?(key)
|
@@ -147,19 +148,25 @@ module ActiveRecord
|
|
147
148
|
end
|
148
149
|
|
149
150
|
def convert_dot_notation_to_hash(attributes)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
attributes.each_with_object({}) do |(key, value), converted|
|
152
|
+
if value.is_a?(Hash)
|
153
|
+
if (existing = converted[key])
|
154
|
+
existing.merge!(value)
|
155
|
+
else
|
156
|
+
converted[key] = value.dup
|
157
|
+
end
|
158
|
+
elsif (idx = key.rindex("."))
|
159
|
+
table_name, column_name = key[0, idx], key[idx + 1, key.length]
|
158
160
|
|
159
|
-
|
161
|
+
if (existing = converted[table_name])
|
162
|
+
existing[column_name] = value
|
163
|
+
else
|
164
|
+
converted[table_name] = { column_name => value }
|
165
|
+
end
|
166
|
+
else
|
167
|
+
converted[key] = value
|
168
|
+
end
|
160
169
|
end
|
161
|
-
|
162
|
-
attributes
|
163
170
|
end
|
164
171
|
|
165
172
|
def handler_for(object)
|
@@ -5,12 +5,27 @@ require "active_model/attribute"
|
|
5
5
|
module ActiveRecord
|
6
6
|
class Relation
|
7
7
|
class QueryAttribute < ActiveModel::Attribute # :nodoc:
|
8
|
+
def initialize(...)
|
9
|
+
super
|
10
|
+
|
11
|
+
# The query attribute value may be mutated before we actually "compile" the query.
|
12
|
+
# To avoid that if the type uses a serializer we eagerly compute the value for database
|
13
|
+
if value_before_type_cast.is_a?(StatementCache::Substitute)
|
14
|
+
# we don't need to serialize StatementCache::Substitute
|
15
|
+
elsif @type.serialized?
|
16
|
+
value_for_database
|
17
|
+
elsif @type.mutable? # If the type is simply mutable, we deep_dup it.
|
18
|
+
@value_before_type_cast = @value_before_type_cast.deep_dup
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
8
22
|
def type_cast(value)
|
9
23
|
value
|
10
24
|
end
|
11
25
|
|
12
26
|
def value_for_database
|
13
|
-
@value_for_database
|
27
|
+
@value_for_database = _value_for_database unless defined?(@value_for_database)
|
28
|
+
@value_for_database
|
14
29
|
end
|
15
30
|
|
16
31
|
def with_cast_value(value)
|
@@ -20,25 +35,28 @@ module ActiveRecord
|
|
20
35
|
def nil?
|
21
36
|
unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
22
37
|
value_before_type_cast.nil? ||
|
23
|
-
type.respond_to?(:subtype
|
38
|
+
type.respond_to?(:subtype) && serializable? && value_for_database.nil?
|
24
39
|
end
|
25
|
-
rescue ::RangeError
|
26
40
|
end
|
27
41
|
|
28
42
|
def infinite?
|
29
|
-
infinity?(value_before_type_cast) || infinity?(value_for_database)
|
30
|
-
rescue ::RangeError
|
43
|
+
infinity?(value_before_type_cast) || serializable? && infinity?(value_for_database)
|
31
44
|
end
|
32
45
|
|
33
46
|
def unboundable?
|
34
|
-
|
35
|
-
@_unboundable
|
36
|
-
else
|
37
|
-
value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
38
|
-
@_unboundable = nil
|
47
|
+
unless defined?(@_unboundable)
|
48
|
+
serializable? { |value| @_unboundable = value <=> 0 } && @_unboundable = nil
|
39
49
|
end
|
40
|
-
|
41
|
-
|
50
|
+
@_unboundable
|
51
|
+
end
|
52
|
+
|
53
|
+
def ==(other)
|
54
|
+
super && value_for_database == other.value_for_database
|
55
|
+
end
|
56
|
+
alias eql? ==
|
57
|
+
|
58
|
+
def hash
|
59
|
+
[self.class, name, value_for_database, type].hash
|
42
60
|
end
|
43
61
|
|
44
62
|
private
|