activerecord 5.2.3 → 6.1.0
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 +898 -532
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +5 -4
- data/lib/active_record/association_relation.rb +22 -12
- 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 +21 -21
- data/lib/active_record/associations/belongs_to_association.rb +50 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
- data/lib/active_record/associations/builder/association.rb +23 -21
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +10 -19
- 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 +27 -28
- 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/join_association.rb +54 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- 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/preloader.rb +48 -35
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +133 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- 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/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +45 -8
- data/lib/active_record/autosave_association.rb +76 -47
- 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/abstract/connection_pool.rb +293 -132
- 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 +21 -17
- 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 +203 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -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 +44 -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 +14 -6
- 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 +63 -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/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/money.rb +2 -2
- 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/oid.rb +2 -0
- 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 +222 -112
- 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 +175 -187
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +285 -33
- data/lib/active_record/core.rb +308 -100
- data/lib/active_record/counter_cache.rb +8 -30
- 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/database_configurations.rb +272 -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 +71 -17
- 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 +197 -481
- data/lib/active_record/gem_version.rb +3 -3
- 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 +26 -22
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +34 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +141 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +205 -156
- 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/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +402 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +113 -101
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -93
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +65 -40
- 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/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 +4 -7
- 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/predicate_builder.rb +58 -40
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +487 -199
- 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 +108 -58
- data/lib/active_record/relation.rb +375 -104
- 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/default.rb +6 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- 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 +51 -8
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -43
- data/lib/active_record/tasks/database_tasks.rb +276 -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 +59 -117
- data/lib/active_record/translation.rb +1 -1
- 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.rb +10 -5
- 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/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- 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/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/nodes.rb +70 -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/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/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- 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/migration.rb +19 -2
- 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 +117 -32
- 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
@@ -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,
|
@@ -133,11 +131,12 @@ module ActiveRecord
|
|
133
131
|
relation = apply_join_dependency
|
134
132
|
|
135
133
|
if operation.to_s.downcase == "count"
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
relation.order_values = []
|
134
|
+
unless distinct_value || distinct_select?(column_name || select_for_count)
|
135
|
+
relation.distinct!
|
136
|
+
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
140
137
|
end
|
138
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
139
|
+
relation.order_values = [] if group_values.empty?
|
141
140
|
end
|
142
141
|
|
143
142
|
relation.calculate(operation, column_name)
|
@@ -175,14 +174,14 @@ module ActiveRecord
|
|
175
174
|
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
176
175
|
# # => [2, 3]
|
177
176
|
#
|
178
|
-
# Person.pluck('DATEDIFF(updated_at, created_at)')
|
177
|
+
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
|
179
178
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
180
179
|
# # => ['0', '27761', '173']
|
181
180
|
#
|
182
181
|
# See also #ids.
|
183
182
|
#
|
184
183
|
def pluck(*column_names)
|
185
|
-
if loaded? && (column_names
|
184
|
+
if loaded? && all_attributes?(column_names)
|
186
185
|
return records.pluck(*column_names)
|
187
186
|
end
|
188
187
|
|
@@ -190,14 +189,43 @@ module ActiveRecord
|
|
190
189
|
relation = apply_join_dependency
|
191
190
|
relation.pluck(*column_names)
|
192
191
|
else
|
193
|
-
klass.
|
192
|
+
klass.disallow_raw_sql!(column_names)
|
193
|
+
columns = arel_columns(column_names)
|
194
194
|
relation = spawn
|
195
|
-
relation.select_values =
|
196
|
-
result = skip_query_cache_if_necessary
|
197
|
-
|
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)
|
198
204
|
end
|
199
205
|
end
|
200
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)
|
224
|
+
end
|
225
|
+
|
226
|
+
limit(1).pluck(*column_names).first
|
227
|
+
end
|
228
|
+
|
201
229
|
# Pluck all the ID's for the relation using the table's primary key
|
202
230
|
#
|
203
231
|
# Person.ids # SELECT people.id FROM people
|
@@ -207,6 +235,10 @@ module ActiveRecord
|
|
207
235
|
end
|
208
236
|
|
209
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
|
+
|
210
242
|
def has_include?(column_name)
|
211
243
|
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
212
244
|
end
|
@@ -245,20 +277,16 @@ module ActiveRecord
|
|
245
277
|
def aggregate_column(column_name)
|
246
278
|
return column_name if Arel::Expressions === column_name
|
247
279
|
|
248
|
-
|
249
|
-
|
250
|
-
else
|
251
|
-
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)
|
252
282
|
end
|
253
283
|
end
|
254
284
|
|
255
285
|
def operation_over_aggregate_column(column, operation, distinct)
|
256
|
-
operation == "count" ? column.count(distinct) : column.
|
286
|
+
operation == "count" ? column.count(distinct) : column.public_send(operation)
|
257
287
|
end
|
258
288
|
|
259
289
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
260
|
-
column_alias = column_name
|
261
|
-
|
262
290
|
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
263
291
|
# Shortcut when limit is zero.
|
264
292
|
return 0 if limit_value == 0
|
@@ -269,56 +297,55 @@ module ActiveRecord
|
|
269
297
|
relation = unscope(:order).distinct!(false)
|
270
298
|
|
271
299
|
column = aggregate_column(column_name)
|
272
|
-
|
273
300
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
274
|
-
if operation == "sum" && distinct
|
275
|
-
select_value.distinct = true
|
276
|
-
end
|
301
|
+
select_value.distinct = true if operation == "sum" && distinct
|
277
302
|
|
278
|
-
column_alias = select_value.alias
|
279
|
-
column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
|
280
303
|
relation.select_values = [select_value]
|
281
304
|
|
282
305
|
query_builder = relation.arel
|
283
306
|
end
|
284
307
|
|
285
|
-
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder
|
286
|
-
row = result.first
|
287
|
-
value = row && row.values.first
|
288
|
-
type = result.column_types.fetch(column_alias) do
|
289
|
-
type_for(column_name)
|
290
|
-
end
|
308
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
|
291
309
|
|
292
|
-
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
|
293
315
|
end
|
294
316
|
|
295
317
|
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
296
|
-
|
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
|
297
329
|
|
298
|
-
if
|
299
|
-
association =
|
300
|
-
associated =
|
301
|
-
group_fields = Array(
|
302
|
-
else
|
303
|
-
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
|
304
334
|
end
|
305
335
|
group_fields = arel_columns(group_fields)
|
306
336
|
|
307
|
-
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
|
+
}
|
308
341
|
group_columns = group_aliases.zip(group_fields)
|
309
342
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
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)
|
315
347
|
|
316
|
-
select_values = [
|
317
|
-
operation_over_aggregate_column(
|
318
|
-
aggregate_column(column_name),
|
319
|
-
operation,
|
320
|
-
distinct).as(aggregate_alias)
|
321
|
-
]
|
348
|
+
select_values = [select_value]
|
322
349
|
select_values += self.select_values unless having_clause.empty?
|
323
350
|
|
324
351
|
select_values.concat group_columns.map { |aliaz, field|
|
@@ -338,43 +365,50 @@ module ActiveRecord
|
|
338
365
|
if association
|
339
366
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
340
367
|
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
341
|
-
key_records =
|
368
|
+
key_records = key_records.index_by(&:id)
|
342
369
|
end
|
343
370
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
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] }
|
351
386
|
key = key.first if key.size == 1
|
352
387
|
key = key_records[key] if associated
|
353
388
|
|
354
|
-
|
355
|
-
|
356
|
-
|
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
|
357
395
|
end
|
358
396
|
|
359
|
-
# Converts the given
|
397
|
+
# Converts the given field to the value that the database adapter returns as
|
360
398
|
# a usable column name:
|
361
399
|
#
|
362
400
|
# column_alias_for("users.id") # => "users_id"
|
363
401
|
# column_alias_for("sum(id)") # => "sum_id"
|
364
402
|
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
365
403
|
# column_alias_for("count(*)") # => "count_all"
|
366
|
-
def column_alias_for(
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
table_name.strip!
|
375
|
-
table_name.gsub!(/ +/, "_")
|
376
|
-
|
377
|
-
@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)
|
378
412
|
end
|
379
413
|
|
380
414
|
def type_for(field, &block)
|
@@ -382,12 +416,41 @@ module ActiveRecord
|
|
382
416
|
@klass.type_for_attribute(field_name, &block)
|
383
417
|
end
|
384
418
|
|
385
|
-
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)
|
386
445
|
case operation
|
387
|
-
when "count"
|
388
|
-
|
389
|
-
when "
|
390
|
-
|
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
|
391
454
|
end
|
392
455
|
end
|
393
456
|
|
@@ -402,16 +465,17 @@ module ActiveRecord
|
|
402
465
|
|
403
466
|
def build_count_subquery(relation, column_name, distinct)
|
404
467
|
if column_name == :all
|
468
|
+
column_alias = Arel.star
|
405
469
|
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
406
470
|
else
|
407
471
|
column_alias = Arel.sql("count_column")
|
408
472
|
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
409
473
|
end
|
410
474
|
|
411
|
-
|
412
|
-
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)
|
413
477
|
|
414
|
-
|
478
|
+
relation.build_subquery(subquery_alias, select_value)
|
415
479
|
end
|
416
480
|
end
|
417
481
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "mutex_m"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
5
|
+
|
3
6
|
module ActiveRecord
|
4
7
|
module Delegation # :nodoc:
|
5
8
|
module DelegateCache # :nodoc:
|
@@ -18,7 +21,7 @@ module ActiveRecord
|
|
18
21
|
include ClassSpecificRelation
|
19
22
|
}
|
20
23
|
include_relation_methods(delegate)
|
21
|
-
mangled_name = klass.name.gsub("::"
|
24
|
+
mangled_name = klass.name.gsub("::", "_")
|
22
25
|
const_set mangled_name, delegate
|
23
26
|
private_constant mangled_name
|
24
27
|
|
@@ -31,35 +34,49 @@ module ActiveRecord
|
|
31
34
|
super
|
32
35
|
end
|
33
36
|
|
37
|
+
def generate_relation_method(method)
|
38
|
+
generated_relation_methods.generate_method(method)
|
39
|
+
end
|
40
|
+
|
34
41
|
protected
|
35
42
|
def include_relation_methods(delegate)
|
36
|
-
superclass.include_relation_methods(delegate) unless base_class
|
43
|
+
superclass.include_relation_methods(delegate) unless base_class?
|
37
44
|
delegate.include generated_relation_methods
|
38
45
|
end
|
39
46
|
|
40
47
|
private
|
41
48
|
def generated_relation_methods
|
42
|
-
@generated_relation_methods ||=
|
43
|
-
|
44
|
-
|
45
|
-
private_constant mod_name
|
49
|
+
@generated_relation_methods ||= GeneratedRelationMethods.new.tap do |mod|
|
50
|
+
const_set(:GeneratedRelationMethods, mod)
|
51
|
+
private_constant :GeneratedRelationMethods
|
46
52
|
end
|
47
53
|
end
|
54
|
+
end
|
48
55
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
class GeneratedRelationMethods < Module # :nodoc:
|
57
|
+
include Mutex_m
|
58
|
+
|
59
|
+
def generate_method(method)
|
60
|
+
synchronize do
|
61
|
+
return if method_defined?(method)
|
62
|
+
|
63
|
+
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
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
66
|
+
def #{method}(#{definition})
|
67
|
+
scoping { klass.#{method}(#{definition}) }
|
54
68
|
end
|
55
69
|
RUBY
|
56
70
|
else
|
57
|
-
|
71
|
+
define_method(method) do |*args, &block|
|
58
72
|
scoping { klass.public_send(method, *args, &block) }
|
59
73
|
end
|
74
|
+
ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
|
60
75
|
end
|
61
76
|
end
|
77
|
+
end
|
62
78
|
end
|
79
|
+
private_constant :GeneratedRelationMethods
|
63
80
|
|
64
81
|
extend ActiveSupport::Concern
|
65
82
|
|
@@ -68,7 +85,7 @@ module ActiveRecord
|
|
68
85
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
69
86
|
# for each different klass, and the delegations are compiled into that subclass only.
|
70
87
|
|
71
|
-
delegate :to_xml, :encode_with, :length, :each, :
|
88
|
+
delegate :to_xml, :encode_with, :length, :each, :join,
|
72
89
|
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
73
90
|
:to_sentence, :to_formatted_s, :as_json,
|
74
91
|
:shuffle, :split, :slice, :index, :rindex, to: :records
|
@@ -78,62 +95,30 @@ module ActiveRecord
|
|
78
95
|
module ClassSpecificRelation # :nodoc:
|
79
96
|
extend ActiveSupport::Concern
|
80
97
|
|
81
|
-
included do
|
82
|
-
@delegation_mutex = Mutex.new
|
83
|
-
end
|
84
|
-
|
85
98
|
module ClassMethods # :nodoc:
|
86
99
|
def name
|
87
100
|
superclass.name
|
88
101
|
end
|
89
|
-
|
90
|
-
def delegate_to_scoped_klass(method)
|
91
|
-
@delegation_mutex.synchronize do
|
92
|
-
return if method_defined?(method)
|
93
|
-
|
94
|
-
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
|
95
|
-
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
96
|
-
def #{method}(*args, &block)
|
97
|
-
scoping { @klass.#{method}(*args, &block) }
|
98
|
-
end
|
99
|
-
RUBY
|
100
|
-
else
|
101
|
-
define_method method do |*args, &block|
|
102
|
-
scoping { @klass.public_send(method, *args, &block) }
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
102
|
end
|
108
103
|
|
109
104
|
private
|
110
|
-
|
111
105
|
def method_missing(method, *args, &block)
|
112
106
|
if @klass.respond_to?(method)
|
113
|
-
|
107
|
+
@klass.generate_relation_method(method)
|
114
108
|
scoping { @klass.public_send(method, *args, &block) }
|
115
|
-
elsif @delegate_to_klass && @klass.respond_to?(method, true)
|
116
|
-
ActiveSupport::Deprecation.warn \
|
117
|
-
"Delegating missing #{method} method to #{@klass}. " \
|
118
|
-
"Accessibility of private/protected class methods in :scope is deprecated and will be removed in Rails 6.0."
|
119
|
-
@klass.send(method, *args, &block)
|
120
|
-
elsif arel.respond_to?(method)
|
121
|
-
ActiveSupport::Deprecation.warn \
|
122
|
-
"Delegating #{method} to arel is deprecated and will be removed in Rails 6.0."
|
123
|
-
arel.public_send(method, *args, &block)
|
124
109
|
else
|
125
110
|
super
|
126
111
|
end
|
127
112
|
end
|
113
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
128
114
|
end
|
129
115
|
|
130
116
|
module ClassMethods # :nodoc:
|
131
|
-
def create(klass, *args)
|
132
|
-
relation_class_for(klass).new(klass, *args)
|
117
|
+
def create(klass, *args, **kwargs)
|
118
|
+
relation_class_for(klass).new(klass, *args, **kwargs)
|
133
119
|
end
|
134
120
|
|
135
121
|
private
|
136
|
-
|
137
122
|
def relation_class_for(klass)
|
138
123
|
klass.relation_delegate_class(self)
|
139
124
|
end
|
@@ -141,7 +126,7 @@ module ActiveRecord
|
|
141
126
|
|
142
127
|
private
|
143
128
|
def respond_to_missing?(method, _)
|
144
|
-
super || @klass.respond_to?(method)
|
129
|
+
super || @klass.respond_to?(method)
|
145
130
|
end
|
146
131
|
end
|
147
132
|
end
|