activerecord 7.0.4 → 7.1.5.1
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 +1971 -1243
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +20 -4
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +20 -14
- data/lib/active_record/associations/collection_proxy.rb +20 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/preloader/association.rb +31 -7
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +333 -222
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +21 -8
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -4
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -26
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +59 -10
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +16 -32
- 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 +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +80 -50
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +51 -7
- 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 +155 -25
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +297 -127
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +509 -103
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +254 -125
- 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 +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -14
- 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 +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +19 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +106 -55
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -45
- 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/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 +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +41 -8
- 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 +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +365 -61
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +354 -193
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +213 -85
- 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 +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +181 -154
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +28 -14
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +15 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- 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 +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +23 -8
- 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/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +112 -28
- data/lib/active_record/errors.rb +112 -18
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_subscriber.rb +1 -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 +29 -8
- data/lib/active_record/fixtures.rb +135 -71
- data/lib/active_record/future_result.rb +40 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +33 -19
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- 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 +9 -11
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +105 -7
- data/lib/active_record/migration/compatibility.rb +163 -58
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +271 -114
- data/lib/active_record/model_schema.rb +69 -44
- data/lib/active_record/nested_attributes.rb +37 -8
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +195 -42
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +87 -51
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +14 -9
- data/lib/active_record/railties/databases.rake +144 -150
- 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 +189 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +232 -81
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- 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 +26 -14
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +408 -76
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +103 -37
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +24 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +50 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -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 +7 -5
- data/lib/active_record/store.rb +9 -9
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +152 -108
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +114 -96
- data/lib/active_record/timestamp.rb +30 -16
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- 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 +8 -4
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- 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 +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +130 -17
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- 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/cte.rb +36 -0
- data/lib/arel/nodes/filter.rb +1 -1
- 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/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +5 -1
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +83 -18
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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 +51 -15
- 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.
|
@@ -324,6 +347,8 @@ module ActiveRecord
|
|
324
347
|
# Person.exists?
|
325
348
|
# Person.where(name: 'Spartacus', rating: 4).exists?
|
326
349
|
def exists?(conditions = :none)
|
350
|
+
return false if @none
|
351
|
+
|
327
352
|
if Base === conditions
|
328
353
|
raise ArgumentError, <<-MSG.squish
|
329
354
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
@@ -350,10 +375,20 @@ module ActiveRecord
|
|
350
375
|
# compared to the records in memory. If the relation is unloaded, an
|
351
376
|
# efficient existence query is performed, as in #exists?.
|
352
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
|
+
|
353
382
|
if loaded? || offset_value || limit_value || having_clause.any?
|
354
383
|
records.include?(record)
|
355
384
|
else
|
356
|
-
|
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)
|
357
392
|
end
|
358
393
|
end
|
359
394
|
|
@@ -442,10 +477,17 @@ module ActiveRecord
|
|
442
477
|
def find_with_ids(*ids)
|
443
478
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
444
479
|
|
445
|
-
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
|
+
|
446
486
|
return [] if expects_array && ids.first.empty?
|
447
487
|
|
448
|
-
ids = ids.
|
488
|
+
ids = ids.first if expects_array
|
489
|
+
|
490
|
+
ids = ids.compact.uniq
|
449
491
|
|
450
492
|
model_name = @klass.name
|
451
493
|
|
@@ -469,7 +511,12 @@ module ActiveRecord
|
|
469
511
|
MSG
|
470
512
|
end
|
471
513
|
|
472
|
-
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
|
+
|
473
520
|
record = relation.take
|
474
521
|
|
475
522
|
raise_record_not_found_exception!(id, 0, 1) unless record
|
@@ -480,7 +527,9 @@ module ActiveRecord
|
|
480
527
|
def find_some(ids)
|
481
528
|
return find_some_ordered(ids) unless order_values.present?
|
482
529
|
|
483
|
-
|
530
|
+
relation = where(primary_key => ids)
|
531
|
+
relation = relation.select(table[primary_key]) unless select_values.empty?
|
532
|
+
result = relation.to_a
|
484
533
|
|
485
534
|
expected_size =
|
486
535
|
if limit_value && ids.size > limit_value
|
@@ -504,7 +553,10 @@ module ActiveRecord
|
|
504
553
|
def find_some_ordered(ids)
|
505
554
|
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
506
555
|
|
507
|
-
|
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
|
508
560
|
|
509
561
|
if result.size == ids.size
|
510
562
|
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
|
@@ -559,10 +611,10 @@ module ActiveRecord
|
|
559
611
|
else
|
560
612
|
relation = ordered_relation
|
561
613
|
|
562
|
-
if
|
614
|
+
if relation.order_values.empty? || relation.has_limit_or_offset?
|
563
615
|
relation.records[-index]
|
564
616
|
else
|
565
|
-
relation.
|
617
|
+
relation.reverse_order.offset(index - 1).first
|
566
618
|
end
|
567
619
|
end
|
568
620
|
end
|
@@ -572,15 +624,24 @@ module ActiveRecord
|
|
572
624
|
end
|
573
625
|
|
574
626
|
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
|
627
|
+
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
628
|
+
order(_order_columns.map { |column| table[column].asc })
|
581
629
|
else
|
582
630
|
self
|
583
631
|
end
|
584
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
|
585
646
|
end
|
586
647
|
end
|
@@ -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)
|
@@ -29,8 +29,8 @@ module ActiveRecord
|
|
29
29
|
attributes.each_with_object([]) do |(key, value), result|
|
30
30
|
if value.is_a?(Hash)
|
31
31
|
result << Arel.sql(key)
|
32
|
-
elsif key.
|
33
|
-
result << Arel.sql(key
|
32
|
+
elsif (idx = key.rindex("."))
|
33
|
+
result << Arel.sql(key[0, idx])
|
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)
|
@@ -142,19 +148,25 @@ module ActiveRecord
|
|
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)
|
@@ -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)
|
@@ -35,6 +50,15 @@ module ActiveRecord
|
|
35
50
|
@_unboundable
|
36
51
|
end
|
37
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
|
60
|
+
end
|
61
|
+
|
38
62
|
private
|
39
63
|
def infinity?(value)
|
40
64
|
value.respond_to?(:infinite?) && value.infinite?
|