activerecord 5.1.7 → 5.2.8.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 +629 -661
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +41 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +27 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +12 -4
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +59 -47
- data/lib/active_record/associations/collection_proxy.rb +20 -49
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +12 -1
- data/lib/active_record/associations/has_many_through_association.rb +36 -30
- data/lib/active_record/associations/has_one_association.rb +12 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/join_dependency.rb +48 -93
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +18 -38
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +40 -63
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +30 -214
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +6 -5
- data/lib/active_record/autosave_association.rb +35 -19
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +15 -1
- data/lib/active_record/collection_cache_key.rb +12 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +233 -111
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +51 -61
- data/lib/active_record/counter_cache.rb +10 -3
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +42 -3
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +14 -17
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +47 -9
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +16 -21
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +167 -16
- data/lib/active_record/query_cache.rb +6 -8
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +80 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +108 -194
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +45 -19
- data/lib/active_record/relation/delegation.rb +45 -27
- data/lib/active_record/relation/finder_methods.rb +75 -76
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +128 -99
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +120 -214
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +8 -9
- data/lib/active_record/scoping/named.rb +23 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +23 -13
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +25 -14
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +33 -28
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +2 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +35 -5
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +26 -39
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -122
- data/lib/active_record/attribute_set/builder.rb +0 -126
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Calculations
|
3
5
|
# Count the records.
|
@@ -37,7 +39,16 @@ module ActiveRecord
|
|
37
39
|
# Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
|
38
40
|
# between databases. In invalid cases, an error from the database is thrown.
|
39
41
|
def count(column_name = nil)
|
40
|
-
|
42
|
+
if block_given?
|
43
|
+
unless column_name.nil?
|
44
|
+
ActiveSupport::Deprecation.warn \
|
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."
|
47
|
+
end
|
48
|
+
|
49
|
+
return super()
|
50
|
+
end
|
51
|
+
|
41
52
|
calculate(:count, column_name)
|
42
53
|
end
|
43
54
|
|
@@ -73,7 +84,16 @@ module ActiveRecord
|
|
73
84
|
#
|
74
85
|
# Person.sum(:age) # => 4562
|
75
86
|
def sum(column_name = nil)
|
76
|
-
|
87
|
+
if block_given?
|
88
|
+
unless column_name.nil?
|
89
|
+
ActiveSupport::Deprecation.warn \
|
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."
|
92
|
+
end
|
93
|
+
|
94
|
+
return super()
|
95
|
+
end
|
96
|
+
|
77
97
|
calculate(:sum, column_name)
|
78
98
|
end
|
79
99
|
|
@@ -110,14 +130,15 @@ module ActiveRecord
|
|
110
130
|
# end
|
111
131
|
def calculate(operation, column_name)
|
112
132
|
if has_include?(column_name)
|
113
|
-
relation =
|
133
|
+
relation = apply_join_dependency
|
114
134
|
|
115
135
|
if operation.to_s.downcase == "count"
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
relation.order_values = []
|
136
|
+
unless distinct_value || distinct_select?(column_name || select_for_count)
|
137
|
+
relation.distinct!
|
138
|
+
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
120
139
|
end
|
140
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
141
|
+
relation.order_values = []
|
121
142
|
end
|
122
143
|
|
123
144
|
relation.calculate(operation, column_name)
|
@@ -167,13 +188,13 @@ module ActiveRecord
|
|
167
188
|
end
|
168
189
|
|
169
190
|
if has_include?(column_names.first)
|
170
|
-
|
191
|
+
relation = apply_join_dependency
|
192
|
+
relation.pluck(*column_names)
|
171
193
|
else
|
194
|
+
klass.enforce_raw_sql_whitelist(column_names)
|
172
195
|
relation = spawn
|
173
|
-
relation.select_values = column_names
|
174
|
-
|
175
|
-
}
|
176
|
-
result = klass.connection.select_all(relation.arel, nil, bound_attributes)
|
196
|
+
relation.select_values = column_names
|
197
|
+
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
177
198
|
result.cast_values(klass.attribute_types)
|
178
199
|
end
|
179
200
|
end
|
@@ -187,7 +208,6 @@ module ActiveRecord
|
|
187
208
|
end
|
188
209
|
|
189
210
|
private
|
190
|
-
|
191
211
|
def has_include?(column_name)
|
192
212
|
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
193
213
|
end
|
@@ -202,10 +222,12 @@ module ActiveRecord
|
|
202
222
|
if operation == "count"
|
203
223
|
column_name ||= select_for_count
|
204
224
|
if column_name == :all
|
205
|
-
if distinct
|
225
|
+
if !distinct
|
226
|
+
distinct = distinct_select?(select_for_count) if group_values.empty?
|
227
|
+
elsif group_values.any? || select_values.empty? && order_values.empty?
|
206
228
|
column_name = primary_key
|
207
229
|
end
|
208
|
-
elsif column_name
|
230
|
+
elsif distinct_select?(column_name)
|
209
231
|
distinct = nil
|
210
232
|
end
|
211
233
|
end
|
@@ -217,10 +239,14 @@ module ActiveRecord
|
|
217
239
|
end
|
218
240
|
end
|
219
241
|
|
242
|
+
def distinct_select?(column_name)
|
243
|
+
column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
|
244
|
+
end
|
245
|
+
|
220
246
|
def aggregate_column(column_name)
|
221
247
|
return column_name if Arel::Expressions === column_name
|
222
248
|
|
223
|
-
if @klass.has_attribute?(column_name
|
249
|
+
if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
|
224
250
|
@klass.arel_attribute(column_name)
|
225
251
|
else
|
226
252
|
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
@@ -257,7 +283,7 @@ module ActiveRecord
|
|
257
283
|
query_builder = relation.arel
|
258
284
|
end
|
259
285
|
|
260
|
-
result = @klass.connection.select_all(query_builder, nil
|
286
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
|
261
287
|
row = result.first
|
262
288
|
value = row && row.values.first
|
263
289
|
type = result.column_types.fetch(column_alias) do
|
@@ -308,7 +334,7 @@ module ActiveRecord
|
|
308
334
|
relation.group_values = group_fields
|
309
335
|
relation.select_values = select_values
|
310
336
|
|
311
|
-
calculated_data = @klass.connection.select_all(relation, nil
|
337
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
|
312
338
|
|
313
339
|
if association
|
314
340
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
@@ -361,7 +387,7 @@ module ActiveRecord
|
|
361
387
|
case operation
|
362
388
|
when "count" then value.to_i
|
363
389
|
when "sum" then type.deserialize(value || 0)
|
364
|
-
when "average" then value.respond_to?(:to_d) ? value.to_d : value
|
390
|
+
when "average" then value && value.respond_to?(:to_d) ? value.to_d : value
|
365
391
|
else type.deserialize(value)
|
366
392
|
end
|
367
393
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Delegation # :nodoc:
|
3
5
|
module DelegateCache # :nodoc:
|
@@ -15,6 +17,7 @@ module ActiveRecord
|
|
15
17
|
delegate = Class.new(klass) {
|
16
18
|
include ClassSpecificRelation
|
17
19
|
}
|
20
|
+
include_relation_methods(delegate)
|
18
21
|
mangled_name = klass.name.gsub("::".freeze, "_".freeze)
|
19
22
|
const_set mangled_name, delegate
|
20
23
|
private_constant mangled_name
|
@@ -27,6 +30,35 @@ module ActiveRecord
|
|
27
30
|
child_class.initialize_relation_delegate_cache
|
28
31
|
super
|
29
32
|
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def include_relation_methods(delegate)
|
36
|
+
superclass.include_relation_methods(delegate) unless base_class == self
|
37
|
+
delegate.include generated_relation_methods
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def generated_relation_methods
|
42
|
+
@generated_relation_methods ||= Module.new.tap do |mod|
|
43
|
+
mod_name = "GeneratedRelationMethods"
|
44
|
+
const_set mod_name, mod
|
45
|
+
private_constant mod_name
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_relation_method(method)
|
50
|
+
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
|
51
|
+
generated_relation_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
52
|
+
def #{method}(*args, &block)
|
53
|
+
scoping { klass.#{method}(*args, &block) }
|
54
|
+
end
|
55
|
+
RUBY
|
56
|
+
else
|
57
|
+
generated_relation_methods.send(:define_method, method) do |*args, &block|
|
58
|
+
scoping { klass.public_send(method, *args, &block) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
30
62
|
end
|
31
63
|
|
32
64
|
extend ActiveSupport::Concern
|
@@ -36,13 +68,12 @@ module ActiveRecord
|
|
36
68
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
37
69
|
# for each different klass, and the delegations are compiled into that subclass only.
|
38
70
|
|
39
|
-
delegate :to_xml, :encode_with, :length, :each, :uniq, :
|
40
|
-
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
71
|
+
delegate :to_xml, :encode_with, :length, :each, :uniq, :join,
|
72
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
41
73
|
:to_sentence, :to_formatted_s, :as_json,
|
42
|
-
:shuffle, :split, :index, to: :records
|
74
|
+
:shuffle, :split, :slice, :index, :rindex, to: :records
|
43
75
|
|
44
|
-
delegate :
|
45
|
-
:connection, :columns_hash, to: :klass
|
76
|
+
delegate :primary_key, :connection, to: :klass
|
46
77
|
|
47
78
|
module ClassSpecificRelation # :nodoc:
|
48
79
|
extend ActiveSupport::Concern
|
@@ -73,13 +104,6 @@ module ActiveRecord
|
|
73
104
|
end
|
74
105
|
end
|
75
106
|
end
|
76
|
-
|
77
|
-
def delegate(method, opts = {})
|
78
|
-
@delegation_mutex.synchronize do
|
79
|
-
return if method_defined?(method)
|
80
|
-
super
|
81
|
-
end
|
82
|
-
end
|
83
107
|
end
|
84
108
|
|
85
109
|
private
|
@@ -88,8 +112,14 @@ module ActiveRecord
|
|
88
112
|
if @klass.respond_to?(method)
|
89
113
|
self.class.delegate_to_scoped_klass(method)
|
90
114
|
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)
|
91
120
|
elsif arel.respond_to?(method)
|
92
|
-
|
121
|
+
ActiveSupport::Deprecation.warn \
|
122
|
+
"Delegating #{method} to arel is deprecated and will be removed in Rails 6.0."
|
93
123
|
arel.public_send(method, *args, &block)
|
94
124
|
else
|
95
125
|
super
|
@@ -109,21 +139,9 @@ module ActiveRecord
|
|
109
139
|
end
|
110
140
|
end
|
111
141
|
|
112
|
-
def respond_to_missing?(method, include_private = false)
|
113
|
-
super || @klass.respond_to?(method, include_private) ||
|
114
|
-
arel.respond_to?(method, include_private)
|
115
|
-
end
|
116
|
-
|
117
142
|
private
|
118
|
-
|
119
|
-
|
120
|
-
if @klass.respond_to?(method)
|
121
|
-
scoping { @klass.public_send(method, *args, &block) }
|
122
|
-
elsif arel.respond_to?(method)
|
123
|
-
arel.public_send(method, *args, &block)
|
124
|
-
else
|
125
|
-
super
|
126
|
-
end
|
143
|
+
def respond_to_missing?(method, _)
|
144
|
+
super || @klass.respond_to?(method) || arel.respond_to?(method)
|
127
145
|
end
|
128
146
|
end
|
129
147
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/string/filters"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -16,9 +18,10 @@ module ActiveRecord
|
|
16
18
|
# Person.find([1]) # returns an array for the object with ID = 1
|
17
19
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
18
20
|
#
|
19
|
-
# NOTE: The returned records
|
20
|
-
#
|
21
|
-
#
|
21
|
+
# NOTE: The returned records are in the same order as the ids you provide.
|
22
|
+
# If you want the results to be sorted by database, you can use ActiveRecord::QueryMethods#where
|
23
|
+
# method and provide an explicit ActiveRecord::QueryMethods#order option.
|
24
|
+
# But ActiveRecord::QueryMethods#where method doesn't raise ActiveRecord::RecordNotFound.
|
22
25
|
#
|
23
26
|
# ==== Find with lock
|
24
27
|
#
|
@@ -86,7 +89,7 @@ module ActiveRecord
|
|
86
89
|
where(arg, *args).take!
|
87
90
|
rescue ::RangeError
|
88
91
|
raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
|
89
|
-
@klass.name)
|
92
|
+
@klass.name, @klass.primary_key)
|
90
93
|
end
|
91
94
|
|
92
95
|
# Gives a record (or N records if a parameter is supplied) without any implied
|
@@ -145,10 +148,9 @@ module ActiveRecord
|
|
145
148
|
#
|
146
149
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
147
150
|
def last(limit = nil)
|
148
|
-
return find_last(limit) if loaded? ||
|
151
|
+
return find_last(limit) if loaded? || has_limit_or_offset?
|
149
152
|
|
150
|
-
result = limit(limit)
|
151
|
-
result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
|
153
|
+
result = ordered_relation.limit(limit)
|
152
154
|
result = result.reverse_order!
|
153
155
|
|
154
156
|
limit ? result.reverse : result.first
|
@@ -283,7 +285,7 @@ module ActiveRecord
|
|
283
285
|
# * Hash - Finds the record that matches these +find+-style conditions
|
284
286
|
# (such as <tt>{name: 'David'}</tt>).
|
285
287
|
# * +false+ - Returns always +false+.
|
286
|
-
# * No args - Returns +false+ if the
|
288
|
+
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
287
289
|
#
|
288
290
|
# For more information about specifying conditions as a hash or array,
|
289
291
|
# see the Conditions section in the introduction to ActiveRecord::Base.
|
@@ -299,6 +301,7 @@ module ActiveRecord
|
|
299
301
|
# Person.exists?(name: 'David')
|
300
302
|
# Person.exists?(false)
|
301
303
|
# Person.exists?
|
304
|
+
# Person.where(name: 'Spartacus', rating: 4).exists?
|
302
305
|
def exists?(conditions = :none)
|
303
306
|
if Base === conditions
|
304
307
|
raise ArgumentError, <<-MSG.squish
|
@@ -309,14 +312,14 @@ module ActiveRecord
|
|
309
312
|
|
310
313
|
return false if !conditions || limit_value == 0
|
311
314
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
315
|
+
if eager_loading?
|
316
|
+
relation = apply_join_dependency(eager_loading: false)
|
317
|
+
return relation.exists?(conditions)
|
318
|
+
end
|
316
319
|
|
317
|
-
relation = construct_relation_for_exists(
|
320
|
+
relation = construct_relation_for_exists(conditions)
|
318
321
|
|
319
|
-
connection.
|
322
|
+
skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists") } ? true : false
|
320
323
|
rescue ::RangeError
|
321
324
|
false
|
322
325
|
end
|
@@ -329,23 +332,23 @@ module ActiveRecord
|
|
329
332
|
# of results obtained should be provided in the +result_size+ argument and
|
330
333
|
# the expected number of results should be provided in the +expected_size+
|
331
334
|
# argument.
|
332
|
-
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key) # :nodoc:
|
333
|
-
conditions = arel.where_sql(@klass
|
335
|
+
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
336
|
+
conditions = arel.where_sql(@klass)
|
334
337
|
conditions = " [#{conditions}]" if conditions
|
335
338
|
name = @klass.name
|
336
339
|
|
337
340
|
if ids.nil?
|
338
|
-
error = "Couldn't find #{name}"
|
341
|
+
error = "Couldn't find #{name}".dup
|
339
342
|
error << " with#{conditions}" if conditions
|
340
|
-
raise RecordNotFound.new(error, name)
|
343
|
+
raise RecordNotFound.new(error, name, key)
|
341
344
|
elsif Array(ids).size == 1
|
342
345
|
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
343
346
|
raise RecordNotFound.new(error, name, key, ids)
|
344
347
|
else
|
345
|
-
error = "Couldn't find all #{name.pluralize} with '#{key}': "
|
346
|
-
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
|
347
|
-
|
348
|
-
raise RecordNotFound.new(error, name,
|
348
|
+
error = "Couldn't find all #{name.pluralize} with '#{key}': ".dup
|
349
|
+
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
350
|
+
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
|
+
raise RecordNotFound.new(error, name, key, ids)
|
349
352
|
end
|
350
353
|
end
|
351
354
|
|
@@ -355,27 +358,12 @@ module ActiveRecord
|
|
355
358
|
offset_value || 0
|
356
359
|
end
|
357
360
|
|
358
|
-
def
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
# SpecialCategorizations is constructed without knowledge of the
|
365
|
-
# preexisting join in joins_values to categorizations (by way of
|
366
|
-
# the `has_many :through` for categories).
|
367
|
-
#
|
368
|
-
join_dependency = construct_join_dependency(joins_values)
|
369
|
-
|
370
|
-
aliases = join_dependency.aliases
|
371
|
-
relation = select aliases.columns
|
372
|
-
relation = apply_join_dependency(relation, join_dependency)
|
373
|
-
|
374
|
-
yield relation, join_dependency
|
375
|
-
end
|
376
|
-
|
377
|
-
def construct_relation_for_exists(relation, conditions)
|
378
|
-
relation = relation.except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
361
|
+
def construct_relation_for_exists(conditions)
|
362
|
+
if distinct_value && offset_value
|
363
|
+
relation = except(:order).limit!(1)
|
364
|
+
else
|
365
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
366
|
+
end
|
379
367
|
|
380
368
|
case conditions
|
381
369
|
when Array, Hash
|
@@ -387,37 +375,41 @@ module ActiveRecord
|
|
387
375
|
relation
|
388
376
|
end
|
389
377
|
|
390
|
-
def construct_join_dependency
|
378
|
+
def construct_join_dependency
|
391
379
|
including = eager_load_values + includes_values
|
392
|
-
ActiveRecord::Associations::JoinDependency.new(
|
393
|
-
|
394
|
-
|
395
|
-
def construct_relation_for_association_calculations
|
396
|
-
apply_join_dependency(self, construct_join_dependency(joins_values))
|
380
|
+
ActiveRecord::Associations::JoinDependency.new(
|
381
|
+
klass, table, including
|
382
|
+
)
|
397
383
|
end
|
398
384
|
|
399
|
-
def apply_join_dependency(
|
400
|
-
|
385
|
+
def apply_join_dependency(eager_loading: group_values.empty?)
|
386
|
+
join_dependency = construct_join_dependency
|
387
|
+
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
401
388
|
|
402
|
-
if using_limitable_reflections?(join_dependency.reflections)
|
403
|
-
|
404
|
-
else
|
405
|
-
if relation.limit_value
|
389
|
+
if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
|
390
|
+
if has_limit_or_offset?
|
406
391
|
limited_ids = limited_ids_for(relation)
|
407
392
|
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
408
393
|
end
|
409
|
-
relation.
|
394
|
+
relation.limit_value = relation.offset_value = nil
|
395
|
+
end
|
396
|
+
|
397
|
+
if block_given?
|
398
|
+
yield relation, join_dependency
|
399
|
+
else
|
400
|
+
relation
|
410
401
|
end
|
411
402
|
end
|
412
403
|
|
413
404
|
def limited_ids_for(relation)
|
414
405
|
values = @klass.connection.columns_for_distinct(
|
415
|
-
|
406
|
+
connection.column_name_from_arel_node(arel_attribute(primary_key)),
|
407
|
+
relation.order_values
|
408
|
+
)
|
416
409
|
|
417
410
|
relation = relation.except(:select).select(values).distinct!
|
418
|
-
arel = relation.arel
|
419
411
|
|
420
|
-
id_rows = @klass.connection.select_all(arel, "SQL"
|
412
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
|
421
413
|
id_rows.map { |row| row[primary_key] }
|
422
414
|
end
|
423
415
|
|
@@ -433,9 +425,12 @@ module ActiveRecord
|
|
433
425
|
|
434
426
|
ids = ids.flatten.compact.uniq
|
435
427
|
|
428
|
+
model_name = @klass.name
|
429
|
+
|
436
430
|
case ids.size
|
437
431
|
when 0
|
438
|
-
|
432
|
+
error_message = "Couldn't find #{model_name} without an ID"
|
433
|
+
raise RecordNotFound.new(error_message, model_name, primary_key)
|
439
434
|
when 1
|
440
435
|
result = find_one(ids.first)
|
441
436
|
expects_array ? [ result ] : result
|
@@ -443,7 +438,8 @@ module ActiveRecord
|
|
443
438
|
find_some(ids)
|
444
439
|
end
|
445
440
|
rescue ::RangeError
|
446
|
-
|
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)
|
447
443
|
end
|
448
444
|
|
449
445
|
def find_one(id)
|
@@ -525,13 +521,13 @@ module ActiveRecord
|
|
525
521
|
if loaded?
|
526
522
|
records[index, limit] || []
|
527
523
|
else
|
528
|
-
relation =
|
529
|
-
|
530
|
-
|
531
|
-
|
524
|
+
relation = ordered_relation
|
525
|
+
|
526
|
+
if limit_value
|
527
|
+
limit = [limit_value - index, limit].min
|
532
528
|
end
|
533
529
|
|
534
|
-
if
|
530
|
+
if limit > 0
|
535
531
|
relation = relation.offset(offset_index + index) unless index.zero?
|
536
532
|
relation.limit(limit).to_a
|
537
533
|
else
|
@@ -544,23 +540,26 @@ module ActiveRecord
|
|
544
540
|
if loaded?
|
545
541
|
records[-index]
|
546
542
|
else
|
547
|
-
relation =
|
548
|
-
|
543
|
+
relation = ordered_relation
|
544
|
+
|
545
|
+
if equal?(relation) || has_limit_or_offset?
|
546
|
+
relation.records[-index]
|
549
547
|
else
|
550
|
-
|
548
|
+
relation.last(index)[-index]
|
551
549
|
end
|
552
|
-
|
553
|
-
relation.to_a[-index]
|
554
|
-
# TODO: can be made more performant on large result sets by
|
555
|
-
# for instance, last(index)[-index] (which would require
|
556
|
-
# refactoring the last(n) finder method to make test suite pass),
|
557
|
-
# or by using a combination of reverse_order, limit, and offset,
|
558
|
-
# e.g., reverse_order.offset(index-1).first
|
559
550
|
end
|
560
551
|
end
|
561
552
|
|
562
553
|
def find_last(limit)
|
563
554
|
limit ? records.last(limit) : records.last
|
564
555
|
end
|
556
|
+
|
557
|
+
def ordered_relation
|
558
|
+
if order_values.empty? && primary_key
|
559
|
+
order(arel_attribute(primary_key).asc)
|
560
|
+
else
|
561
|
+
self
|
562
|
+
end
|
563
|
+
end
|
565
564
|
end
|
566
565
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class Relation
|
3
5
|
class FromClause # :nodoc:
|
@@ -8,14 +10,6 @@ module ActiveRecord
|
|
8
10
|
@name = name
|
9
11
|
end
|
10
12
|
|
11
|
-
def binds
|
12
|
-
if value.is_a?(Relation)
|
13
|
-
value.bound_attributes
|
14
|
-
else
|
15
|
-
[]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
13
|
def merge(other)
|
20
14
|
self
|
21
15
|
end
|