activerecord 6.0.0 → 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 +872 -582
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations.rb +116 -13
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -29
- data/lib/active_record/associations/association_scope.rb +17 -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 -3
- 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 +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- 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.rb +77 -42
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +86 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +4 -9
- 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 +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- 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/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- 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 +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- 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 +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- 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 +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +81 -57
- 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 +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +211 -81
- data/lib/active_record/core.rb +237 -69
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations.rb +124 -85
- 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 -41
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- 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 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +39 -10
- 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 +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +108 -67
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- 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/query_methods.rb +340 -180
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/result.rb +41 -34
- 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.rb +0 -1
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- 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 +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +22 -71
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +15 -12
- 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.rb +3 -1
- 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/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +6 -2
- 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 +4 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -24
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- 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 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "mutex_m"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
module Delegation # :nodoc:
|
@@ -59,16 +60,18 @@ module ActiveRecord
|
|
59
60
|
synchronize do
|
60
61
|
return if method_defined?(method)
|
61
62
|
|
62
|
-
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
|
63
|
+
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
|
64
|
+
definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
|
63
65
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
64
|
-
def #{method}(
|
65
|
-
scoping { klass.#{method}(
|
66
|
+
def #{method}(#{definition})
|
67
|
+
scoping { klass.#{method}(#{definition}) }
|
66
68
|
end
|
67
69
|
RUBY
|
68
70
|
else
|
69
71
|
define_method(method) do |*args, &block|
|
70
72
|
scoping { klass.public_send(method, *args, &block) }
|
71
73
|
end
|
74
|
+
ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
|
72
75
|
end
|
73
76
|
end
|
74
77
|
end
|
@@ -99,7 +102,6 @@ module ActiveRecord
|
|
99
102
|
end
|
100
103
|
|
101
104
|
private
|
102
|
-
|
103
105
|
def method_missing(method, *args, &block)
|
104
106
|
if @klass.respond_to?(method)
|
105
107
|
@klass.generate_relation_method(method)
|
@@ -108,15 +110,15 @@ module ActiveRecord
|
|
108
110
|
super
|
109
111
|
end
|
110
112
|
end
|
113
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
111
114
|
end
|
112
115
|
|
113
116
|
module ClassMethods # :nodoc:
|
114
|
-
def create(klass, *args)
|
115
|
-
relation_class_for(klass).new(klass, *args)
|
117
|
+
def create(klass, *args, **kwargs)
|
118
|
+
relation_class_for(klass).new(klass, *args, **kwargs)
|
116
119
|
end
|
117
120
|
|
118
121
|
private
|
119
|
-
|
120
122
|
def relation_class_for(klass)
|
121
123
|
klass.relation_delegate_class(self)
|
122
124
|
end
|
@@ -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?
|
316
319
|
|
317
|
-
skip_query_cache_if_necessary { connection.
|
320
|
+
skip_query_cache_if_necessary { connection.select_rows(relation.arel, "#{name} Exists?").size == 1 }
|
318
321
|
end
|
319
322
|
|
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
|
334
|
+
end
|
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,9 +364,15 @@ module ActiveRecord
|
|
346
364
|
end
|
347
365
|
|
348
366
|
private
|
349
|
-
|
350
|
-
|
351
|
-
|
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
|
352
376
|
end
|
353
377
|
|
354
378
|
def construct_relation_for_exists(conditions)
|
@@ -372,11 +396,20 @@ module ActiveRecord
|
|
372
396
|
|
373
397
|
def apply_join_dependency(eager_loading: group_values.empty?)
|
374
398
|
join_dependency = construct_join_dependency(
|
375
|
-
eager_load_values
|
399
|
+
eager_load_values | includes_values, Arel::Nodes::OuterJoin
|
376
400
|
)
|
377
401
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
378
402
|
|
379
|
-
if eager_loading && !
|
403
|
+
if eager_loading && !(
|
404
|
+
using_limitable_reflections?(join_dependency.reflections) &&
|
405
|
+
using_limitable_reflections?(
|
406
|
+
construct_join_dependency(
|
407
|
+
select_association_list(joins_values).concat(
|
408
|
+
select_association_list(left_outer_joins_values)
|
409
|
+
), nil
|
410
|
+
).reflections
|
411
|
+
)
|
412
|
+
)
|
380
413
|
if has_limit_or_offset?
|
381
414
|
limited_ids = limited_ids_for(relation)
|
382
415
|
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
@@ -393,14 +426,14 @@ module ActiveRecord
|
|
393
426
|
|
394
427
|
def limited_ids_for(relation)
|
395
428
|
values = @klass.connection.columns_for_distinct(
|
396
|
-
connection.visitor.compile(
|
429
|
+
connection.visitor.compile(table[primary_key]),
|
397
430
|
relation.order_values
|
398
431
|
)
|
399
432
|
|
400
433
|
relation = relation.except(:select).select(values).distinct!
|
401
434
|
|
402
|
-
id_rows = skip_query_cache_if_necessary { @klass.connection.
|
403
|
-
id_rows.map
|
435
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_rows(relation.arel, "SQL") }
|
436
|
+
id_rows.map(&:last)
|
404
437
|
end
|
405
438
|
|
406
439
|
def using_limitable_reflections?(reflections)
|
@@ -501,7 +534,8 @@ module ActiveRecord
|
|
501
534
|
end
|
502
535
|
|
503
536
|
def find_nth(index)
|
504
|
-
@offsets
|
537
|
+
@offsets ||= {}
|
538
|
+
@offsets[index] ||= find_nth_with_limit(index, 1).first
|
505
539
|
end
|
506
540
|
|
507
541
|
def find_nth_with_limit(index, limit)
|
@@ -515,7 +549,7 @@ module ActiveRecord
|
|
515
549
|
end
|
516
550
|
|
517
551
|
if limit > 0
|
518
|
-
relation = relation.offset(
|
552
|
+
relation = relation.offset((offset_value || 0) + index) unless index.zero?
|
519
553
|
relation.limit(limit).to_a
|
520
554
|
else
|
521
555
|
[]
|
@@ -543,7 +577,11 @@ module ActiveRecord
|
|
543
577
|
|
544
578
|
def ordered_relation
|
545
579
|
if order_values.empty? && (implicit_order_column || primary_key)
|
546
|
-
|
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
|
547
585
|
else
|
548
586
|
self
|
549
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
|
@@ -89,13 +86,12 @@ module ActiveRecord
|
|
89
86
|
end
|
90
87
|
|
91
88
|
private
|
92
|
-
|
93
89
|
def merge_preloads
|
94
90
|
return if other.preload_values.empty? && other.includes_values.empty?
|
95
91
|
|
96
92
|
if other.klass == relation.klass
|
97
|
-
relation.
|
98
|
-
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?
|
99
95
|
else
|
100
96
|
reflection = relation.klass.reflect_on_all_associations.find do |r|
|
101
97
|
r.class_name == other.klass.name
|
@@ -112,10 +108,10 @@ module ActiveRecord
|
|
112
108
|
end
|
113
109
|
|
114
110
|
def merge_joins
|
115
|
-
return if other.joins_values.
|
111
|
+
return if other.joins_values.empty?
|
116
112
|
|
117
113
|
if other.klass == relation.klass
|
118
|
-
relation.
|
114
|
+
relation.joins_values |= other.joins_values
|
119
115
|
else
|
120
116
|
associations, others = other.joins_values.partition do |join|
|
121
117
|
case join
|
@@ -131,16 +127,21 @@ module ActiveRecord
|
|
131
127
|
end
|
132
128
|
|
133
129
|
def merge_outer_joins
|
134
|
-
return if other.left_outer_joins_values.
|
130
|
+
return if other.left_outer_joins_values.empty?
|
135
131
|
|
136
132
|
if other.klass == relation.klass
|
137
|
-
relation.
|
133
|
+
relation.left_outer_joins_values |= other.left_outer_joins_values
|
138
134
|
else
|
139
|
-
associations = other.left_outer_joins_values
|
135
|
+
associations, others = other.left_outer_joins_values.partition do |join|
|
136
|
+
case join
|
137
|
+
when Hash, Symbol, Array; true
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
140
141
|
join_dependency = other.construct_join_dependency(
|
141
142
|
associations, Arel::Nodes::OuterJoin
|
142
143
|
)
|
143
|
-
relation.
|
144
|
+
relation.left_outer_joins!(join_dependency, *others)
|
144
145
|
end
|
145
146
|
end
|
146
147
|
|
@@ -168,7 +169,7 @@ module ActiveRecord
|
|
168
169
|
def merge_clauses
|
169
170
|
relation.from_clause = other.from_clause if replace_from_clause?
|
170
171
|
|
171
|
-
where_clause = relation.where_clause.merge(other.where_clause)
|
172
|
+
where_clause = relation.where_clause.merge(other.where_clause, @rewhere)
|
172
173
|
relation.where_clause = where_clause unless where_clause.empty?
|
173
174
|
|
174
175
|
having_clause = relation.having_clause.merge(other.having_clause)
|
@@ -2,34 +2,41 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class PredicateBuilder # :nodoc:
|
5
|
-
|
5
|
+
require "active_record/relation/predicate_builder/array_handler"
|
6
|
+
require "active_record/relation/predicate_builder/basic_object_handler"
|
7
|
+
require "active_record/relation/predicate_builder/range_handler"
|
8
|
+
require "active_record/relation/predicate_builder/relation_handler"
|
9
|
+
require "active_record/relation/predicate_builder/association_query_value"
|
10
|
+
require "active_record/relation/predicate_builder/polymorphic_array_value"
|
11
|
+
|
12
|
+
# No-op BaseHandler to work Mashal.load(File.read("legacy_relation.dump")).
|
13
|
+
# TODO: Remove the constant alias once Rails 6.1 has released.
|
14
|
+
BaseHandler = BasicObjectHandler
|
6
15
|
|
7
16
|
def initialize(table)
|
8
17
|
@table = table
|
9
18
|
@handlers = []
|
10
19
|
|
11
20
|
register_handler(BasicObject, BasicObjectHandler.new(self))
|
12
|
-
register_handler(Base, BaseHandler.new(self))
|
13
21
|
register_handler(Range, RangeHandler.new(self))
|
14
22
|
register_handler(Relation, RelationHandler.new)
|
15
23
|
register_handler(Array, ArrayHandler.new(self))
|
16
24
|
register_handler(Set, ArrayHandler.new(self))
|
17
25
|
end
|
18
26
|
|
19
|
-
def build_from_hash(attributes)
|
27
|
+
def build_from_hash(attributes, &block)
|
20
28
|
attributes = convert_dot_notation_to_hash(attributes)
|
21
|
-
expand_from_hash(attributes)
|
29
|
+
expand_from_hash(attributes, &block)
|
22
30
|
end
|
23
31
|
|
24
32
|
def self.references(attributes)
|
25
|
-
attributes.
|
33
|
+
attributes.each_with_object([]) do |(key, value), result|
|
26
34
|
if value.is_a?(Hash)
|
27
|
-
key
|
28
|
-
|
29
|
-
|
30
|
-
key.split(".").first if key.include?(".")
|
35
|
+
result << Arel.sql(key)
|
36
|
+
elsif key.include?(".")
|
37
|
+
result << Arel.sql(key.split(".").first)
|
31
38
|
end
|
32
|
-
end
|
39
|
+
end
|
33
40
|
end
|
34
41
|
|
35
42
|
# Define how a class is converted to Arel nodes when passed to +where+.
|
@@ -47,27 +54,37 @@ module ActiveRecord
|
|
47
54
|
@handlers.unshift([klass, handler])
|
48
55
|
end
|
49
56
|
|
50
|
-
def
|
51
|
-
|
57
|
+
def [](attr_name, value, operator = nil)
|
58
|
+
build(table.arel_table[attr_name], value, operator)
|
59
|
+
end
|
60
|
+
|
61
|
+
def build(attribute, value, operator = nil)
|
62
|
+
value = value.id if value.respond_to?(:id)
|
63
|
+
if operator ||= table.type(attribute.name).force_equality?(value) && :eq
|
52
64
|
bind = build_bind_attribute(attribute.name, value)
|
53
|
-
attribute.
|
65
|
+
attribute.public_send(operator, bind)
|
54
66
|
else
|
55
67
|
handler_for(value).call(attribute, value)
|
56
68
|
end
|
57
69
|
end
|
58
70
|
|
59
71
|
def build_bind_attribute(column_name, value)
|
60
|
-
attr = Relation::QueryAttribute.new(column_name
|
72
|
+
attr = Relation::QueryAttribute.new(column_name, value, table.type(column_name))
|
61
73
|
Arel::Nodes::BindParam.new(attr)
|
62
74
|
end
|
63
75
|
|
76
|
+
def resolve_arel_attribute(table_name, column_name, &block)
|
77
|
+
table.associated_table(table_name, &block).arel_table[column_name]
|
78
|
+
end
|
79
|
+
|
64
80
|
protected
|
65
|
-
def expand_from_hash(attributes)
|
81
|
+
def expand_from_hash(attributes, &block)
|
66
82
|
return ["1=0"] if attributes.empty?
|
67
83
|
|
68
84
|
attributes.flat_map do |key, value|
|
69
85
|
if value.is_a?(Hash) && !table.has_column?(key)
|
70
|
-
|
86
|
+
table.associated_table(key, &block)
|
87
|
+
.predicate_builder.expand_from_hash(value.stringify_keys)
|
71
88
|
elsif table.associated_with?(key)
|
72
89
|
# Find the foreign key when using queries such as:
|
73
90
|
# Post.where(author: author)
|
@@ -81,13 +98,18 @@ module ActiveRecord
|
|
81
98
|
value = [value] unless value.is_a?(Array)
|
82
99
|
klass = PolymorphicArrayValue
|
83
100
|
end
|
101
|
+
elsif associated_table.through_association?
|
102
|
+
next associated_table.predicate_builder.expand_from_hash(
|
103
|
+
associated_table.primary_key => value
|
104
|
+
)
|
84
105
|
end
|
85
106
|
|
86
107
|
klass ||= AssociationQueryValue
|
87
|
-
queries = klass.new(associated_table, value).queries.map do |query|
|
88
|
-
expand_from_hash(query)
|
108
|
+
queries = klass.new(associated_table, value).queries.map! do |query|
|
109
|
+
expand_from_hash(query)
|
89
110
|
end
|
90
|
-
|
111
|
+
|
112
|
+
grouping_queries(queries)
|
91
113
|
elsif table.aggregated_with?(key)
|
92
114
|
mapping = table.reflect_on_aggregation(key).mapping
|
93
115
|
values = value.nil? ? [nil] : Array.wrap(value)
|
@@ -96,17 +118,18 @@ module ActiveRecord
|
|
96
118
|
values = values.map do |object|
|
97
119
|
object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
|
98
120
|
end
|
99
|
-
|
121
|
+
self[column_name, values]
|
100
122
|
else
|
101
123
|
queries = values.map do |object|
|
102
124
|
mapping.map do |field_attr, aggregate_attr|
|
103
|
-
|
104
|
-
end
|
125
|
+
self[field_attr, object.try!(aggregate_attr)]
|
126
|
+
end
|
105
127
|
end
|
106
|
-
|
128
|
+
|
129
|
+
grouping_queries(queries)
|
107
130
|
end
|
108
131
|
else
|
109
|
-
|
132
|
+
self[key, value]
|
110
133
|
end
|
111
134
|
end
|
112
135
|
end
|
@@ -114,8 +137,14 @@ module ActiveRecord
|
|
114
137
|
private
|
115
138
|
attr_reader :table
|
116
139
|
|
117
|
-
def
|
118
|
-
|
140
|
+
def grouping_queries(queries)
|
141
|
+
if queries.one?
|
142
|
+
queries.first
|
143
|
+
else
|
144
|
+
queries.map! { |query| query.reduce(&:and) }
|
145
|
+
queries = queries.reduce { |result, query| Arel::Nodes::Or.new(result, query) }
|
146
|
+
Arel::Nodes::Grouping.new(queries)
|
147
|
+
end
|
119
148
|
end
|
120
149
|
|
121
150
|
def convert_dot_notation_to_hash(attributes)
|
@@ -139,12 +168,3 @@ module ActiveRecord
|
|
139
168
|
end
|
140
169
|
end
|
141
170
|
end
|
142
|
-
|
143
|
-
require "active_record/relation/predicate_builder/array_handler"
|
144
|
-
require "active_record/relation/predicate_builder/base_handler"
|
145
|
-
require "active_record/relation/predicate_builder/basic_object_handler"
|
146
|
-
require "active_record/relation/predicate_builder/range_handler"
|
147
|
-
require "active_record/relation/predicate_builder/relation_handler"
|
148
|
-
|
149
|
-
require "active_record/relation/predicate_builder/association_query_value"
|
150
|
-
require "active_record/relation/predicate_builder/polymorphic_array_value"
|