activerecord 7.0.8.7 → 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 +781 -1777
- data/MIT-LICENSE +1 -1
- data/README.rdoc +30 -30
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +40 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +35 -21
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- 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 +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -3
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +153 -33
- data/lib/active_record/attributes.rb +96 -71
- data/lib/active_record/autosave_association.rb +81 -39
- data/lib/active_record/base.rb +11 -7
- data/lib/active_record/callbacks.rb +11 -25
- 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 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +343 -91
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +229 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +142 -12
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +539 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +289 -128
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +60 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +108 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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 +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +371 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +374 -203
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -45
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +51 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +298 -113
- 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 +124 -1
- data/lib/active_record/connection_handling.rb +101 -105
- data/lib/active_record/core.rb +273 -178
- data/lib/active_record/counter_cache.rb +69 -35
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +56 -27
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +46 -22
- data/lib/active_record/encryption/encrypted_attribute_type.rb +48 -13
- data/lib/active_record/encryption/encryptor.rb +35 -19
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +130 -28
- data/lib/active_record/errors.rb +154 -34
- data/lib/active_record/explain.rb +21 -12
- 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 +48 -10
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- 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 +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +236 -118
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +96 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +35 -10
- data/lib/active_record/railtie.rb +131 -87
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +147 -155
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +270 -108
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +97 -21
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -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 +28 -16
- data/lib/active_record/relation/query_attribute.rb +3 -2
- data/lib/active_record/relation/query_methods.rb +585 -109
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +15 -21
- data/lib/active_record/relation.rb +592 -92
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +90 -23
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +33 -11
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +23 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- 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 +108 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- 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 +9 -3
- 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 +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +3 -1
- 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 +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- 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 +4 -2
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +114 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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
- metadata +56 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
|
@@ -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)
|
|
@@ -324,6 +355,8 @@ module ActiveRecord
|
|
|
324
355
|
# Person.exists?
|
|
325
356
|
# Person.where(name: 'Spartacus', rating: 4).exists?
|
|
326
357
|
def exists?(conditions = :none)
|
|
358
|
+
return false if @none
|
|
359
|
+
|
|
327
360
|
if Base === conditions
|
|
328
361
|
raise ArgumentError, <<-MSG.squish
|
|
329
362
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
|
@@ -341,7 +374,11 @@ module ActiveRecord
|
|
|
341
374
|
relation = construct_relation_for_exists(conditions)
|
|
342
375
|
return false if relation.where_clause.contradiction?
|
|
343
376
|
|
|
344
|
-
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
|
|
345
382
|
end
|
|
346
383
|
|
|
347
384
|
# Returns true if the relation contains the given record or false otherwise.
|
|
@@ -350,10 +387,20 @@ module ActiveRecord
|
|
|
350
387
|
# compared to the records in memory. If the relation is unloaded, an
|
|
351
388
|
# efficient existence query is performed, as in #exists?.
|
|
352
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
|
+
|
|
353
394
|
if loaded? || offset_value || limit_value || having_clause.any?
|
|
354
395
|
records.include?(record)
|
|
355
396
|
else
|
|
356
|
-
|
|
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)
|
|
357
404
|
end
|
|
358
405
|
end
|
|
359
406
|
|
|
@@ -377,12 +424,13 @@ module ActiveRecord
|
|
|
377
424
|
error << " with#{conditions}" if conditions
|
|
378
425
|
raise RecordNotFound.new(error, name, key)
|
|
379
426
|
elsif Array.wrap(ids).size == 1
|
|
380
|
-
|
|
427
|
+
id = Array.wrap(ids)[0]
|
|
428
|
+
error = "Couldn't find #{name} with '#{key}'=#{id.inspect}#{conditions}"
|
|
381
429
|
raise RecordNotFound.new(error, name, key, ids)
|
|
382
430
|
else
|
|
383
431
|
error = +"Couldn't find all #{name.pluralize} with '#{key}': "
|
|
384
|
-
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
|
385
|
-
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
|
|
386
434
|
raise RecordNotFound.new(error, name, key, ids)
|
|
387
435
|
end
|
|
388
436
|
end
|
|
@@ -424,7 +472,9 @@ module ActiveRecord
|
|
|
424
472
|
)
|
|
425
473
|
)
|
|
426
474
|
relation = skip_query_cache_if_necessary do
|
|
427
|
-
klass.
|
|
475
|
+
klass.with_connection do |c|
|
|
476
|
+
c.distinct_relation_for_primary_key(relation)
|
|
477
|
+
end
|
|
428
478
|
end
|
|
429
479
|
end
|
|
430
480
|
|
|
@@ -442,10 +492,17 @@ module ActiveRecord
|
|
|
442
492
|
def find_with_ids(*ids)
|
|
443
493
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
|
444
494
|
|
|
445
|
-
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
|
+
|
|
446
501
|
return [] if expects_array && ids.first.empty?
|
|
447
502
|
|
|
448
|
-
ids = ids.
|
|
503
|
+
ids = ids.first if expects_array
|
|
504
|
+
|
|
505
|
+
ids = ids.compact.uniq
|
|
449
506
|
|
|
450
507
|
model_name = @klass.name
|
|
451
508
|
|
|
@@ -469,7 +526,12 @@ module ActiveRecord
|
|
|
469
526
|
MSG
|
|
470
527
|
end
|
|
471
528
|
|
|
472
|
-
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
|
+
|
|
473
535
|
record = relation.take
|
|
474
536
|
|
|
475
537
|
raise_record_not_found_exception!(id, 0, 1) unless record
|
|
@@ -480,7 +542,9 @@ module ActiveRecord
|
|
|
480
542
|
def find_some(ids)
|
|
481
543
|
return find_some_ordered(ids) unless order_values.present?
|
|
482
544
|
|
|
483
|
-
|
|
545
|
+
relation = where(primary_key => ids)
|
|
546
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
|
547
|
+
result = relation.to_a
|
|
484
548
|
|
|
485
549
|
expected_size =
|
|
486
550
|
if limit_value && ids.size > limit_value
|
|
@@ -504,7 +568,10 @@ module ActiveRecord
|
|
|
504
568
|
def find_some_ordered(ids)
|
|
505
569
|
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
|
506
570
|
|
|
507
|
-
|
|
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
|
|
508
575
|
|
|
509
576
|
if result.size == ids.size
|
|
510
577
|
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
|
|
@@ -559,10 +626,10 @@ module ActiveRecord
|
|
|
559
626
|
else
|
|
560
627
|
relation = ordered_relation
|
|
561
628
|
|
|
562
|
-
if
|
|
629
|
+
if relation.order_values.empty? || relation.has_limit_or_offset?
|
|
563
630
|
relation.records[-index]
|
|
564
631
|
else
|
|
565
|
-
relation.
|
|
632
|
+
relation.reverse_order.offset(index - 1).first
|
|
566
633
|
end
|
|
567
634
|
end
|
|
568
635
|
end
|
|
@@ -572,15 +639,24 @@ module ActiveRecord
|
|
|
572
639
|
end
|
|
573
640
|
|
|
574
641
|
def ordered_relation
|
|
575
|
-
if order_values.empty? && (implicit_order_column || primary_key)
|
|
576
|
-
|
|
577
|
-
order(table[implicit_order_column].asc, table[primary_key].asc)
|
|
578
|
-
else
|
|
579
|
-
order(table[implicit_order_column || primary_key].asc)
|
|
580
|
-
end
|
|
642
|
+
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
|
643
|
+
order(_order_columns.map { |column| table[column].asc })
|
|
581
644
|
else
|
|
582
645
|
self
|
|
583
646
|
end
|
|
584
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
|
|
585
661
|
end
|
|
586
662
|
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,11 +43,10 @@ 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
52
|
NORMAL_VALUES = Relation::VALUE_METHODS - Relation::CLAUSE_METHODS -
|
|
@@ -69,6 +67,8 @@ module ActiveRecord
|
|
|
69
67
|
end
|
|
70
68
|
end
|
|
71
69
|
|
|
70
|
+
relation.none! if other.null_relation?
|
|
71
|
+
|
|
72
72
|
merge_select_values
|
|
73
73
|
merge_multi_values
|
|
74
74
|
merge_single_values
|
|
@@ -176,7 +176,7 @@ module ActiveRecord
|
|
|
176
176
|
def merge_clauses
|
|
177
177
|
relation.from_clause = other.from_clause if replace_from_clause?
|
|
178
178
|
|
|
179
|
-
where_clause = relation.where_clause.merge(other.where_clause
|
|
179
|
+
where_clause = relation.where_clause.merge(other.where_clause)
|
|
180
180
|
relation.where_clause = where_clause unless where_clause.empty?
|
|
181
181
|
|
|
182
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
|
|
@@ -25,7 +32,7 @@ module ActiveRecord
|
|
|
25
32
|
when Array
|
|
26
33
|
value.map { |v| convert_to_id(v) }
|
|
27
34
|
else
|
|
28
|
-
convert_to_id(value)
|
|
35
|
+
[convert_to_id(value)]
|
|
29
36
|
end
|
|
30
37
|
end
|
|
31
38
|
|
|
@@ -50,7 +57,17 @@ module ActiveRecord
|
|
|
50
57
|
end
|
|
51
58
|
|
|
52
59
|
def convert_to_id(value)
|
|
53
|
-
if
|
|
60
|
+
if primary_key.is_a?(Array)
|
|
61
|
+
primary_key.map do |attribute|
|
|
62
|
+
next nil if value.nil?
|
|
63
|
+
|
|
64
|
+
if attribute == "id"
|
|
65
|
+
value.id_value
|
|
66
|
+
else
|
|
67
|
+
value.public_send(attribute)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
elsif value.respond_to?(primary_key)
|
|
54
71
|
value.public_send(primary_key)
|
|
55
72
|
else
|
|
56
73
|
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)
|
|
@@ -28,9 +28,9 @@ module ActiveRecord
|
|
|
28
28
|
def self.references(attributes)
|
|
29
29
|
attributes.each_with_object([]) do |(key, value), result|
|
|
30
30
|
if value.is_a?(Hash)
|
|
31
|
-
result << Arel.sql(key)
|
|
32
|
-
elsif key.
|
|
33
|
-
result << Arel.sql(key
|
|
31
|
+
result << Arel.sql(key, retryable: true)
|
|
32
|
+
elsif (idx = key.rindex("."))
|
|
33
|
+
result << Arel.sql(key[0, idx], retryable: true)
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
end
|
|
@@ -77,7 +77,13 @@ module ActiveRecord
|
|
|
77
77
|
return ["1=0"] if attributes.empty?
|
|
78
78
|
|
|
79
79
|
attributes.flat_map do |key, value|
|
|
80
|
-
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)
|
|
81
87
|
table.associated_table(key, &block)
|
|
82
88
|
.predicate_builder.expand_from_hash(value.stringify_keys)
|
|
83
89
|
elsif table.associated_with?(key)
|
|
@@ -136,25 +142,31 @@ module ActiveRecord
|
|
|
136
142
|
queries.first
|
|
137
143
|
else
|
|
138
144
|
queries.map! { |query| query.reduce(&:and) }
|
|
139
|
-
queries =
|
|
145
|
+
queries = Arel::Nodes::Or.new(queries)
|
|
140
146
|
Arel::Nodes::Grouping.new(queries)
|
|
141
147
|
end
|
|
142
148
|
end
|
|
143
149
|
|
|
144
150
|
def convert_dot_notation_to_hash(attributes)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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]
|
|
153
160
|
|
|
154
|
-
|
|
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
|
|
155
169
|
end
|
|
156
|
-
|
|
157
|
-
attributes
|
|
158
170
|
end
|
|
159
171
|
|
|
160
172
|
def handler_for(object)
|
|
@@ -24,7 +24,8 @@ module ActiveRecord
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def value_for_database
|
|
27
|
-
@value_for_database
|
|
27
|
+
@value_for_database = _value_for_database unless defined?(@value_for_database)
|
|
28
|
+
@value_for_database
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def with_cast_value(value)
|
|
@@ -34,7 +35,7 @@ module ActiveRecord
|
|
|
34
35
|
def nil?
|
|
35
36
|
unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
|
36
37
|
value_before_type_cast.nil? ||
|
|
37
|
-
type.respond_to?(:subtype) && serializable? && value_for_database.nil?
|
|
38
|
+
(type.respond_to?(:subtype) || type.respond_to?(:normalizer)) && serializable? && value_for_database.nil?
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
|