activerecord 6.0.6 → 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 +783 -910
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +43 -26
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +2 -24
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- 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/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- 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 +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- 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 +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- 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/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +223 -66
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +27 -10
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- 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 +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +34 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +318 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/named.rb +1 -17
- 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 +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- 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
- metadata +28 -30
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -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.
|
@@ -179,7 +181,7 @@ module ActiveRecord
|
|
179
181
|
# See also #ids.
|
180
182
|
#
|
181
183
|
def pluck(*column_names)
|
182
|
-
if loaded? && (column_names
|
184
|
+
if loaded? && all_attributes?(column_names)
|
183
185
|
return records.pluck(*column_names)
|
184
186
|
end
|
185
187
|
|
@@ -188,10 +190,17 @@ module ActiveRecord
|
|
188
190
|
relation.pluck(*column_names)
|
189
191
|
else
|
190
192
|
klass.disallow_raw_sql!(column_names)
|
193
|
+
columns = arel_columns(column_names)
|
191
194
|
relation = spawn
|
192
|
-
relation.select_values =
|
193
|
-
result = skip_query_cache_if_necessary
|
194
|
-
|
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)
|
195
204
|
end
|
196
205
|
end
|
197
206
|
|
@@ -210,6 +219,10 @@ module ActiveRecord
|
|
210
219
|
# # SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
|
211
220
|
# # => [ 'David', 'david@loudthinking.com' ]
|
212
221
|
def pick(*column_names)
|
222
|
+
if loaded? && all_attributes?(column_names)
|
223
|
+
return records.pick(*column_names)
|
224
|
+
end
|
225
|
+
|
213
226
|
limit(1).pluck(*column_names).first
|
214
227
|
end
|
215
228
|
|
@@ -222,6 +235,10 @@ module ActiveRecord
|
|
222
235
|
end
|
223
236
|
|
224
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
|
+
|
225
242
|
def has_include?(column_name)
|
226
243
|
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
227
244
|
end
|
@@ -266,12 +283,10 @@ module ActiveRecord
|
|
266
283
|
end
|
267
284
|
|
268
285
|
def operation_over_aggregate_column(column, operation, distinct)
|
269
|
-
operation == "count" ? column.count(distinct) : column.
|
286
|
+
operation == "count" ? column.count(distinct) : column.public_send(operation)
|
270
287
|
end
|
271
288
|
|
272
289
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
273
|
-
column_alias = column_name
|
274
|
-
|
275
290
|
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
276
291
|
# Shortcut when limit is zero.
|
277
292
|
return 0 if limit_value == 0
|
@@ -282,31 +297,35 @@ module ActiveRecord
|
|
282
297
|
relation = unscope(:order).distinct!(false)
|
283
298
|
|
284
299
|
column = aggregate_column(column_name)
|
285
|
-
|
286
300
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
287
|
-
if operation == "sum" && distinct
|
288
|
-
select_value.distinct = true
|
289
|
-
end
|
301
|
+
select_value.distinct = true if operation == "sum" && distinct
|
290
302
|
|
291
|
-
column_alias = select_value.alias
|
292
|
-
column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
|
293
303
|
relation.select_values = [select_value]
|
294
304
|
|
295
305
|
query_builder = relation.arel
|
296
306
|
end
|
297
307
|
|
298
|
-
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder
|
299
|
-
row = result.first
|
300
|
-
value = row && row.values.first
|
301
|
-
type = result.column_types.fetch(column_alias) do
|
302
|
-
type_for(column_name)
|
303
|
-
end
|
308
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
|
304
309
|
|
305
|
-
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
|
306
315
|
end
|
307
316
|
|
308
317
|
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
309
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
|
310
329
|
|
311
330
|
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
312
331
|
association = klass._reflect_on_association(group_fields.first)
|
@@ -321,14 +340,12 @@ module ActiveRecord
|
|
321
340
|
}
|
322
341
|
group_columns = group_aliases.zip(group_fields)
|
323
342
|
|
324
|
-
|
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)
|
325
347
|
|
326
|
-
select_values = [
|
327
|
-
operation_over_aggregate_column(
|
328
|
-
aggregate_column(column_name),
|
329
|
-
operation,
|
330
|
-
distinct).as(aggregate_alias)
|
331
|
-
]
|
348
|
+
select_values = [select_value]
|
332
349
|
select_values += self.select_values unless having_clause.empty?
|
333
350
|
|
334
351
|
select_values.concat group_columns.map { |aliaz, field|
|
@@ -348,22 +365,33 @@ module ActiveRecord
|
|
348
365
|
if association
|
349
366
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
350
367
|
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
351
|
-
key_records =
|
368
|
+
key_records = key_records.index_by(&:id)
|
352
369
|
end
|
353
370
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
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] }
|
361
386
|
key = key.first if key.size == 1
|
362
387
|
key = key_records[key] if associated
|
363
388
|
|
364
|
-
|
365
|
-
|
366
|
-
|
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
|
367
395
|
end
|
368
396
|
|
369
397
|
# Converts the given field to the value that the database adapter returns as
|
@@ -388,12 +416,41 @@ module ActiveRecord
|
|
388
416
|
@klass.type_for_attribute(field_name, &block)
|
389
417
|
end
|
390
418
|
|
391
|
-
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)
|
392
445
|
case operation
|
393
|
-
when "count"
|
394
|
-
|
395
|
-
when "
|
396
|
-
|
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
|
397
454
|
end
|
398
455
|
end
|
399
456
|
|
@@ -114,6 +114,8 @@ module ActiveRecord
|
|
114
114
|
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
|
115
115
|
#
|
116
116
|
def first(limit = nil)
|
117
|
+
check_reorder_deprecation unless loaded?
|
118
|
+
|
117
119
|
if limit
|
118
120
|
find_nth_with_limit(0, limit)
|
119
121
|
else
|
@@ -275,9 +277,9 @@ module ActiveRecord
|
|
275
277
|
# * Integer - Finds the record with this primary key.
|
276
278
|
# * String - Finds the record with a primary key corresponding to this
|
277
279
|
# string (such as <tt>'5'</tt>).
|
278
|
-
# * Array - Finds the record that matches these +
|
280
|
+
# * Array - Finds the record that matches these +where+-style conditions
|
279
281
|
# (such as <tt>['name LIKE ?', "%#{query}%"]</tt>).
|
280
|
-
# * Hash - Finds the record that matches these +
|
282
|
+
# * Hash - Finds the record that matches these +where+-style conditions
|
281
283
|
# (such as <tt>{name: 'David'}</tt>).
|
282
284
|
# * +false+ - Returns always +false+.
|
283
285
|
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
@@ -313,10 +315,26 @@ module ActiveRecord
|
|
313
315
|
end
|
314
316
|
|
315
317
|
relation = construct_relation_for_exists(conditions)
|
318
|
+
return false if relation.where_clause.contradiction?
|
319
|
+
|
320
|
+
skip_query_cache_if_necessary { connection.select_rows(relation.arel, "#{name} Exists?").size == 1 }
|
321
|
+
end
|
316
322
|
|
317
|
-
|
323
|
+
# Returns true if the relation contains the given record or false otherwise.
|
324
|
+
#
|
325
|
+
# No query is performed if the relation is loaded; the given record is
|
326
|
+
# compared to the records in memory. If the relation is unloaded, an
|
327
|
+
# efficient existence query is performed, as in #exists?.
|
328
|
+
def include?(record)
|
329
|
+
if loaded? || offset_value || limit_value
|
330
|
+
records.include?(record)
|
331
|
+
else
|
332
|
+
record.is_a?(klass) && exists?(record.id)
|
333
|
+
end
|
318
334
|
end
|
319
335
|
|
336
|
+
alias :member? :include?
|
337
|
+
|
320
338
|
# This method is called whenever no records are found with either a single
|
321
339
|
# id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
|
322
340
|
#
|
@@ -326,15 +344,15 @@ module ActiveRecord
|
|
326
344
|
# the expected number of results should be provided in the +expected_size+
|
327
345
|
# argument.
|
328
346
|
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
329
|
-
conditions = arel.where_sql(
|
330
|
-
|
347
|
+
conditions = " [#{arel.where_sql(klass)}]" unless where_clause.empty?
|
348
|
+
|
331
349
|
name = @klass.name
|
332
350
|
|
333
351
|
if ids.nil?
|
334
352
|
error = +"Couldn't find #{name}"
|
335
353
|
error << " with#{conditions}" if conditions
|
336
354
|
raise RecordNotFound.new(error, name, key)
|
337
|
-
elsif Array(ids).size == 1
|
355
|
+
elsif Array.wrap(ids).size == 1
|
338
356
|
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
339
357
|
raise RecordNotFound.new(error, name, key, ids)
|
340
358
|
else
|
@@ -346,8 +364,15 @@ module ActiveRecord
|
|
346
364
|
end
|
347
365
|
|
348
366
|
private
|
349
|
-
def
|
350
|
-
|
367
|
+
def check_reorder_deprecation
|
368
|
+
if !order_values.empty? && order_values.all?(&:blank?)
|
369
|
+
blank_value = order_values.first
|
370
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
371
|
+
`.reorder(#{blank_value.inspect})` with `.first` / `.first!` no longer
|
372
|
+
takes non-deterministic result in Rails 6.2.
|
373
|
+
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
374
|
+
MSG
|
375
|
+
end
|
351
376
|
end
|
352
377
|
|
353
378
|
def construct_relation_for_exists(conditions)
|
@@ -401,14 +426,14 @@ module ActiveRecord
|
|
401
426
|
|
402
427
|
def limited_ids_for(relation)
|
403
428
|
values = @klass.connection.columns_for_distinct(
|
404
|
-
connection.visitor.compile(
|
429
|
+
connection.visitor.compile(table[primary_key]),
|
405
430
|
relation.order_values
|
406
431
|
)
|
407
432
|
|
408
433
|
relation = relation.except(:select).select(values).distinct!
|
409
434
|
|
410
|
-
id_rows = skip_query_cache_if_necessary { @klass.connection.
|
411
|
-
id_rows.map
|
435
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_rows(relation.arel, "SQL") }
|
436
|
+
id_rows.map(&:last)
|
412
437
|
end
|
413
438
|
|
414
439
|
def using_limitable_reflections?(reflections)
|
@@ -509,7 +534,8 @@ module ActiveRecord
|
|
509
534
|
end
|
510
535
|
|
511
536
|
def find_nth(index)
|
512
|
-
@offsets
|
537
|
+
@offsets ||= {}
|
538
|
+
@offsets[index] ||= find_nth_with_limit(index, 1).first
|
513
539
|
end
|
514
540
|
|
515
541
|
def find_nth_with_limit(index, limit)
|
@@ -523,7 +549,7 @@ module ActiveRecord
|
|
523
549
|
end
|
524
550
|
|
525
551
|
if limit > 0
|
526
|
-
relation = relation.offset(
|
552
|
+
relation = relation.offset((offset_value || 0) + index) unless index.zero?
|
527
553
|
relation.limit(limit).to_a
|
528
554
|
else
|
529
555
|
[]
|
@@ -551,7 +577,11 @@ module ActiveRecord
|
|
551
577
|
|
552
578
|
def ordered_relation
|
553
579
|
if order_values.empty? && (implicit_order_column || primary_key)
|
554
|
-
|
580
|
+
if implicit_order_column && primary_key && implicit_order_column != primary_key
|
581
|
+
order(table[implicit_order_column].asc, table[primary_key].asc)
|
582
|
+
else
|
583
|
+
order(table[implicit_order_column || primary_key].asc)
|
584
|
+
end
|
555
585
|
else
|
556
586
|
self
|
557
587
|
end
|
@@ -7,15 +7,16 @@ module ActiveRecord
|
|
7
7
|
class HashMerger # :nodoc:
|
8
8
|
attr_reader :relation, :hash
|
9
9
|
|
10
|
-
def initialize(relation, hash)
|
10
|
+
def initialize(relation, hash, rewhere = nil)
|
11
11
|
hash.assert_valid_keys(*Relation::VALUE_METHODS)
|
12
12
|
|
13
13
|
@relation = relation
|
14
14
|
@hash = hash
|
15
|
+
@rewhere = rewhere
|
15
16
|
end
|
16
17
|
|
17
|
-
def merge
|
18
|
-
Merger.new(relation, other).merge
|
18
|
+
def merge
|
19
|
+
Merger.new(relation, other, @rewhere).merge
|
19
20
|
end
|
20
21
|
|
21
22
|
# Applying values to a relation has some side effects. E.g.
|
@@ -28,19 +29,14 @@ module ActiveRecord
|
|
28
29
|
table: relation.table,
|
29
30
|
predicate_builder: relation.predicate_builder
|
30
31
|
)
|
31
|
-
hash.each
|
32
|
-
if k == :
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
other.joins!(*v)
|
37
|
-
end
|
38
|
-
elsif k == :select
|
39
|
-
other._select!(v)
|
32
|
+
hash.each do |k, v|
|
33
|
+
k = :_select if k == :select
|
34
|
+
if Array === v
|
35
|
+
other.public_send("#{k}!", *v)
|
40
36
|
else
|
41
|
-
other.
|
37
|
+
other.public_send("#{k}!", v)
|
42
38
|
end
|
43
|
-
|
39
|
+
end
|
44
40
|
other
|
45
41
|
end
|
46
42
|
end
|
@@ -48,10 +44,11 @@ module ActiveRecord
|
|
48
44
|
class Merger # :nodoc:
|
49
45
|
attr_reader :relation, :values, :other
|
50
46
|
|
51
|
-
def initialize(relation, other)
|
47
|
+
def initialize(relation, other, rewhere = nil)
|
52
48
|
@relation = relation
|
53
49
|
@values = other.values
|
54
50
|
@other = other
|
51
|
+
@rewhere = rewhere
|
55
52
|
end
|
56
53
|
|
57
54
|
NORMAL_VALUES = Relation::VALUE_METHODS -
|
@@ -73,7 +70,7 @@ module ActiveRecord
|
|
73
70
|
if name == :select
|
74
71
|
relation._select!(*value)
|
75
72
|
else
|
76
|
-
relation.
|
73
|
+
relation.public_send("#{name}!", *value)
|
77
74
|
end
|
78
75
|
end
|
79
76
|
end
|
@@ -93,8 +90,8 @@ module ActiveRecord
|
|
93
90
|
return if other.preload_values.empty? && other.includes_values.empty?
|
94
91
|
|
95
92
|
if other.klass == relation.klass
|
96
|
-
relation.
|
97
|
-
relation.
|
93
|
+
relation.preload_values |= other.preload_values unless other.preload_values.empty?
|
94
|
+
relation.includes_values |= other.includes_values unless other.includes_values.empty?
|
98
95
|
else
|
99
96
|
reflection = relation.klass.reflect_on_all_associations.find do |r|
|
100
97
|
r.class_name == other.klass.name
|
@@ -111,10 +108,10 @@ module ActiveRecord
|
|
111
108
|
end
|
112
109
|
|
113
110
|
def merge_joins
|
114
|
-
return if other.joins_values.
|
111
|
+
return if other.joins_values.empty?
|
115
112
|
|
116
113
|
if other.klass == relation.klass
|
117
|
-
relation.
|
114
|
+
relation.joins_values |= other.joins_values
|
118
115
|
else
|
119
116
|
associations, others = other.joins_values.partition do |join|
|
120
117
|
case join
|
@@ -130,10 +127,10 @@ module ActiveRecord
|
|
130
127
|
end
|
131
128
|
|
132
129
|
def merge_outer_joins
|
133
|
-
return if other.left_outer_joins_values.
|
130
|
+
return if other.left_outer_joins_values.empty?
|
134
131
|
|
135
132
|
if other.klass == relation.klass
|
136
|
-
relation.
|
133
|
+
relation.left_outer_joins_values |= other.left_outer_joins_values
|
137
134
|
else
|
138
135
|
associations, others = other.left_outer_joins_values.partition do |join|
|
139
136
|
case join
|
@@ -172,7 +169,7 @@ module ActiveRecord
|
|
172
169
|
def merge_clauses
|
173
170
|
relation.from_clause = other.from_clause if replace_from_clause?
|
174
171
|
|
175
|
-
where_clause = relation.where_clause.merge(other.where_clause)
|
172
|
+
where_clause = relation.where_clause.merge(other.where_clause, @rewhere)
|
176
173
|
relation.where_clause = where_clause unless where_clause.empty?
|
177
174
|
|
178
175
|
having_clause = relation.having_clause.merge(other.having_clause)
|
@@ -20,20 +20,19 @@ module ActiveRecord
|
|
20
20
|
case values.length
|
21
21
|
when 0 then NullPredicate
|
22
22
|
when 1 then predicate_builder.build(attribute, values.first)
|
23
|
-
else
|
24
|
-
values.map! do |v|
|
25
|
-
predicate_builder.build_bind_attribute(attribute.name, v)
|
26
|
-
end
|
27
|
-
values.empty? ? NullPredicate : attribute.in(values)
|
23
|
+
else Arel::Nodes::HomogeneousIn.new(values, attribute, :in)
|
28
24
|
end
|
29
25
|
|
30
26
|
unless nils.empty?
|
31
|
-
values_predicate = values_predicate.or(
|
27
|
+
values_predicate = values_predicate.or(attribute.eq(nil))
|
32
28
|
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
if ranges.empty?
|
31
|
+
values_predicate
|
32
|
+
else
|
33
|
+
array_predicates = ranges.map! { |range| predicate_builder.build(attribute, range) }
|
34
|
+
array_predicates.inject(values_predicate, &:or)
|
35
|
+
end
|
37
36
|
end
|
38
37
|
|
39
38
|
private
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def queries
|
12
|
-
[associated_table.
|
12
|
+
[associated_table.join_foreign_key => ids]
|
13
13
|
end
|
14
14
|
|
15
15
|
private
|
@@ -27,13 +27,12 @@ module ActiveRecord
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def primary_key
|
30
|
-
associated_table.
|
30
|
+
associated_table.join_primary_key
|
31
31
|
end
|
32
32
|
|
33
33
|
def convert_to_id(value)
|
34
|
-
|
35
|
-
|
36
|
-
value._read_attribute(primary_key)
|
34
|
+
if value.respond_to?(:id)
|
35
|
+
value.id
|
37
36
|
else
|
38
37
|
value
|
39
38
|
end
|
@@ -11,8 +11,8 @@ module ActiveRecord
|
|
11
11
|
def queries
|
12
12
|
type_to_ids_mapping.map do |type, ids|
|
13
13
|
{
|
14
|
-
associated_table.
|
15
|
-
associated_table.
|
14
|
+
associated_table.join_foreign_type => type,
|
15
|
+
associated_table.join_foreign_key => ids
|
16
16
|
}
|
17
17
|
end
|
18
18
|
end
|
@@ -28,7 +28,7 @@ module ActiveRecord
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def primary_key(value)
|
31
|
-
associated_table.
|
31
|
+
associated_table.join_primary_key(klass(value))
|
32
32
|
end
|
33
33
|
|
34
34
|
def klass(value)
|