activerecord 5.2.6 → 6.0.5.1
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 +956 -559
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +55 -19
- data/lib/active_record/associations/association_scope.rb +11 -7
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +19 -23
- data/lib/active_record/associations/collection_proxy.rb +14 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
- data/lib/active_record/associations/join_dependency.rb +47 -30
- data/lib/active_record/associations/preloader/association.rb +61 -41
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +44 -33
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +12 -14
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -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 +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- 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/date_time.rb +8 -0
- 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/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- 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 +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- 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 +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +117 -66
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +44 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/fixture_set/model_metadata.rb +33 -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 +144 -474
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +14 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/model_schema.rb +62 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +95 -40
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +51 -51
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +55 -49
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +12 -17
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +5 -11
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +232 -69
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +326 -81
- data/lib/active_record/result.rb +30 -12
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +6 -2
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +25 -16
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- 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 +0 -1
- 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 +3 -5
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/associated.rb +0 -1
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +10 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -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 +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -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 +18 -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 +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -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 +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -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 +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -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 +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -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 +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/migration.rb +14 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +116 -29
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -41,15 +41,13 @@ module ActiveRecord
|
|
41
41
|
def count(column_name = nil)
|
42
42
|
if block_given?
|
43
43
|
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."
|
44
|
+
raise ArgumentError, "Column name argument is not supported when a block is passed."
|
47
45
|
end
|
48
46
|
|
49
|
-
|
47
|
+
super()
|
48
|
+
else
|
49
|
+
calculate(:count, column_name)
|
50
50
|
end
|
51
|
-
|
52
|
-
calculate(:count, column_name)
|
53
51
|
end
|
54
52
|
|
55
53
|
# Calculates the average value on a given column. Returns +nil+ if there's
|
@@ -86,15 +84,13 @@ module ActiveRecord
|
|
86
84
|
def sum(column_name = nil)
|
87
85
|
if block_given?
|
88
86
|
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."
|
87
|
+
raise ArgumentError, "Column name argument is not supported when a block is passed."
|
92
88
|
end
|
93
89
|
|
94
|
-
|
90
|
+
super()
|
91
|
+
else
|
92
|
+
calculate(:sum, column_name)
|
95
93
|
end
|
96
|
-
|
97
|
-
calculate(:sum, column_name)
|
98
94
|
end
|
99
95
|
|
100
96
|
# This calculates aggregate values in the given column. Methods for #count, #sum, #average,
|
@@ -138,7 +134,7 @@ module ActiveRecord
|
|
138
134
|
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
139
135
|
end
|
140
136
|
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
141
|
-
relation.order_values = []
|
137
|
+
relation.order_values = [] if group_values.empty?
|
142
138
|
end
|
143
139
|
|
144
140
|
relation.calculate(operation, column_name)
|
@@ -176,7 +172,7 @@ module ActiveRecord
|
|
176
172
|
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
177
173
|
# # => [2, 3]
|
178
174
|
#
|
179
|
-
# Person.pluck('DATEDIFF(updated_at, created_at)')
|
175
|
+
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
|
180
176
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
181
177
|
# # => ['0', '27761', '173']
|
182
178
|
#
|
@@ -191,7 +187,7 @@ module ActiveRecord
|
|
191
187
|
relation = apply_join_dependency
|
192
188
|
relation.pluck(*column_names)
|
193
189
|
else
|
194
|
-
klass.
|
190
|
+
klass.disallow_raw_sql!(column_names)
|
195
191
|
relation = spawn
|
196
192
|
relation.select_values = column_names
|
197
193
|
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
@@ -199,6 +195,24 @@ module ActiveRecord
|
|
199
195
|
end
|
200
196
|
end
|
201
197
|
|
198
|
+
# Pick the value(s) from the named column(s) in the current relation.
|
199
|
+
# This is short-hand for <tt>relation.limit(1).pluck(*column_names).first</tt>, and is primarily useful
|
200
|
+
# when you have a relation that's already narrowed down to a single row.
|
201
|
+
#
|
202
|
+
# Just like #pluck, #pick will only load the actual value, not the entire record object, so it's also
|
203
|
+
# more efficient. The value is, again like with pluck, typecast by the column type.
|
204
|
+
#
|
205
|
+
# Person.where(id: 1).pick(:name)
|
206
|
+
# # SELECT people.name FROM people WHERE id = 1 LIMIT 1
|
207
|
+
# # => 'David'
|
208
|
+
#
|
209
|
+
# Person.where(id: 1).pick(:name, :email_address)
|
210
|
+
# # SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
|
211
|
+
# # => [ 'David', 'david@loudthinking.com' ]
|
212
|
+
def pick(*column_names)
|
213
|
+
limit(1).pluck(*column_names).first
|
214
|
+
end
|
215
|
+
|
202
216
|
# Pluck all the ID's for the relation using the table's primary key
|
203
217
|
#
|
204
218
|
# Person.ids # SELECT people.id FROM people
|
@@ -246,10 +260,8 @@ module ActiveRecord
|
|
246
260
|
def aggregate_column(column_name)
|
247
261
|
return column_name if Arel::Expressions === column_name
|
248
262
|
|
249
|
-
|
250
|
-
|
251
|
-
else
|
252
|
-
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
263
|
+
arel_column(column_name.to_s) do |name|
|
264
|
+
Arel.sql(column_name == :all ? "*" : name)
|
253
265
|
end
|
254
266
|
end
|
255
267
|
|
@@ -294,25 +306,22 @@ module ActiveRecord
|
|
294
306
|
end
|
295
307
|
|
296
308
|
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
297
|
-
|
309
|
+
group_fields = group_values
|
298
310
|
|
299
|
-
if
|
300
|
-
association =
|
301
|
-
associated =
|
302
|
-
group_fields = Array(
|
303
|
-
else
|
304
|
-
group_fields = group_attrs
|
311
|
+
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
312
|
+
association = klass._reflect_on_association(group_fields.first)
|
313
|
+
associated = association && association.belongs_to? # only count belongs_to associations
|
314
|
+
group_fields = Array(association.foreign_key) if associated
|
305
315
|
end
|
306
316
|
group_fields = arel_columns(group_fields)
|
307
317
|
|
308
|
-
group_aliases = group_fields.map { |field|
|
318
|
+
group_aliases = group_fields.map { |field|
|
319
|
+
field = connection.visitor.compile(field) if Arel.arel_node?(field)
|
320
|
+
column_alias_for(field.to_s.downcase)
|
321
|
+
}
|
309
322
|
group_columns = group_aliases.zip(group_fields)
|
310
323
|
|
311
|
-
|
312
|
-
aggregate_alias = "count_all"
|
313
|
-
else
|
314
|
-
aggregate_alias = column_alias_for([operation, column_name].join(" "))
|
315
|
-
end
|
324
|
+
aggregate_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
|
316
325
|
|
317
326
|
select_values = [
|
318
327
|
operation_over_aggregate_column(
|
@@ -357,25 +366,21 @@ module ActiveRecord
|
|
357
366
|
end]
|
358
367
|
end
|
359
368
|
|
360
|
-
# Converts the given
|
369
|
+
# Converts the given field to the value that the database adapter returns as
|
361
370
|
# a usable column name:
|
362
371
|
#
|
363
372
|
# column_alias_for("users.id") # => "users_id"
|
364
373
|
# column_alias_for("sum(id)") # => "sum_id"
|
365
374
|
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
366
375
|
# 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)
|
376
|
+
def column_alias_for(field)
|
377
|
+
column_alias = +field
|
378
|
+
column_alias.gsub!(/\*/, "all")
|
379
|
+
column_alias.gsub!(/\W+/, " ")
|
380
|
+
column_alias.strip!
|
381
|
+
column_alias.gsub!(/ +/, "_")
|
382
|
+
|
383
|
+
connection.table_alias_for(column_alias)
|
379
384
|
end
|
380
385
|
|
381
386
|
def type_for(field, &block)
|
@@ -387,7 +392,7 @@ module ActiveRecord
|
|
387
392
|
case operation
|
388
393
|
when "count" then value.to_i
|
389
394
|
when "sum" then type.deserialize(value || 0)
|
390
|
-
when "average" then value
|
395
|
+
when "average" then value&.respond_to?(:to_d) ? value.to_d : value
|
391
396
|
else type.deserialize(value)
|
392
397
|
end
|
393
398
|
end
|
@@ -403,16 +408,17 @@ module ActiveRecord
|
|
403
408
|
|
404
409
|
def build_count_subquery(relation, column_name, distinct)
|
405
410
|
if column_name == :all
|
411
|
+
column_alias = Arel.star
|
406
412
|
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
407
413
|
else
|
408
414
|
column_alias = Arel.sql("count_column")
|
409
415
|
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
410
416
|
end
|
411
417
|
|
412
|
-
|
413
|
-
select_value = operation_over_aggregate_column(column_alias
|
418
|
+
subquery_alias = Arel.sql("subquery_for_count")
|
419
|
+
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
414
420
|
|
415
|
-
|
421
|
+
relation.build_subquery(subquery_alias, select_value)
|
416
422
|
end
|
417
423
|
end
|
418
424
|
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
|
@@ -7,8 +7,8 @@ module ActiveRecord
|
|
7
7
|
ONE_AS_ONE = "1 AS one"
|
8
8
|
|
9
9
|
# Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
|
10
|
-
# If one or more records
|
11
|
-
# is an integer, find by id coerces its arguments using +to_i+.
|
10
|
+
# If one or more records cannot be found for the requested ids, then ActiveRecord::RecordNotFound will be raised.
|
11
|
+
# If the primary key is an integer, find by id coerces its arguments by using +to_i+.
|
12
12
|
#
|
13
13
|
# Person.find(1) # returns the object for ID = 1
|
14
14
|
# Person.find("1") # returns the object for ID = 1
|
@@ -79,17 +79,12 @@ module ActiveRecord
|
|
79
79
|
# Post.find_by "published_at < ?", 2.weeks.ago
|
80
80
|
def find_by(arg, *args)
|
81
81
|
where(arg, *args).take
|
82
|
-
rescue ::RangeError
|
83
|
-
nil
|
84
82
|
end
|
85
83
|
|
86
84
|
# Like #find_by, except that if no record is found, raises
|
87
85
|
# an ActiveRecord::RecordNotFound error.
|
88
86
|
def find_by!(arg, *args)
|
89
87
|
where(arg, *args).take!
|
90
|
-
rescue ::RangeError
|
91
|
-
raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
|
92
|
-
@klass.name, @klass.primary_key)
|
93
88
|
end
|
94
89
|
|
95
90
|
# Gives a record (or N records if a parameter is supplied) without any implied
|
@@ -319,9 +314,7 @@ module ActiveRecord
|
|
319
314
|
|
320
315
|
relation = construct_relation_for_exists(conditions)
|
321
316
|
|
322
|
-
skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists") } ? true : false
|
323
|
-
rescue ::RangeError
|
324
|
-
false
|
317
|
+
skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists?") } ? true : false
|
325
318
|
end
|
326
319
|
|
327
320
|
# This method is called whenever no records are found with either a single
|
@@ -338,14 +331,14 @@ module ActiveRecord
|
|
338
331
|
name = @klass.name
|
339
332
|
|
340
333
|
if ids.nil?
|
341
|
-
error = "Couldn't find #{name}"
|
334
|
+
error = +"Couldn't find #{name}"
|
342
335
|
error << " with#{conditions}" if conditions
|
343
336
|
raise RecordNotFound.new(error, name, key)
|
344
337
|
elsif Array(ids).size == 1
|
345
338
|
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
346
339
|
raise RecordNotFound.new(error, name, key, ids)
|
347
340
|
else
|
348
|
-
error = "Couldn't find all #{name.pluralize} with '#{key}': "
|
341
|
+
error = +"Couldn't find all #{name.pluralize} with '#{key}': "
|
349
342
|
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
350
343
|
error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
|
351
344
|
raise RecordNotFound.new(error, name, key, ids)
|
@@ -353,12 +346,13 @@ module ActiveRecord
|
|
353
346
|
end
|
354
347
|
|
355
348
|
private
|
356
|
-
|
357
349
|
def offset_index
|
358
350
|
offset_value || 0
|
359
351
|
end
|
360
352
|
|
361
353
|
def construct_relation_for_exists(conditions)
|
354
|
+
conditions = sanitize_forbidden_attributes(conditions)
|
355
|
+
|
362
356
|
if distinct_value && offset_value
|
363
357
|
relation = except(:order).limit!(1)
|
364
358
|
else
|
@@ -375,18 +369,22 @@ module ActiveRecord
|
|
375
369
|
relation
|
376
370
|
end
|
377
371
|
|
378
|
-
def construct_join_dependency
|
379
|
-
including = eager_load_values + includes_values
|
380
|
-
ActiveRecord::Associations::JoinDependency.new(
|
381
|
-
klass, table, including
|
382
|
-
)
|
383
|
-
end
|
384
|
-
|
385
372
|
def apply_join_dependency(eager_loading: group_values.empty?)
|
386
|
-
join_dependency = construct_join_dependency
|
373
|
+
join_dependency = construct_join_dependency(
|
374
|
+
eager_load_values | includes_values, Arel::Nodes::OuterJoin
|
375
|
+
)
|
387
376
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
388
377
|
|
389
|
-
if eager_loading && !
|
378
|
+
if eager_loading && !(
|
379
|
+
using_limitable_reflections?(join_dependency.reflections) &&
|
380
|
+
using_limitable_reflections?(
|
381
|
+
construct_join_dependency(
|
382
|
+
select_association_list(joins_values).concat(
|
383
|
+
select_association_list(left_outer_joins_values)
|
384
|
+
), nil
|
385
|
+
).reflections
|
386
|
+
)
|
387
|
+
)
|
390
388
|
if has_limit_or_offset?
|
391
389
|
limited_ids = limited_ids_for(relation)
|
392
390
|
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
@@ -403,7 +401,7 @@ module ActiveRecord
|
|
403
401
|
|
404
402
|
def limited_ids_for(relation)
|
405
403
|
values = @klass.connection.columns_for_distinct(
|
406
|
-
connection.
|
404
|
+
connection.visitor.compile(arel_attribute(primary_key)),
|
407
405
|
relation.order_values
|
408
406
|
)
|
409
407
|
|
@@ -437,9 +435,6 @@ module ActiveRecord
|
|
437
435
|
else
|
438
436
|
find_some(ids)
|
439
437
|
end
|
440
|
-
rescue ::RangeError
|
441
|
-
error_message = "Couldn't find #{model_name} with an out of range ID"
|
442
|
-
raise RecordNotFound.new(error_message, model_name, primary_key, ids)
|
443
438
|
end
|
444
439
|
|
445
440
|
def find_one(id)
|
@@ -555,8 +550,8 @@ module ActiveRecord
|
|
555
550
|
end
|
556
551
|
|
557
552
|
def ordered_relation
|
558
|
-
if order_values.empty? && primary_key
|
559
|
-
order(arel_attribute(primary_key).asc)
|
553
|
+
if order_values.empty? && (implicit_order_column || primary_key)
|
554
|
+
order(arel_attribute(implicit_order_column || primary_key).asc)
|
560
555
|
else
|
561
556
|
self
|
562
557
|
end
|
@@ -89,7 +89,6 @@ module ActiveRecord
|
|
89
89
|
end
|
90
90
|
|
91
91
|
private
|
92
|
-
|
93
92
|
def merge_preloads
|
94
93
|
return if other.preload_values.empty? && other.includes_values.empty?
|
95
94
|
|
@@ -117,18 +116,16 @@ module ActiveRecord
|
|
117
116
|
if other.klass == relation.klass
|
118
117
|
relation.joins!(*other.joins_values)
|
119
118
|
else
|
120
|
-
|
119
|
+
associations, others = other.joins_values.partition do |join|
|
121
120
|
case join
|
122
|
-
when Hash, Symbol, Array
|
123
|
-
ActiveRecord::Associations::JoinDependency.new(
|
124
|
-
other.klass, other.table, join
|
125
|
-
)
|
126
|
-
else
|
127
|
-
join
|
121
|
+
when Hash, Symbol, Array; true
|
128
122
|
end
|
129
123
|
end
|
130
124
|
|
131
|
-
|
125
|
+
join_dependency = other.construct_join_dependency(
|
126
|
+
associations, Arel::Nodes::InnerJoin
|
127
|
+
)
|
128
|
+
relation.joins!(join_dependency, *others)
|
132
129
|
end
|
133
130
|
end
|
134
131
|
|
@@ -138,18 +135,16 @@ module ActiveRecord
|
|
138
135
|
if other.klass == relation.klass
|
139
136
|
relation.left_outer_joins!(*other.left_outer_joins_values)
|
140
137
|
else
|
141
|
-
|
138
|
+
associations, others = other.left_outer_joins_values.partition do |join|
|
142
139
|
case join
|
143
|
-
when Hash, Symbol, Array
|
144
|
-
ActiveRecord::Associations::JoinDependency.new(
|
145
|
-
other.klass, other.table, join
|
146
|
-
)
|
147
|
-
else
|
148
|
-
join
|
140
|
+
when Hash, Symbol, Array; true
|
149
141
|
end
|
150
142
|
end
|
151
143
|
|
152
|
-
|
144
|
+
join_dependency = other.construct_join_dependency(
|
145
|
+
associations, Arel::Nodes::OuterJoin
|
146
|
+
)
|
147
|
+
relation.left_outer_joins!(join_dependency, *others)
|
153
148
|
end
|
154
149
|
end
|
155
150
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/array/extract"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
class PredicateBuilder
|
5
7
|
class ArrayHandler # :nodoc:
|
@@ -11,8 +13,8 @@ module ActiveRecord
|
|
11
13
|
return attribute.in([]) if value.empty?
|
12
14
|
|
13
15
|
values = value.map { |x| x.is_a?(Base) ? x.id : x }
|
14
|
-
nils
|
15
|
-
ranges
|
16
|
+
nils = values.extract!(&:nil?)
|
17
|
+
ranges = values.extract! { |v| v.is_a?(Range) }
|
16
18
|
|
17
19
|
values_predicate =
|
18
20
|
case values.length
|
@@ -34,8 +36,7 @@ module ActiveRecord
|
|
34
36
|
array_predicates.inject(&:or)
|
35
37
|
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
private
|
39
40
|
attr_reader :predicate_builder
|
40
41
|
|
41
42
|
module NullPredicate # :nodoc:
|
@@ -12,12 +12,9 @@ module ActiveRecord
|
|
12
12
|
[associated_table.association_join_foreign_key.to_s => ids]
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
17
|
-
protected
|
15
|
+
private
|
18
16
|
attr_reader :associated_table, :value
|
19
17
|
|
20
|
-
private
|
21
18
|
def ids
|
22
19
|
case value
|
23
20
|
when Relation
|
@@ -17,12 +17,9 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
22
|
-
protected
|
20
|
+
private
|
23
21
|
attr_reader :associated_table, :values
|
24
22
|
|
25
|
-
private
|
26
23
|
def type_to_ids_mapping
|
27
24
|
default_hash = Hash.new { |hsh, key| hsh[key] = [] }
|
28
25
|
values.each_with_object(default_hash) do |value, hash|
|