activerecord 6.0.6.1 → 6.1.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1146 -788
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record/aggregations.rb +5 -5
- data/lib/active_record/association_relation.rb +30 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +49 -26
- data/lib/active_record/associations/association_scope.rb +18 -20
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- 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 +32 -18
- 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 +37 -21
- 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 +14 -8
- 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 +118 -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 +33 -8
- 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 +1 -1
- 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 +66 -23
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
- 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 +114 -26
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
- 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 +35 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- 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 +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
- 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 +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -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/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 +30 -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 +75 -64
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -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 +52 -0
- data/lib/active_record/connection_handling.rb +218 -71
- data/lib/active_record/core.rb +264 -63
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -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 +125 -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 +69 -34
- 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 +58 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +38 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +24 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -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 +72 -18
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +89 -14
- 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/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +279 -101
- 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 +104 -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 +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +61 -38
- data/lib/active_record/relation/query_methods.rb +322 -196
- 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 +111 -61
- data/lib/active_record/relation.rb +100 -81
- 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/default.rb +1 -3
- 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 +8 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -51
- data/lib/active_record/tasks/database_tasks.rb +140 -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 +79 -31
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +19 -66
- 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 +76 -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 +24 -25
- 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,36 @@ 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 = type.subtype if Enum::EnumType === type
|
314
|
+
type.deserialize(value)
|
315
|
+
end
|
306
316
|
end
|
307
317
|
|
308
318
|
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
|
309
319
|
group_fields = group_values
|
320
|
+
group_fields = group_fields.uniq if group_fields.size > 1
|
321
|
+
|
322
|
+
unless group_fields == group_values
|
323
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
324
|
+
`#{operation}` with group by duplicated fields does no longer affect to result in Rails 7.0.
|
325
|
+
To migrate to Rails 7.0's behavior, use `uniq!(:group)` to deduplicate group fields
|
326
|
+
(`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
|
327
|
+
MSG
|
328
|
+
group_fields = group_values
|
329
|
+
end
|
310
330
|
|
311
331
|
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
312
332
|
association = klass._reflect_on_association(group_fields.first)
|
@@ -321,14 +341,12 @@ module ActiveRecord
|
|
321
341
|
}
|
322
342
|
group_columns = group_aliases.zip(group_fields)
|
323
343
|
|
324
|
-
|
344
|
+
column = aggregate_column(column_name)
|
345
|
+
column_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
|
346
|
+
select_value = operation_over_aggregate_column(column, operation, distinct)
|
347
|
+
select_value.as(column_alias)
|
325
348
|
|
326
|
-
select_values = [
|
327
|
-
operation_over_aggregate_column(
|
328
|
-
aggregate_column(column_name),
|
329
|
-
operation,
|
330
|
-
distinct).as(aggregate_alias)
|
331
|
-
]
|
349
|
+
select_values = [select_value]
|
332
350
|
select_values += self.select_values unless having_clause.empty?
|
333
351
|
|
334
352
|
select_values.concat group_columns.map { |aliaz, field|
|
@@ -348,22 +366,36 @@ module ActiveRecord
|
|
348
366
|
if association
|
349
367
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
350
368
|
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
351
|
-
key_records =
|
369
|
+
key_records = key_records.index_by(&:id)
|
352
370
|
end
|
353
371
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
372
|
+
key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
|
373
|
+
types[aliaz] = type_for(col_name) do
|
374
|
+
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
hash_rows = calculated_data.cast_values(key_types).map! do |row|
|
379
|
+
calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
|
380
|
+
hash[col_name] = row[i]
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
type = nil
|
385
|
+
hash_rows.each_with_object({}) do |row, result|
|
386
|
+
key = group_aliases.map { |aliaz| row[aliaz] }
|
361
387
|
key = key.first if key.size == 1
|
362
388
|
key = key_records[key] if associated
|
363
389
|
|
364
|
-
|
365
|
-
|
366
|
-
|
390
|
+
result[key] = type_cast_calculated_value(row[column_alias], operation) do |value|
|
391
|
+
unless type
|
392
|
+
type = column.try(:type_caster) ||
|
393
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
394
|
+
type = type.subtype if Enum::EnumType === type
|
395
|
+
end
|
396
|
+
type.deserialize(value)
|
397
|
+
end
|
398
|
+
end
|
367
399
|
end
|
368
400
|
|
369
401
|
# Converts the given field to the value that the database adapter returns as
|
@@ -388,12 +420,41 @@ module ActiveRecord
|
|
388
420
|
@klass.type_for_attribute(field_name, &block)
|
389
421
|
end
|
390
422
|
|
391
|
-
def
|
423
|
+
def lookup_cast_type_from_join_dependencies(name, join_dependencies = build_join_dependencies)
|
424
|
+
each_join_dependencies(join_dependencies) do |join|
|
425
|
+
type = join.base_klass.attribute_types.fetch(name, nil)
|
426
|
+
return type if type
|
427
|
+
end
|
428
|
+
nil
|
429
|
+
end
|
430
|
+
|
431
|
+
def type_cast_pluck_values(result, columns)
|
432
|
+
cast_types = if result.columns.size != columns.size
|
433
|
+
klass.attribute_types
|
434
|
+
else
|
435
|
+
join_dependencies = nil
|
436
|
+
columns.map.with_index do |column, i|
|
437
|
+
column.try(:type_caster) ||
|
438
|
+
klass.attribute_types.fetch(name = result.columns[i]) do
|
439
|
+
join_dependencies ||= build_join_dependencies
|
440
|
+
lookup_cast_type_from_join_dependencies(name, join_dependencies) ||
|
441
|
+
result.column_types[name] || Type.default_value
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
result.cast_values(cast_types)
|
446
|
+
end
|
447
|
+
|
448
|
+
def type_cast_calculated_value(value, operation)
|
392
449
|
case operation
|
393
|
-
when "count"
|
394
|
-
|
395
|
-
when "
|
396
|
-
|
450
|
+
when "count"
|
451
|
+
value.to_i
|
452
|
+
when "sum"
|
453
|
+
yield value || 0
|
454
|
+
when "average"
|
455
|
+
value&.respond_to?(:to_d) ? value.to_d : value
|
456
|
+
else # "minimum", "maximum"
|
457
|
+
yield value
|
397
458
|
end
|
398
459
|
end
|
399
460
|
|
@@ -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 || having_clause.any?
|
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 7.0.
|
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?(primary_key)
|
35
|
+
value.public_send(primary_key)
|
37
36
|
else
|
38
37
|
value
|
39
38
|
end
|
@@ -9,11 +9,13 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def queries
|
12
|
+
return [ associated_table.join_foreign_key => values ] if values.empty?
|
13
|
+
|
12
14
|
type_to_ids_mapping.map do |type, ids|
|
13
|
-
{
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
query = {}
|
16
|
+
query[associated_table.join_foreign_type] = type if type
|
17
|
+
query[associated_table.join_foreign_key] = ids
|
18
|
+
query
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
@@ -23,12 +25,12 @@ module ActiveRecord
|
|
23
25
|
def type_to_ids_mapping
|
24
26
|
default_hash = Hash.new { |hsh, key| hsh[key] = [] }
|
25
27
|
values.each_with_object(default_hash) do |value, hash|
|
26
|
-
hash[klass(value)
|
28
|
+
hash[klass(value)&.polymorphic_name] << convert_to_id(value)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
32
|
def primary_key(value)
|
31
|
-
associated_table.
|
33
|
+
associated_table.join_primary_key(klass(value))
|
32
34
|
end
|
33
35
|
|
34
36
|
def klass(value)
|
@@ -46,6 +48,8 @@ module ActiveRecord
|
|
46
48
|
value._read_attribute(primary_key(value))
|
47
49
|
when Relation
|
48
50
|
value.select(primary_key(value))
|
51
|
+
else
|
52
|
+
value
|
49
53
|
end
|
50
54
|
end
|
51
55
|
end
|