activerecord 5.2.6 → 6.1.3.2
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 +1038 -571
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +13 -12
- data/lib/active_record/aggregations.rb +9 -8
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations.rb +137 -25
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +95 -42
- data/lib/active_record/associations/association_scope.rb +23 -21
- data/lib/active_record/associations/belongs_to_association.rb +54 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
- data/lib/active_record/associations/builder/association.rb +45 -22
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +8 -17
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +24 -18
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/preloader.rb +47 -34
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attributes.rb +46 -9
- data/lib/active_record/autosave_association.rb +57 -42
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +228 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
- data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +293 -33
- data/lib/active_record/core.rb +323 -97
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +111 -37
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +200 -481
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +37 -23
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +35 -35
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/migration.rb +206 -157
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +142 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +115 -58
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +408 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +109 -93
- data/lib/active_record/relation.rb +374 -104
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +153 -90
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +64 -39
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder.rb +62 -45
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +475 -186
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +111 -61
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +277 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +62 -118
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/arel.rb +54 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +119 -34
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -37,6 +37,7 @@ module ActiveRecord
|
|
37
37
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
38
38
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
39
39
|
# an order is present in the relation.
|
40
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be :asc or :desc). Defaults to :asc.
|
40
41
|
#
|
41
42
|
# Limits are honored, and if present there is no requirement for the batch
|
42
43
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -57,22 +58,22 @@ module ActiveRecord
|
|
57
58
|
# person.party_all_night!
|
58
59
|
# end
|
59
60
|
#
|
60
|
-
# NOTE:
|
61
|
-
# ascending on the primary key ("id ASC")
|
62
|
-
#
|
61
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
62
|
+
# ascending on the primary key ("id ASC").
|
63
|
+
# This also means that this method only works when the primary key is
|
63
64
|
# orderable (e.g. an integer or string).
|
64
65
|
#
|
65
66
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
66
67
|
# other processes are modifying the database.
|
67
|
-
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
|
68
|
+
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
|
68
69
|
if block_given?
|
69
|
-
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do |records|
|
70
|
+
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
|
70
71
|
records.each { |record| yield record }
|
71
72
|
end
|
72
73
|
else
|
73
|
-
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
|
74
|
+
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
74
75
|
relation = self
|
75
|
-
apply_limits(relation, start, finish).size
|
76
|
+
apply_limits(relation, start, finish, order).size
|
76
77
|
end
|
77
78
|
end
|
78
79
|
end
|
@@ -101,6 +102,7 @@ module ActiveRecord
|
|
101
102
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
102
103
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
103
104
|
# an order is present in the relation.
|
105
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be :asc or :desc). Defaults to :asc.
|
104
106
|
#
|
105
107
|
# Limits are honored, and if present there is no requirement for the batch
|
106
108
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -116,23 +118,23 @@ module ActiveRecord
|
|
116
118
|
# group.each { |person| person.party_all_night! }
|
117
119
|
# end
|
118
120
|
#
|
119
|
-
# NOTE:
|
120
|
-
# ascending on the primary key ("id ASC")
|
121
|
-
#
|
121
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
122
|
+
# ascending on the primary key ("id ASC").
|
123
|
+
# This also means that this method only works when the primary key is
|
122
124
|
# orderable (e.g. an integer or string).
|
123
125
|
#
|
124
126
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
125
127
|
# other processes are modifying the database.
|
126
|
-
def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
|
128
|
+
def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
|
127
129
|
relation = self
|
128
130
|
unless block_given?
|
129
|
-
return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
|
130
|
-
total = apply_limits(relation, start, finish).size
|
131
|
+
return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
132
|
+
total = apply_limits(relation, start, finish, order).size
|
131
133
|
(total - 1).div(batch_size) + 1
|
132
134
|
end
|
133
135
|
end
|
134
136
|
|
135
|
-
in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore) do |batch|
|
137
|
+
in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore, order: order) do |batch|
|
136
138
|
yield batch.to_a
|
137
139
|
end
|
138
140
|
end
|
@@ -165,6 +167,7 @@ module ActiveRecord
|
|
165
167
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
166
168
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
167
169
|
# an order is present in the relation.
|
170
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be :asc or :desc). Defaults to :asc.
|
168
171
|
#
|
169
172
|
# Limits are honored, and if present there is no requirement for the batch
|
170
173
|
# size, it can be less than, equal, or greater than the limit.
|
@@ -191,19 +194,23 @@ module ActiveRecord
|
|
191
194
|
#
|
192
195
|
# Person.in_batches.each_record(&:party_all_night!)
|
193
196
|
#
|
194
|
-
# NOTE:
|
195
|
-
# ascending on the primary key ("id ASC")
|
196
|
-
#
|
197
|
-
# or
|
197
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
198
|
+
# ascending on the primary key ("id ASC").
|
199
|
+
# This also means that this method only works when the primary key is
|
200
|
+
# orderable (e.g. an integer or string).
|
198
201
|
#
|
199
202
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
200
203
|
# other processes are modifying the database.
|
201
|
-
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil)
|
204
|
+
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil, order: :asc)
|
202
205
|
relation = self
|
203
206
|
unless block_given?
|
204
207
|
return BatchEnumerator.new(of: of, start: start, finish: finish, relation: self)
|
205
208
|
end
|
206
209
|
|
210
|
+
unless [:asc, :desc].include?(order)
|
211
|
+
raise ArgumentError, ":order must be :asc or :desc, got #{order.inspect}"
|
212
|
+
end
|
213
|
+
|
207
214
|
if arel.orders.present?
|
208
215
|
act_on_ignored_order(error_on_ignore)
|
209
216
|
end
|
@@ -214,8 +221,8 @@ module ActiveRecord
|
|
214
221
|
batch_limit = remaining if remaining < batch_limit
|
215
222
|
end
|
216
223
|
|
217
|
-
relation = relation.reorder(batch_order).limit(batch_limit)
|
218
|
-
relation = apply_limits(relation, start, finish)
|
224
|
+
relation = relation.reorder(batch_order(order)).limit(batch_limit)
|
225
|
+
relation = apply_limits(relation, start, finish, order)
|
219
226
|
relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
|
220
227
|
batch_relation = relation
|
221
228
|
|
@@ -251,27 +258,29 @@ module ActiveRecord
|
|
251
258
|
end
|
252
259
|
end
|
253
260
|
|
254
|
-
|
255
|
-
|
261
|
+
batch_relation = relation.where(
|
262
|
+
predicate_builder[primary_key, primary_key_offset, order == :desc ? :lt : :gt]
|
263
|
+
)
|
256
264
|
end
|
257
265
|
end
|
258
266
|
|
259
267
|
private
|
260
|
-
|
261
|
-
|
262
|
-
if
|
263
|
-
attr = Relation::QueryAttribute.new(primary_key, start, klass.type_for_attribute(primary_key))
|
264
|
-
relation = relation.where(arel_attribute(primary_key).gteq(Arel::Nodes::BindParam.new(attr)))
|
265
|
-
end
|
266
|
-
if finish
|
267
|
-
attr = Relation::QueryAttribute.new(primary_key, finish, klass.type_for_attribute(primary_key))
|
268
|
-
relation = relation.where(arel_attribute(primary_key).lteq(Arel::Nodes::BindParam.new(attr)))
|
269
|
-
end
|
268
|
+
def apply_limits(relation, start, finish, order)
|
269
|
+
relation = apply_start_limit(relation, start, order) if start
|
270
|
+
relation = apply_finish_limit(relation, finish, order) if finish
|
270
271
|
relation
|
271
272
|
end
|
272
273
|
|
273
|
-
def
|
274
|
-
|
274
|
+
def apply_start_limit(relation, start, order)
|
275
|
+
relation.where(predicate_builder[primary_key, start, order == :desc ? :lteq : :gteq])
|
276
|
+
end
|
277
|
+
|
278
|
+
def apply_finish_limit(relation, finish, order)
|
279
|
+
relation.where(predicate_builder[primary_key, finish, order == :desc ? :gteq : :lteq])
|
280
|
+
end
|
281
|
+
|
282
|
+
def batch_order(order)
|
283
|
+
table[primary_key].public_send(order)
|
275
284
|
end
|
276
285
|
|
277
286
|
def act_on_ignored_order(error_on_ignore)
|
@@ -41,19 +41,35 @@ module ActiveRecord
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
#
|
44
|
+
# Deletes records in batches. Returns the total number of rows affected.
|
45
45
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
# Person.in_batches.delete_all
|
47
|
+
#
|
48
|
+
# See Relation#delete_all for details of how each batch is deleted.
|
49
|
+
def delete_all
|
50
|
+
sum(&:delete_all)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Updates records in batches. Returns the total number of rows affected.
|
54
|
+
#
|
55
|
+
# Person.in_batches.update_all("age = age + 1")
|
56
|
+
#
|
57
|
+
# See Relation#update_all for details of how each batch is updated.
|
58
|
+
def update_all(updates)
|
59
|
+
sum do |relation|
|
60
|
+
relation.update_all(updates)
|
54
61
|
end
|
55
62
|
end
|
56
63
|
|
64
|
+
# Destroys records in batches.
|
65
|
+
#
|
66
|
+
# Person.where("age < 10").in_batches.destroy_all
|
67
|
+
#
|
68
|
+
# See Relation#destroy_all for details of how each batch is destroyed.
|
69
|
+
def destroy_all
|
70
|
+
each(&:destroy_all)
|
71
|
+
end
|
72
|
+
|
57
73
|
# Yields an ActiveRecord::Relation object for each batch of records.
|
58
74
|
#
|
59
75
|
# Person.in_batches.each do |relation|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module Calculations
|
5
7
|
# Count the records.
|
@@ -41,15 +43,13 @@ module ActiveRecord
|
|
41
43
|
def count(column_name = nil)
|
42
44
|
if block_given?
|
43
45
|
unless column_name.nil?
|
44
|
-
|
45
|
-
"When `count' is called with a block, it ignores other arguments. " \
|
46
|
-
"This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
|
46
|
+
raise ArgumentError, "Column name argument is not supported when a block is passed."
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
super()
|
50
|
+
else
|
51
|
+
calculate(:count, column_name)
|
50
52
|
end
|
51
|
-
|
52
|
-
calculate(:count, column_name)
|
53
53
|
end
|
54
54
|
|
55
55
|
# Calculates the average value on a given column. Returns +nil+ if there's
|
@@ -86,15 +86,13 @@ module ActiveRecord
|
|
86
86
|
def sum(column_name = nil)
|
87
87
|
if block_given?
|
88
88
|
unless column_name.nil?
|
89
|
-
|
90
|
-
"When `sum' is called with a block, it ignores other arguments. " \
|
91
|
-
"This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
|
89
|
+
raise ArgumentError, "Column name argument is not supported when a block is passed."
|
92
90
|
end
|
93
91
|
|
94
|
-
|
92
|
+
super()
|
93
|
+
else
|
94
|
+
calculate(:sum, column_name)
|
95
95
|
end
|
96
|
-
|
97
|
-
calculate(:sum, column_name)
|
98
96
|
end
|
99
97
|
|
100
98
|
# This calculates aggregate values in the given column. Methods for #count, #sum, #average,
|
@@ -138,7 +136,7 @@ module ActiveRecord
|
|
138
136
|
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
139
137
|
end
|
140
138
|
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
141
|
-
relation.order_values = []
|
139
|
+
relation.order_values = [] if group_values.empty?
|
142
140
|
end
|
143
141
|
|
144
142
|
relation.calculate(operation, column_name)
|
@@ -176,14 +174,14 @@ module ActiveRecord
|
|
176
174
|
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
177
175
|
# # => [2, 3]
|
178
176
|
#
|
179
|
-
# Person.pluck('DATEDIFF(updated_at, created_at)')
|
177
|
+
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
|
180
178
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
181
179
|
# # => ['0', '27761', '173']
|
182
180
|
#
|
183
181
|
# See also #ids.
|
184
182
|
#
|
185
183
|
def pluck(*column_names)
|
186
|
-
if loaded? && (column_names
|
184
|
+
if loaded? && all_attributes?(column_names)
|
187
185
|
return records.pluck(*column_names)
|
188
186
|
end
|
189
187
|
|
@@ -191,12 +189,41 @@ module ActiveRecord
|
|
191
189
|
relation = apply_join_dependency
|
192
190
|
relation.pluck(*column_names)
|
193
191
|
else
|
194
|
-
klass.
|
192
|
+
klass.disallow_raw_sql!(column_names)
|
193
|
+
columns = arel_columns(column_names)
|
195
194
|
relation = spawn
|
196
|
-
relation.select_values =
|
197
|
-
result = skip_query_cache_if_necessary
|
198
|
-
|
195
|
+
relation.select_values = columns
|
196
|
+
result = skip_query_cache_if_necessary do
|
197
|
+
if where_clause.contradiction?
|
198
|
+
ActiveRecord::Result.new([], [])
|
199
|
+
else
|
200
|
+
klass.connection.select_all(relation.arel, nil)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
type_cast_pluck_values(result, columns)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Pick the value(s) from the named column(s) in the current relation.
|
208
|
+
# This is short-hand for <tt>relation.limit(1).pluck(*column_names).first</tt>, and is primarily useful
|
209
|
+
# when you have a relation that's already narrowed down to a single row.
|
210
|
+
#
|
211
|
+
# Just like #pluck, #pick will only load the actual value, not the entire record object, so it's also
|
212
|
+
# more efficient. The value is, again like with pluck, typecast by the column type.
|
213
|
+
#
|
214
|
+
# Person.where(id: 1).pick(:name)
|
215
|
+
# # SELECT people.name FROM people WHERE id = 1 LIMIT 1
|
216
|
+
# # => 'David'
|
217
|
+
#
|
218
|
+
# Person.where(id: 1).pick(:name, :email_address)
|
219
|
+
# # SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
|
220
|
+
# # => [ 'David', 'david@loudthinking.com' ]
|
221
|
+
def pick(*column_names)
|
222
|
+
if loaded? && all_attributes?(column_names)
|
223
|
+
return records.pick(*column_names)
|
199
224
|
end
|
225
|
+
|
226
|
+
limit(1).pluck(*column_names).first
|
200
227
|
end
|
201
228
|
|
202
229
|
# Pluck all the ID's for the relation using the table's primary key
|
@@ -208,6 +235,10 @@ module ActiveRecord
|
|
208
235
|
end
|
209
236
|
|
210
237
|
private
|
238
|
+
def all_attributes?(column_names)
|
239
|
+
(column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
|
240
|
+
end
|
241
|
+
|
211
242
|
def has_include?(column_name)
|
212
243
|
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
213
244
|
end
|
@@ -246,20 +277,16 @@ module ActiveRecord
|
|
246
277
|
def aggregate_column(column_name)
|
247
278
|
return column_name if Arel::Expressions === column_name
|
248
279
|
|
249
|
-
|
250
|
-
|
251
|
-
else
|
252
|
-
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
280
|
+
arel_column(column_name.to_s) do |name|
|
281
|
+
Arel.sql(column_name == :all ? "*" : name)
|
253
282
|
end
|
254
283
|
end
|
255
284
|
|
256
285
|
def operation_over_aggregate_column(column, operation, distinct)
|
257
|
-
operation == "count" ? column.count(distinct) : column.
|
286
|
+
operation == "count" ? column.count(distinct) : column.public_send(operation)
|
258
287
|
end
|
259
288
|
|
260
289
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
261
|
-
column_alias = column_name
|
262
|
-
|
263
290
|
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
264
291
|
# Shortcut when limit is zero.
|
265
292
|
return 0 if limit_value == 0
|
@@ -270,56 +297,55 @@ module ActiveRecord
|
|
270
297
|
relation = unscope(:order).distinct!(false)
|
271
298
|
|
272
299
|
column = aggregate_column(column_name)
|
273
|
-
|
274
300
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
275
|
-
if operation == "sum" && distinct
|
276
|
-
select_value.distinct = true
|
277
|
-
end
|
301
|
+
select_value.distinct = true if operation == "sum" && distinct
|
278
302
|
|
279
|
-
column_alias = select_value.alias
|
280
|
-
column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
|
281
303
|
relation.select_values = [select_value]
|
282
304
|
|
283
305
|
query_builder = relation.arel
|
284
306
|
end
|
285
307
|
|
286
|
-
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder
|
287
|
-
row = result.first
|
288
|
-
value = row && row.values.first
|
289
|
-
type = result.column_types.fetch(column_alias) do
|
290
|
-
type_for(column_name)
|
291
|
-
end
|
308
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
|
292
309
|
|
293
|
-
type_cast_calculated_value(
|
310
|
+
type_cast_calculated_value(result.cast_values.first, operation) do |value|
|
311
|
+
type = column.try(:type_caster) ||
|
312
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
313
|
+
type.deserialize(value)
|
314
|
+
end
|
294
315
|
end
|
295
316
|
|
296
317
|
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
297
|
-
|
318
|
+
group_fields = group_values
|
319
|
+
group_fields = group_fields.uniq if group_fields.size > 1
|
320
|
+
|
321
|
+
unless group_fields == group_values
|
322
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
323
|
+
`#{operation}` with group by duplicated fields does no longer affect to result in Rails 6.2.
|
324
|
+
To migrate to Rails 6.2's behavior, use `uniq!(:group)` to deduplicate group fields
|
325
|
+
(`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
|
326
|
+
MSG
|
327
|
+
group_fields = group_values
|
328
|
+
end
|
298
329
|
|
299
|
-
if
|
300
|
-
association =
|
301
|
-
associated =
|
302
|
-
group_fields = Array(
|
303
|
-
else
|
304
|
-
group_fields = group_attrs
|
330
|
+
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
331
|
+
association = klass._reflect_on_association(group_fields.first)
|
332
|
+
associated = association && association.belongs_to? # only count belongs_to associations
|
333
|
+
group_fields = Array(association.foreign_key) if associated
|
305
334
|
end
|
306
335
|
group_fields = arel_columns(group_fields)
|
307
336
|
|
308
|
-
group_aliases = group_fields.map { |field|
|
337
|
+
group_aliases = group_fields.map { |field|
|
338
|
+
field = connection.visitor.compile(field) if Arel.arel_node?(field)
|
339
|
+
column_alias_for(field.to_s.downcase)
|
340
|
+
}
|
309
341
|
group_columns = group_aliases.zip(group_fields)
|
310
342
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
end
|
343
|
+
column = aggregate_column(column_name)
|
344
|
+
column_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
|
345
|
+
select_value = operation_over_aggregate_column(column, operation, distinct)
|
346
|
+
select_value.as(column_alias)
|
316
347
|
|
317
|
-
select_values = [
|
318
|
-
operation_over_aggregate_column(
|
319
|
-
aggregate_column(column_name),
|
320
|
-
operation,
|
321
|
-
distinct).as(aggregate_alias)
|
322
|
-
]
|
348
|
+
select_values = [select_value]
|
323
349
|
select_values += self.select_values unless having_clause.empty?
|
324
350
|
|
325
351
|
select_values.concat group_columns.map { |aliaz, field|
|
@@ -339,43 +365,50 @@ module ActiveRecord
|
|
339
365
|
if association
|
340
366
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
341
367
|
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
342
|
-
key_records =
|
368
|
+
key_records = key_records.index_by(&:id)
|
343
369
|
end
|
344
370
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
371
|
+
key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
|
372
|
+
types[aliaz] = type_for(col_name) do
|
373
|
+
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
hash_rows = calculated_data.cast_values(key_types).map! do |row|
|
378
|
+
calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
|
379
|
+
hash[col_name] = row[i]
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
type = nil
|
384
|
+
hash_rows.each_with_object({}) do |row, result|
|
385
|
+
key = group_aliases.map { |aliaz| row[aliaz] }
|
352
386
|
key = key.first if key.size == 1
|
353
387
|
key = key_records[key] if associated
|
354
388
|
|
355
|
-
|
356
|
-
|
357
|
-
|
389
|
+
result[key] = type_cast_calculated_value(row[column_alias], operation) do |value|
|
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
|
394
|
+
end
|
358
395
|
end
|
359
396
|
|
360
|
-
# Converts the given
|
397
|
+
# Converts the given field to the value that the database adapter returns as
|
361
398
|
# a usable column name:
|
362
399
|
#
|
363
400
|
# column_alias_for("users.id") # => "users_id"
|
364
401
|
# column_alias_for("sum(id)") # => "sum_id"
|
365
402
|
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
366
403
|
# column_alias_for("count(*)") # => "count_all"
|
367
|
-
def column_alias_for(
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
table_name.strip!
|
376
|
-
table_name.gsub!(/ +/, "_")
|
377
|
-
|
378
|
-
@klass.connection.table_alias_for(table_name)
|
404
|
+
def column_alias_for(field)
|
405
|
+
column_alias = +field
|
406
|
+
column_alias.gsub!(/\*/, "all")
|
407
|
+
column_alias.gsub!(/\W+/, " ")
|
408
|
+
column_alias.strip!
|
409
|
+
column_alias.gsub!(/ +/, "_")
|
410
|
+
|
411
|
+
connection.table_alias_for(column_alias)
|
379
412
|
end
|
380
413
|
|
381
414
|
def type_for(field, &block)
|
@@ -383,12 +416,41 @@ module ActiveRecord
|
|
383
416
|
@klass.type_for_attribute(field_name, &block)
|
384
417
|
end
|
385
418
|
|
386
|
-
def
|
419
|
+
def lookup_cast_type_from_join_dependencies(name, join_dependencies = build_join_dependencies)
|
420
|
+
each_join_dependencies(join_dependencies) do |join|
|
421
|
+
type = join.base_klass.attribute_types.fetch(name, nil)
|
422
|
+
return type if type
|
423
|
+
end
|
424
|
+
nil
|
425
|
+
end
|
426
|
+
|
427
|
+
def type_cast_pluck_values(result, columns)
|
428
|
+
cast_types = if result.columns.size != columns.size
|
429
|
+
klass.attribute_types
|
430
|
+
else
|
431
|
+
join_dependencies = nil
|
432
|
+
columns.map.with_index do |column, i|
|
433
|
+
column.try(:type_caster) ||
|
434
|
+
klass.attribute_types.fetch(name = result.columns[i]) do
|
435
|
+
join_dependencies ||= build_join_dependencies
|
436
|
+
lookup_cast_type_from_join_dependencies(name, join_dependencies) ||
|
437
|
+
result.column_types[name] || Type.default_value
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
result.cast_values(cast_types)
|
442
|
+
end
|
443
|
+
|
444
|
+
def type_cast_calculated_value(value, operation)
|
387
445
|
case operation
|
388
|
-
when "count"
|
389
|
-
|
390
|
-
when "
|
391
|
-
|
446
|
+
when "count"
|
447
|
+
value.to_i
|
448
|
+
when "sum"
|
449
|
+
yield value || 0
|
450
|
+
when "average"
|
451
|
+
value&.respond_to?(:to_d) ? value.to_d : value
|
452
|
+
else # "minimum", "maximum"
|
453
|
+
yield value
|
392
454
|
end
|
393
455
|
end
|
394
456
|
|
@@ -403,16 +465,17 @@ module ActiveRecord
|
|
403
465
|
|
404
466
|
def build_count_subquery(relation, column_name, distinct)
|
405
467
|
if column_name == :all
|
468
|
+
column_alias = Arel.star
|
406
469
|
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
407
470
|
else
|
408
471
|
column_alias = Arel.sql("count_column")
|
409
472
|
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
410
473
|
end
|
411
474
|
|
412
|
-
|
413
|
-
select_value = operation_over_aggregate_column(column_alias
|
475
|
+
subquery_alias = Arel.sql("subquery_for_count")
|
476
|
+
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
414
477
|
|
415
|
-
|
478
|
+
relation.build_subquery(subquery_alias, select_value)
|
416
479
|
end
|
417
480
|
end
|
418
481
|
end
|