activerecord 5.1.5 → 5.2.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 +450 -699
- 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 +4 -2
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +33 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- 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 +14 -5
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- 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 +52 -41
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +3 -1
- data/lib/active_record/associations/has_many_through_association.rb +8 -19
- 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 +22 -67
- 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 +17 -37
- 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 +25 -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 +7 -6
- data/lib/active_record/autosave_association.rb +16 -14
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
- 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 +149 -78
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
- 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 +2 -0
- 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 +6 -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 +3 -1
- 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 +3 -1
- 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 +8 -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 +14 -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 +248 -112
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
- 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 +20 -1
- 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 +79 -92
- 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 +39 -60
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +17 -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 +4 -2
- 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 +30 -42
- 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 +40 -2
- 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 +19 -24
- 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 +196 -48
- data/lib/active_record/query_cache.rb +12 -14
- data/lib/active_record/querying.rb +3 -1
- data/lib/active_record/railtie.rb +61 -3
- 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 +110 -192
- 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 +31 -9
- data/lib/active_record/relation/delegation.rb +15 -27
- data/lib/active_record/relation/finder_methods.rb +71 -76
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +47 -20
- 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 +55 -79
- data/lib/active_record/relation/query_attribute.rb +26 -2
- data/lib/active_record/relation/query_methods.rb +95 -91
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -1
- 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 +106 -219
- 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 +6 -7
- data/lib/active_record/scoping/named.rb +21 -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 +22 -12
- 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 +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +32 -27
- 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 +6 -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 +36 -6
- 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 +23 -36
- 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 -114
- data/lib/active_record/attribute_set/builder.rb +0 -124
- 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,9 +130,9 @@ 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
|
-
if operation.to_s.downcase == "count"
|
135
|
+
if operation.to_s.downcase == "count"
|
116
136
|
relation.distinct!
|
117
137
|
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
118
138
|
if (column_name == :all || column_name.nil?) && select_values.empty?
|
@@ -167,13 +187,15 @@ module ActiveRecord
|
|
167
187
|
end
|
168
188
|
|
169
189
|
if has_include?(column_names.first)
|
170
|
-
|
190
|
+
relation = apply_join_dependency
|
191
|
+
relation.pluck(*column_names)
|
171
192
|
else
|
193
|
+
enforce_raw_sql_whitelist(column_names)
|
172
194
|
relation = spawn
|
173
195
|
relation.select_values = column_names.map { |cn|
|
174
196
|
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
175
197
|
}
|
176
|
-
result = klass.connection.select_all(relation.arel, nil
|
198
|
+
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
177
199
|
result.cast_values(klass.attribute_types)
|
178
200
|
end
|
179
201
|
end
|
@@ -220,7 +242,7 @@ module ActiveRecord
|
|
220
242
|
def aggregate_column(column_name)
|
221
243
|
return column_name if Arel::Expressions === column_name
|
222
244
|
|
223
|
-
if @klass.has_attribute?(column_name
|
245
|
+
if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
|
224
246
|
@klass.arel_attribute(column_name)
|
225
247
|
else
|
226
248
|
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
@@ -257,7 +279,7 @@ module ActiveRecord
|
|
257
279
|
query_builder = relation.arel
|
258
280
|
end
|
259
281
|
|
260
|
-
result = @klass.connection.select_all(query_builder, nil
|
282
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
|
261
283
|
row = result.first
|
262
284
|
value = row && row.values.first
|
263
285
|
type = result.column_types.fetch(column_alias) do
|
@@ -308,7 +330,7 @@ module ActiveRecord
|
|
308
330
|
relation.group_values = group_fields
|
309
331
|
relation.select_values = select_values
|
310
332
|
|
311
|
-
calculated_data = @klass.connection.select_all(relation, nil
|
333
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
|
312
334
|
|
313
335
|
if association
|
314
336
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Delegation # :nodoc:
|
3
5
|
module DelegateCache # :nodoc:
|
@@ -36,13 +38,12 @@ module ActiveRecord
|
|
36
38
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
37
39
|
# for each different klass, and the delegations are compiled into that subclass only.
|
38
40
|
|
39
|
-
delegate :to_xml, :encode_with, :length, :each, :uniq, :
|
40
|
-
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
41
|
+
delegate :to_xml, :encode_with, :length, :each, :uniq, :join,
|
42
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
41
43
|
:to_sentence, :to_formatted_s, :as_json,
|
42
|
-
:shuffle, :split, :index, to: :records
|
44
|
+
:shuffle, :split, :slice, :index, :rindex, to: :records
|
43
45
|
|
44
|
-
delegate :
|
45
|
-
:connection, :columns_hash, to: :klass
|
46
|
+
delegate :primary_key, :connection, to: :klass
|
46
47
|
|
47
48
|
module ClassSpecificRelation # :nodoc:
|
48
49
|
extend ActiveSupport::Concern
|
@@ -73,13 +74,6 @@ module ActiveRecord
|
|
73
74
|
end
|
74
75
|
end
|
75
76
|
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
77
|
end
|
84
78
|
|
85
79
|
private
|
@@ -88,8 +82,14 @@ module ActiveRecord
|
|
88
82
|
if @klass.respond_to?(method)
|
89
83
|
self.class.delegate_to_scoped_klass(method)
|
90
84
|
scoping { @klass.public_send(method, *args, &block) }
|
85
|
+
elsif @delegate_to_klass && @klass.respond_to?(method, true)
|
86
|
+
ActiveSupport::Deprecation.warn \
|
87
|
+
"Delegating missing #{method} method to #{@klass}. " \
|
88
|
+
"Accessibility of private/protected class methods in :scope is deprecated and will be removed in Rails 6.0."
|
89
|
+
@klass.send(method, *args, &block)
|
91
90
|
elsif arel.respond_to?(method)
|
92
|
-
|
91
|
+
ActiveSupport::Deprecation.warn \
|
92
|
+
"Delegating #{method} to arel is deprecated and will be removed in Rails 6.0."
|
93
93
|
arel.public_send(method, *args, &block)
|
94
94
|
else
|
95
95
|
super
|
@@ -109,21 +109,9 @@ module ActiveRecord
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
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
112
|
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
|
113
|
+
def respond_to_missing?(method, _)
|
114
|
+
super || @klass.respond_to?(method) || arel.respond_to?(method)
|
127
115
|
end
|
128
116
|
end
|
129
117
|
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.select_value(relation, "#{name} Exists"
|
322
|
+
skip_query_cache_if_necessary { connection.select_value(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,8 @@ module ActiveRecord
|
|
355
358
|
offset_value || 0
|
356
359
|
end
|
357
360
|
|
358
|
-
def
|
359
|
-
|
360
|
-
# any joins already present in `self`, so pass them in
|
361
|
-
#
|
362
|
-
# failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
|
363
|
-
# incorrect SQL is generated. In that case, the join dependency for
|
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
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
379
363
|
|
380
364
|
case conditions
|
381
365
|
when Array, Hash
|
@@ -387,37 +371,41 @@ module ActiveRecord
|
|
387
371
|
relation
|
388
372
|
end
|
389
373
|
|
390
|
-
def construct_join_dependency
|
374
|
+
def construct_join_dependency
|
391
375
|
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))
|
376
|
+
ActiveRecord::Associations::JoinDependency.new(
|
377
|
+
klass, table, including
|
378
|
+
)
|
397
379
|
end
|
398
380
|
|
399
|
-
def apply_join_dependency(
|
400
|
-
|
381
|
+
def apply_join_dependency(eager_loading: group_values.empty?)
|
382
|
+
join_dependency = construct_join_dependency
|
383
|
+
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
401
384
|
|
402
|
-
if using_limitable_reflections?(join_dependency.reflections)
|
403
|
-
|
404
|
-
else
|
405
|
-
if relation.limit_value
|
385
|
+
if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
|
386
|
+
if has_limit_or_offset?
|
406
387
|
limited_ids = limited_ids_for(relation)
|
407
388
|
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
408
389
|
end
|
409
|
-
relation.
|
390
|
+
relation.limit_value = relation.offset_value = nil
|
391
|
+
end
|
392
|
+
|
393
|
+
if block_given?
|
394
|
+
yield relation, join_dependency
|
395
|
+
else
|
396
|
+
relation
|
410
397
|
end
|
411
398
|
end
|
412
399
|
|
413
400
|
def limited_ids_for(relation)
|
414
401
|
values = @klass.connection.columns_for_distinct(
|
415
|
-
|
402
|
+
connection.column_name_from_arel_node(arel_attribute(primary_key)),
|
403
|
+
relation.order_values
|
404
|
+
)
|
416
405
|
|
417
406
|
relation = relation.except(:select).select(values).distinct!
|
418
|
-
arel = relation.arel
|
419
407
|
|
420
|
-
id_rows = @klass.connection.select_all(arel, "SQL"
|
408
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
|
421
409
|
id_rows.map { |row| row[primary_key] }
|
422
410
|
end
|
423
411
|
|
@@ -433,9 +421,12 @@ module ActiveRecord
|
|
433
421
|
|
434
422
|
ids = ids.flatten.compact.uniq
|
435
423
|
|
424
|
+
model_name = @klass.name
|
425
|
+
|
436
426
|
case ids.size
|
437
427
|
when 0
|
438
|
-
|
428
|
+
error_message = "Couldn't find #{model_name} without an ID"
|
429
|
+
raise RecordNotFound.new(error_message, model_name, primary_key)
|
439
430
|
when 1
|
440
431
|
result = find_one(ids.first)
|
441
432
|
expects_array ? [ result ] : result
|
@@ -443,7 +434,8 @@ module ActiveRecord
|
|
443
434
|
find_some(ids)
|
444
435
|
end
|
445
436
|
rescue ::RangeError
|
446
|
-
|
437
|
+
error_message = "Couldn't find #{model_name} with an out of range ID"
|
438
|
+
raise RecordNotFound.new(error_message, model_name, primary_key, ids)
|
447
439
|
end
|
448
440
|
|
449
441
|
def find_one(id)
|
@@ -525,13 +517,13 @@ module ActiveRecord
|
|
525
517
|
if loaded?
|
526
518
|
records[index, limit] || []
|
527
519
|
else
|
528
|
-
relation =
|
529
|
-
|
530
|
-
|
531
|
-
|
520
|
+
relation = ordered_relation
|
521
|
+
|
522
|
+
if limit_value
|
523
|
+
limit = [limit_value - index, limit].min
|
532
524
|
end
|
533
525
|
|
534
|
-
if
|
526
|
+
if limit > 0
|
535
527
|
relation = relation.offset(offset_index + index) unless index.zero?
|
536
528
|
relation.limit(limit).to_a
|
537
529
|
else
|
@@ -544,23 +536,26 @@ module ActiveRecord
|
|
544
536
|
if loaded?
|
545
537
|
records[-index]
|
546
538
|
else
|
547
|
-
relation =
|
548
|
-
|
539
|
+
relation = ordered_relation
|
540
|
+
|
541
|
+
if equal?(relation) || has_limit_or_offset?
|
542
|
+
relation.records[-index]
|
549
543
|
else
|
550
|
-
|
544
|
+
relation.last(index)[-index]
|
551
545
|
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
546
|
end
|
560
547
|
end
|
561
548
|
|
562
549
|
def find_last(limit)
|
563
550
|
limit ? records.last(limit) : records.last
|
564
551
|
end
|
552
|
+
|
553
|
+
def ordered_relation
|
554
|
+
if order_values.empty? && primary_key
|
555
|
+
order(arel_attribute(primary_key).asc)
|
556
|
+
else
|
557
|
+
self
|
558
|
+
end
|
559
|
+
end
|
565
560
|
end
|
566
561
|
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
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/hash/keys"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -21,7 +23,11 @@ module ActiveRecord
|
|
21
23
|
# build a relation to merge in rather than directly merging
|
22
24
|
# the values.
|
23
25
|
def other
|
24
|
-
other = Relation.create(
|
26
|
+
other = Relation.create(
|
27
|
+
relation.klass,
|
28
|
+
table: relation.table,
|
29
|
+
predicate_builder: relation.predicate_builder
|
30
|
+
)
|
25
31
|
hash.each { |k, v|
|
26
32
|
if k == :joins
|
27
33
|
if Hash === v
|
@@ -50,7 +56,7 @@ module ActiveRecord
|
|
50
56
|
|
51
57
|
NORMAL_VALUES = Relation::VALUE_METHODS -
|
52
58
|
Relation::CLAUSE_METHODS -
|
53
|
-
[:includes, :preload, :joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
|
59
|
+
[:includes, :preload, :joins, :left_outer_joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
|
54
60
|
|
55
61
|
def normal_values
|
56
62
|
NORMAL_VALUES
|
@@ -77,6 +83,7 @@ module ActiveRecord
|
|
77
83
|
merge_clauses
|
78
84
|
merge_preloads
|
79
85
|
merge_joins
|
86
|
+
merge_outer_joins
|
80
87
|
|
81
88
|
relation
|
82
89
|
end
|
@@ -110,21 +117,39 @@ module ActiveRecord
|
|
110
117
|
if other.klass == relation.klass
|
111
118
|
relation.joins!(*other.joins_values)
|
112
119
|
else
|
113
|
-
joins_dependency
|
120
|
+
joins_dependency = other.joins_values.map do |join|
|
114
121
|
case join
|
115
122
|
when Hash, Symbol, Array
|
116
|
-
|
123
|
+
ActiveRecord::Associations::JoinDependency.new(
|
124
|
+
other.klass, other.table, join
|
125
|
+
)
|
117
126
|
else
|
118
|
-
|
127
|
+
join
|
119
128
|
end
|
120
129
|
end
|
121
130
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
relation.joins! rest
|
131
|
+
relation.joins!(*joins_dependency)
|
132
|
+
end
|
133
|
+
end
|
126
134
|
|
127
|
-
|
135
|
+
def merge_outer_joins
|
136
|
+
return if other.left_outer_joins_values.blank?
|
137
|
+
|
138
|
+
if other.klass == relation.klass
|
139
|
+
relation.left_outer_joins!(*other.left_outer_joins_values)
|
140
|
+
else
|
141
|
+
joins_dependency = other.left_outer_joins_values.map do |join|
|
142
|
+
case join
|
143
|
+
when Hash, Symbol, Array
|
144
|
+
ActiveRecord::Associations::JoinDependency.new(
|
145
|
+
other.klass, other.table, join
|
146
|
+
)
|
147
|
+
else
|
148
|
+
join
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
relation.left_outer_joins!(*joins_dependency)
|
128
153
|
end
|
129
154
|
end
|
130
155
|
|
@@ -132,19 +157,17 @@ module ActiveRecord
|
|
132
157
|
if other.reordering_value
|
133
158
|
# override any order specified in the original relation
|
134
159
|
relation.reorder! other.order_values
|
135
|
-
elsif other.order_values
|
160
|
+
elsif other.order_values.any?
|
136
161
|
# merge in order_values from relation
|
137
162
|
relation.order! other.order_values
|
138
163
|
end
|
139
164
|
|
140
|
-
|
165
|
+
extensions = other.extensions - relation.extensions
|
166
|
+
relation.extending!(*extensions) if extensions.any?
|
141
167
|
end
|
142
168
|
|
143
169
|
def merge_single_values
|
144
|
-
if
|
145
|
-
relation.from_clause = other.from_clause
|
146
|
-
end
|
147
|
-
relation.lock_value ||= other.lock_value
|
170
|
+
relation.lock_value ||= other.lock_value if other.lock_value
|
148
171
|
|
149
172
|
unless other.create_with_value.blank?
|
150
173
|
relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
|
@@ -152,11 +175,15 @@ module ActiveRecord
|
|
152
175
|
end
|
153
176
|
|
154
177
|
def merge_clauses
|
155
|
-
|
156
|
-
|
157
|
-
other_clause = other.get_value(method)
|
158
|
-
relation.set_value(method, clause.merge(other_clause))
|
178
|
+
if relation.from_clause.empty? && !other.from_clause.empty?
|
179
|
+
relation.from_clause = other.from_clause
|
159
180
|
end
|
181
|
+
|
182
|
+
where_clause = relation.where_clause.merge(other.where_clause)
|
183
|
+
relation.where_clause = where_clause unless where_clause.empty?
|
184
|
+
|
185
|
+
having_clause = relation.having_clause.merge(other.having_clause)
|
186
|
+
relation.having_clause = having_clause unless having_clause.empty?
|
160
187
|
end
|
161
188
|
end
|
162
189
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class PredicateBuilder
|
3
5
|
class ArrayHandler # :nodoc:
|
@@ -6,18 +8,21 @@ module ActiveRecord
|
|
6
8
|
end
|
7
9
|
|
8
10
|
def call(attribute, value)
|
11
|
+
return attribute.in([]) if value.empty?
|
12
|
+
|
9
13
|
values = value.map { |x| x.is_a?(Base) ? x.id : x }
|
10
14
|
nils, values = values.partition(&:nil?)
|
11
|
-
|
12
|
-
return attribute.in([]) if values.empty? && nils.empty?
|
13
|
-
|
14
15
|
ranges, values = values.partition { |v| v.is_a?(Range) }
|
15
16
|
|
16
17
|
values_predicate =
|
17
18
|
case values.length
|
18
19
|
when 0 then NullPredicate
|
19
20
|
when 1 then predicate_builder.build(attribute, values.first)
|
20
|
-
else
|
21
|
+
else
|
22
|
+
bind_values = values.map do |v|
|
23
|
+
predicate_builder.build_bind_attribute(attribute.name, v)
|
24
|
+
end
|
25
|
+
attribute.in(bind_values)
|
21
26
|
end
|
22
27
|
|
23
28
|
unless nils.empty?
|
@@ -26,11 +31,9 @@ module ActiveRecord
|
|
26
31
|
|
27
32
|
array_predicates = ranges.map { |range| predicate_builder.build(attribute, range) }
|
28
33
|
array_predicates.unshift(values_predicate)
|
29
|
-
array_predicates.inject
|
34
|
+
array_predicates.inject(&:or)
|
30
35
|
end
|
31
36
|
|
32
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
33
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
34
37
|
protected
|
35
38
|
|
36
39
|
attr_reader :predicate_builder
|