activerecord 6.1.3.2 → 7.0.0.alpha2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +734 -1058
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +35 -7
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +16 -6
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- 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 +2 -2
- data/lib/active_record/associations/collection_association.rb +24 -25
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/preloader/association.rb +161 -49
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +41 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +11 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- 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/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -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 +6 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +8 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +129 -117
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +18 -9
- data/lib/active_record/delegated_type.rb +33 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- 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/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -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 +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -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 +80 -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 +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +44 -46
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +39 -6
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +46 -32
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +83 -58
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +42 -25
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +32 -23
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +233 -50
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +22 -15
- data/lib/active_record/relation.rb +170 -87
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +62 -15
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +107 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +45 -4
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +1 -1
- data/lib/active_record.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/composite.rb +3 -3
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- data/lib/arel/nodes/homogeneous_in.rb +4 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +3 -2
- data/lib/arel/predications.rb +3 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +44 -3
- data/lib/arel.rb +1 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- 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
- metadata +55 -16
@@ -5,13 +5,27 @@ module ActiveRecord
|
|
5
5
|
class BatchEnumerator
|
6
6
|
include Enumerable
|
7
7
|
|
8
|
-
def initialize(of: 1000, start: nil, finish: nil, relation:)
|
8
|
+
def initialize(of: 1000, start: nil, finish: nil, relation:) # :nodoc:
|
9
9
|
@of = of
|
10
10
|
@relation = relation
|
11
11
|
@start = start
|
12
12
|
@finish = finish
|
13
13
|
end
|
14
14
|
|
15
|
+
# The primary key value from which the BatchEnumerator starts, inclusive of the value.
|
16
|
+
attr_reader :start
|
17
|
+
|
18
|
+
# The primary key value at which the BatchEnumerator ends, inclusive of the value.
|
19
|
+
attr_reader :finish
|
20
|
+
|
21
|
+
# The relation from which the BatchEnumerator yields batches.
|
22
|
+
attr_reader :relation
|
23
|
+
|
24
|
+
# The size of the batches yielded by the BatchEnumerator.
|
25
|
+
def batch_size
|
26
|
+
@of
|
27
|
+
end
|
28
|
+
|
15
29
|
# Looping through a collection of records from the database (using the
|
16
30
|
# +all+ method, for example) is very inefficient since it will try to
|
17
31
|
# instantiate all the objects at once.
|
@@ -33,11 +47,11 @@ module ActiveRecord
|
|
33
47
|
# Person.in_batches.each_record.with_index do |person, index|
|
34
48
|
# person.award_trophy(index + 1)
|
35
49
|
# end
|
36
|
-
def each_record
|
50
|
+
def each_record(&block)
|
37
51
|
return to_enum(:each_record) unless block_given?
|
38
52
|
|
39
53
|
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
|
40
|
-
relation.records.each
|
54
|
+
relation.records.each(&block)
|
41
55
|
end
|
42
56
|
end
|
43
57
|
|
@@ -75,9 +89,9 @@ module ActiveRecord
|
|
75
89
|
# Person.in_batches.each do |relation|
|
76
90
|
# relation.update_all(awesome: true)
|
77
91
|
# end
|
78
|
-
def each
|
92
|
+
def each(&block)
|
79
93
|
enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false)
|
80
|
-
return enum.each
|
94
|
+
return enum.each(&block) if block_given?
|
81
95
|
enum
|
82
96
|
end
|
83
97
|
end
|
@@ -65,10 +65,10 @@ module ActiveRecord
|
|
65
65
|
#
|
66
66
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
67
67
|
# other processes are modifying the database.
|
68
|
-
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
|
68
|
+
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block)
|
69
69
|
if block_given?
|
70
70
|
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
|
71
|
-
records.each
|
71
|
+
records.each(&block)
|
72
72
|
end
|
73
73
|
else
|
74
74
|
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
@@ -284,7 +284,7 @@ module ActiveRecord
|
|
284
284
|
end
|
285
285
|
|
286
286
|
def act_on_ignored_order(error_on_ignore)
|
287
|
-
raise_error = (error_on_ignore.nil? ?
|
287
|
+
raise_error = (error_on_ignore.nil? ? ActiveRecord.error_on_ignored_order : error_on_ignore)
|
288
288
|
|
289
289
|
if raise_error
|
290
290
|
raise ArgumentError.new(ORDER_IGNORE_MESSAGE)
|
@@ -83,15 +83,24 @@ module ActiveRecord
|
|
83
83
|
# #calculate for examples with options.
|
84
84
|
#
|
85
85
|
# Person.sum(:age) # => 4562
|
86
|
-
def sum(
|
86
|
+
def sum(identity_or_column = nil, &block)
|
87
87
|
if block_given?
|
88
|
-
|
89
|
-
|
88
|
+
values = map(&block)
|
89
|
+
if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == [])
|
90
|
+
identity_or_column = 0
|
90
91
|
end
|
91
92
|
|
92
|
-
|
93
|
+
if identity_or_column.nil?
|
94
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
95
|
+
Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
|
96
|
+
Sum of non-numeric elements requires an initial argument.
|
97
|
+
MSG
|
98
|
+
values.inject(:+) || 0
|
99
|
+
else
|
100
|
+
values.sum(identity_or_column)
|
101
|
+
end
|
93
102
|
else
|
94
|
-
calculate(:sum,
|
103
|
+
calculate(:sum, identity_or_column)
|
95
104
|
end
|
96
105
|
end
|
97
106
|
|
@@ -195,9 +204,9 @@ module ActiveRecord
|
|
195
204
|
relation.select_values = columns
|
196
205
|
result = skip_query_cache_if_necessary do
|
197
206
|
if where_clause.contradiction?
|
198
|
-
ActiveRecord::Result.
|
207
|
+
ActiveRecord::Result.empty
|
199
208
|
else
|
200
|
-
klass.connection.select_all(relation.arel,
|
209
|
+
klass.connection.select_all(relation.arel, "#{klass.name} Pluck")
|
201
210
|
end
|
202
211
|
end
|
203
212
|
type_cast_pluck_values(result, columns)
|
@@ -286,7 +295,7 @@ module ActiveRecord
|
|
286
295
|
operation == "count" ? column.count(distinct) : column.public_send(operation)
|
287
296
|
end
|
288
297
|
|
289
|
-
def execute_simple_calculation(operation, column_name, distinct)
|
298
|
+
def execute_simple_calculation(operation, column_name, distinct) # :nodoc:
|
290
299
|
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
291
300
|
# Shortcut when limit is zero.
|
292
301
|
return 0 if limit_value == 0
|
@@ -305,23 +314,25 @@ module ActiveRecord
|
|
305
314
|
query_builder = relation.arel
|
306
315
|
end
|
307
316
|
|
308
|
-
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
|
317
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, "#{@klass.name} #{operation.capitalize}") }
|
309
318
|
|
310
|
-
|
319
|
+
if operation != "count"
|
311
320
|
type = column.try(:type_caster) ||
|
312
321
|
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
313
|
-
type.
|
322
|
+
type = type.subtype if Enum::EnumType === type
|
314
323
|
end
|
324
|
+
|
325
|
+
type_cast_calculated_value(result.cast_values.first, operation, type)
|
315
326
|
end
|
316
327
|
|
317
|
-
def execute_grouped_calculation(operation, column_name, distinct)
|
328
|
+
def execute_grouped_calculation(operation, column_name, distinct) # :nodoc:
|
318
329
|
group_fields = group_values
|
319
330
|
group_fields = group_fields.uniq if group_fields.size > 1
|
320
331
|
|
321
332
|
unless group_fields == group_values
|
322
333
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
323
|
-
`#{operation}` with group by duplicated fields does no longer affect to result in Rails
|
324
|
-
To migrate to Rails
|
334
|
+
`#{operation}` with group by duplicated fields does no longer affect to result in Rails 7.0.
|
335
|
+
To migrate to Rails 7.0's behavior, use `uniq!(:group)` to deduplicate group fields
|
325
336
|
(`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
|
326
337
|
MSG
|
327
338
|
group_fields = group_values
|
@@ -360,7 +371,7 @@ module ActiveRecord
|
|
360
371
|
relation.group_values = group_fields
|
361
372
|
relation.select_values = select_values
|
362
373
|
|
363
|
-
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel,
|
374
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "#{@klass.name} #{operation.capitalize}") }
|
364
375
|
|
365
376
|
if association
|
366
377
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
@@ -380,17 +391,18 @@ module ActiveRecord
|
|
380
391
|
end
|
381
392
|
end
|
382
393
|
|
383
|
-
|
394
|
+
if operation != "count"
|
395
|
+
type = column.try(:type_caster) ||
|
396
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
397
|
+
type = type.subtype if Enum::EnumType === type
|
398
|
+
end
|
399
|
+
|
384
400
|
hash_rows.each_with_object({}) do |row, result|
|
385
401
|
key = group_aliases.map { |aliaz| row[aliaz] }
|
386
402
|
key = key.first if key.size == 1
|
387
403
|
key = key_records[key] if associated
|
388
404
|
|
389
|
-
result[key] = type_cast_calculated_value(row[column_alias], operation)
|
390
|
-
type ||= column.try(:type_caster) ||
|
391
|
-
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
392
|
-
type.deserialize(value)
|
393
|
-
end
|
405
|
+
result[key] = type_cast_calculated_value(row[column_alias], operation, type)
|
394
406
|
end
|
395
407
|
end
|
396
408
|
|
@@ -441,16 +453,21 @@ module ActiveRecord
|
|
441
453
|
result.cast_values(cast_types)
|
442
454
|
end
|
443
455
|
|
444
|
-
def type_cast_calculated_value(value, operation)
|
456
|
+
def type_cast_calculated_value(value, operation, type)
|
445
457
|
case operation
|
446
458
|
when "count"
|
447
459
|
value.to_i
|
448
460
|
when "sum"
|
449
|
-
|
461
|
+
type.deserialize(value || 0)
|
450
462
|
when "average"
|
451
|
-
|
463
|
+
case type.type
|
464
|
+
when :integer, :decimal
|
465
|
+
value&.to_d
|
466
|
+
else
|
467
|
+
type.deserialize(value)
|
468
|
+
end
|
452
469
|
else # "minimum", "maximum"
|
453
|
-
|
470
|
+
type.deserialize(value)
|
454
471
|
end
|
455
472
|
end
|
456
473
|
|
@@ -15,7 +15,8 @@ module ActiveRecord
|
|
15
15
|
[
|
16
16
|
ActiveRecord::Relation,
|
17
17
|
ActiveRecord::Associations::CollectionProxy,
|
18
|
-
ActiveRecord::AssociationRelation
|
18
|
+
ActiveRecord::AssociationRelation,
|
19
|
+
ActiveRecord::DisableJoinsAssociationRelation
|
19
20
|
].each do |klass|
|
20
21
|
delegate = Class.new(klass) {
|
21
22
|
include ClassSpecificRelation
|
@@ -61,17 +62,16 @@ module ActiveRecord
|
|
61
62
|
return if method_defined?(method)
|
62
63
|
|
63
64
|
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
|
64
|
-
definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
|
65
65
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
66
|
-
def #{method}(
|
67
|
-
scoping { klass.#{method}(
|
66
|
+
def #{method}(...)
|
67
|
+
scoping { klass.#{method}(...) }
|
68
68
|
end
|
69
69
|
RUBY
|
70
70
|
else
|
71
71
|
define_method(method) do |*args, &block|
|
72
72
|
scoping { klass.public_send(method, *args, &block) }
|
73
73
|
end
|
74
|
-
ruby2_keywords(method)
|
74
|
+
ruby2_keywords(method)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -110,7 +110,7 @@ module ActiveRecord
|
|
110
110
|
super
|
111
111
|
end
|
112
112
|
end
|
113
|
-
ruby2_keywords(:method_missing)
|
113
|
+
ruby2_keywords(:method_missing)
|
114
114
|
end
|
115
115
|
|
116
116
|
module ClassMethods # :nodoc:
|
@@ -104,6 +104,32 @@ module ActiveRecord
|
|
104
104
|
take || raise_record_not_found_exception!
|
105
105
|
end
|
106
106
|
|
107
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
108
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
109
|
+
# record is found.
|
110
|
+
#
|
111
|
+
# Product.where(["price = %?", price]).sole
|
112
|
+
def sole
|
113
|
+
found, undesired = first(2)
|
114
|
+
|
115
|
+
if found.nil?
|
116
|
+
raise_record_not_found_exception!
|
117
|
+
elsif undesired.present?
|
118
|
+
raise ActiveRecord::SoleRecordExceeded.new(self)
|
119
|
+
else
|
120
|
+
found
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
125
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
126
|
+
# record is found.
|
127
|
+
#
|
128
|
+
# Product.find_sole_by(["price = %?", price])
|
129
|
+
def find_sole_by(arg, *args)
|
130
|
+
where(arg, *args).sole
|
131
|
+
end
|
132
|
+
|
107
133
|
# Find the first record (or first N records if a parameter is supplied).
|
108
134
|
# If no order is defined it will order by primary key.
|
109
135
|
#
|
@@ -369,7 +395,7 @@ module ActiveRecord
|
|
369
395
|
blank_value = order_values.first
|
370
396
|
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
371
397
|
`.reorder(#{blank_value.inspect})` with `.first` / `.first!` no longer
|
372
|
-
takes non-deterministic result in Rails
|
398
|
+
takes non-deterministic result in Rails 7.0.
|
373
399
|
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
374
400
|
MSG
|
375
401
|
end
|
@@ -400,7 +426,7 @@ module ActiveRecord
|
|
400
426
|
)
|
401
427
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
402
428
|
|
403
|
-
if eager_loading && !(
|
429
|
+
if eager_loading && has_limit_or_offset? && !(
|
404
430
|
using_limitable_reflections?(join_dependency.reflections) &&
|
405
431
|
using_limitable_reflections?(
|
406
432
|
construct_join_dependency(
|
@@ -409,12 +435,10 @@ module ActiveRecord
|
|
409
435
|
), nil
|
410
436
|
).reflections
|
411
437
|
)
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
438
|
+
)
|
439
|
+
relation = skip_query_cache_if_necessary do
|
440
|
+
klass.connection.distinct_relation_for_primary_key(relation)
|
416
441
|
end
|
417
|
-
relation.limit_value = relation.offset_value = nil
|
418
442
|
end
|
419
443
|
|
420
444
|
if block_given?
|
@@ -424,18 +448,6 @@ module ActiveRecord
|
|
424
448
|
end
|
425
449
|
end
|
426
450
|
|
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
451
|
def using_limitable_reflections?(reflections)
|
440
452
|
reflections.none?(&:collection?)
|
441
453
|
end
|
@@ -508,10 +520,7 @@ module ActiveRecord
|
|
508
520
|
result = except(:limit, :offset).where(primary_key => ids).records
|
509
521
|
|
510
522
|
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)) }
|
523
|
+
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
|
515
524
|
else
|
516
525
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
517
526
|
end
|
@@ -51,30 +51,25 @@ 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
|
+
merge_select_values
|
78
73
|
merge_multi_values
|
79
74
|
merge_single_values
|
80
75
|
merge_clauses
|
@@ -86,6 +81,18 @@ module ActiveRecord
|
|
86
81
|
end
|
87
82
|
|
88
83
|
private
|
84
|
+
def merge_select_values
|
85
|
+
return if other.select_values.empty?
|
86
|
+
|
87
|
+
if other.klass == relation.klass
|
88
|
+
relation.select_values |= other.select_values
|
89
|
+
else
|
90
|
+
relation.select_values |= other.instance_eval do
|
91
|
+
arel_columns(select_values)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
89
96
|
def merge_preloads
|
90
97
|
return if other.preload_values.empty? && other.includes_values.empty?
|
91
98
|
|
@@ -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 = []
|
@@ -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)
|
@@ -20,25 +20,19 @@ module ActiveRecord
|
|
20
20
|
def nil?
|
21
21
|
unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
22
22
|
value_before_type_cast.nil? ||
|
23
|
-
type.respond_to?(:subtype
|
23
|
+
type.respond_to?(:subtype) && serializable? && value_for_database.nil?
|
24
24
|
end
|
25
|
-
rescue ::RangeError
|
26
25
|
end
|
27
26
|
|
28
27
|
def infinite?
|
29
|
-
infinity?(value_before_type_cast) || infinity?(value_for_database)
|
30
|
-
rescue ::RangeError
|
28
|
+
infinity?(value_before_type_cast) || serializable? && infinity?(value_for_database)
|
31
29
|
end
|
32
30
|
|
33
31
|
def unboundable?
|
34
|
-
|
35
|
-
@_unboundable
|
36
|
-
else
|
37
|
-
value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
38
|
-
@_unboundable = nil
|
32
|
+
unless defined?(@_unboundable)
|
33
|
+
serializable? { |value| @_unboundable = value <=> 0 } && @_unboundable = nil
|
39
34
|
end
|
40
|
-
|
41
|
-
@_unboundable = type.cast(value_before_type_cast) <=> 0
|
35
|
+
@_unboundable
|
42
36
|
end
|
43
37
|
|
44
38
|
private
|