activerecord 6.0.0 → 6.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1045 -575
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +5 -6
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations.rb +120 -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 +19 -15
- data/lib/active_record/associations/belongs_to_association.rb +22 -8
- 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 -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 +39 -16
- 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 +33 -9
- 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 +87 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
- 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 +141 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -77
- 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 +18 -3
- 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 +5 -2
- 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 +73 -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/money.rb +2 -2
- 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 +83 -65
- 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 +219 -81
- data/lib/active_record/core.rb +253 -67
- 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 +82 -38
- 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 +58 -12
- data/lib/active_record/gem_version.rb +2 -2
- 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 +33 -18
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +28 -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 +115 -85
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +71 -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/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +277 -97
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +107 -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 +59 -40
- 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/query_methods.rb +343 -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 +107 -61
- 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 +42 -36
- data/lib/active_record/tasks/database_tasks.rb +140 -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 +26 -73
- 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 +30 -27
- 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
@@ -32,6 +32,18 @@ module ActiveRecord
|
|
32
32
|
target.destroyed_by_association = reflection
|
33
33
|
target.destroy
|
34
34
|
throw(:abort) unless target.destroyed?
|
35
|
+
when :destroy_async
|
36
|
+
primary_key_column = target.class.primary_key.to_sym
|
37
|
+
id = target.public_send(primary_key_column)
|
38
|
+
|
39
|
+
enqueue_destroy_association(
|
40
|
+
owner_model_name: owner.class.to_s,
|
41
|
+
owner_id: owner.id,
|
42
|
+
association_class: reflection.klass.to_s,
|
43
|
+
association_ids: [id],
|
44
|
+
association_primary_key_column: primary_key_column,
|
45
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
46
|
+
)
|
35
47
|
when :nullify
|
36
48
|
target.update_columns(nullified_owner_attributes) if target.persisted?
|
37
49
|
end
|
@@ -81,7 +93,9 @@ module ActiveRecord
|
|
81
93
|
target.delete
|
82
94
|
when :destroy
|
83
95
|
target.destroyed_by_association = reflection
|
84
|
-
target.
|
96
|
+
if target.persisted?
|
97
|
+
target.destroy
|
98
|
+
end
|
85
99
|
else
|
86
100
|
nullify_owner_attributes(target)
|
87
101
|
remove_inverse_instance(target)
|
@@ -34,7 +34,7 @@ module ActiveRecord
|
|
34
34
|
Table = Struct.new(:node, :columns) do # :nodoc:
|
35
35
|
def column_aliases
|
36
36
|
t = node.table
|
37
|
-
columns.map { |column| t[column.name].as
|
37
|
+
columns.map { |column| t[column.name].as(column.alias) }
|
38
38
|
end
|
39
39
|
end
|
40
40
|
Column = Struct.new(:name, :alias)
|
@@ -70,18 +70,26 @@ module ActiveRecord
|
|
70
70
|
@join_type = join_type
|
71
71
|
end
|
72
72
|
|
73
|
+
def base_klass
|
74
|
+
join_root.base_klass
|
75
|
+
end
|
76
|
+
|
73
77
|
def reflections
|
74
78
|
join_root.drop(1).map!(&:reflection)
|
75
79
|
end
|
76
80
|
|
77
|
-
def join_constraints(joins_to_add, alias_tracker)
|
81
|
+
def join_constraints(joins_to_add, alias_tracker, references)
|
78
82
|
@alias_tracker = alias_tracker
|
83
|
+
@joined_tables = {}
|
84
|
+
@references = {}
|
85
|
+
|
86
|
+
references.each do |table_name|
|
87
|
+
@references[table_name.to_sym] = table_name if table_name.is_a?(Arel::Nodes::SqlLiteral)
|
88
|
+
end unless references.empty?
|
79
89
|
|
80
|
-
construct_tables!(join_root)
|
81
90
|
joins = make_join_constraints(join_root, join_type)
|
82
91
|
|
83
92
|
joins.concat joins_to_add.flat_map { |oj|
|
84
|
-
construct_tables!(oj.join_root)
|
85
93
|
if join_root.match? oj.join_root
|
86
94
|
walk(join_root, oj.join_root, oj.join_type)
|
87
95
|
else
|
@@ -90,18 +98,35 @@ module ActiveRecord
|
|
90
98
|
}
|
91
99
|
end
|
92
100
|
|
93
|
-
def instantiate(result_set, &block)
|
101
|
+
def instantiate(result_set, strict_loading_value, &block)
|
94
102
|
primary_key = aliases.column_alias(join_root, join_root.primary_key)
|
95
103
|
|
96
|
-
seen = Hash.new { |i,
|
97
|
-
i[
|
104
|
+
seen = Hash.new { |i, parent|
|
105
|
+
i[parent] = Hash.new { |j, child_class|
|
98
106
|
j[child_class] = {}
|
99
107
|
}
|
100
|
-
}
|
108
|
+
}.compare_by_identity
|
101
109
|
|
102
110
|
model_cache = Hash.new { |h, klass| h[klass] = {} }
|
103
111
|
parents = model_cache[join_root]
|
104
|
-
|
112
|
+
|
113
|
+
column_aliases = aliases.column_aliases(join_root)
|
114
|
+
column_names = []
|
115
|
+
|
116
|
+
result_set.columns.each do |name|
|
117
|
+
column_names << name unless /\At\d+_r\d+\z/.match?(name)
|
118
|
+
end
|
119
|
+
|
120
|
+
if column_names.empty?
|
121
|
+
column_types = {}
|
122
|
+
else
|
123
|
+
column_types = result_set.column_types
|
124
|
+
unless column_types.empty?
|
125
|
+
attribute_types = join_root.attribute_types
|
126
|
+
column_types = column_types.slice(*column_names).delete_if { |k, _| attribute_types.key?(k) }
|
127
|
+
end
|
128
|
+
column_aliases += column_names.map! { |name| Aliases::Column.new(name, name) }
|
129
|
+
end
|
105
130
|
|
106
131
|
message_bus = ActiveSupport::Notifications.instrumenter
|
107
132
|
|
@@ -113,8 +138,8 @@ module ActiveRecord
|
|
113
138
|
message_bus.instrument("instantiation.active_record", payload) do
|
114
139
|
result_set.each { |row_hash|
|
115
140
|
parent_key = primary_key ? row_hash[primary_key] : row_hash
|
116
|
-
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
|
117
|
-
construct(parent, join_root, row_hash, seen, model_cache)
|
141
|
+
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, column_types, &block)
|
142
|
+
construct(parent, join_root, row_hash, seen, model_cache, strict_loading_value)
|
118
143
|
}
|
119
144
|
end
|
120
145
|
|
@@ -122,30 +147,36 @@ module ActiveRecord
|
|
122
147
|
end
|
123
148
|
|
124
149
|
def apply_column_aliases(relation)
|
150
|
+
@join_root_alias = relation.select_values.empty?
|
125
151
|
relation._select!(-> { aliases.columns })
|
126
152
|
end
|
127
153
|
|
154
|
+
def each(&block)
|
155
|
+
join_root.each(&block)
|
156
|
+
end
|
157
|
+
|
128
158
|
protected
|
129
159
|
attr_reader :join_root, :join_type
|
130
160
|
|
131
161
|
private
|
132
|
-
attr_reader :alias_tracker
|
162
|
+
attr_reader :alias_tracker, :join_root_alias
|
133
163
|
|
134
164
|
def aliases
|
135
165
|
@aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
|
136
|
-
|
166
|
+
column_names = if join_part == join_root && !join_root_alias
|
167
|
+
primary_key = join_root.primary_key
|
168
|
+
primary_key ? [primary_key] : []
|
169
|
+
else
|
170
|
+
join_part.column_names
|
171
|
+
end
|
172
|
+
|
173
|
+
columns = column_names.each_with_index.map { |column_name, j|
|
137
174
|
Aliases::Column.new column_name, "t#{i}_r#{j}"
|
138
175
|
}
|
139
176
|
Aliases::Table.new(join_part, columns)
|
140
177
|
}
|
141
178
|
end
|
142
179
|
|
143
|
-
def construct_tables!(join_root)
|
144
|
-
join_root.each_children do |parent, child|
|
145
|
-
child.tables = table_aliases_for(parent, child)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
180
|
def make_join_constraints(join_root, join_type)
|
150
181
|
join_root.children.flat_map do |child|
|
151
182
|
make_constraints(join_root, child, join_type)
|
@@ -155,23 +186,25 @@ module ActiveRecord
|
|
155
186
|
def make_constraints(parent, child, join_type)
|
156
187
|
foreign_table = parent.table
|
157
188
|
foreign_klass = parent.base_klass
|
158
|
-
|
159
|
-
|
160
|
-
|
189
|
+
child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection|
|
190
|
+
table, terminated = @joined_tables[reflection]
|
191
|
+
root = reflection == child.reflection
|
161
192
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
193
|
+
if table && (!root || !terminated)
|
194
|
+
@joined_tables[reflection] = [table, root] if root
|
195
|
+
next table, true
|
196
|
+
end
|
197
|
+
|
198
|
+
table_name = @references[reflection.name.to_sym]&.to_s
|
199
|
+
|
200
|
+
table = alias_tracker.aliased_table_for(reflection.klass.arel_table, table_name) do
|
201
|
+
name = reflection.alias_candidate(parent.table_name)
|
202
|
+
root ? name : "#{name}_join"
|
203
|
+
end
|
171
204
|
|
172
|
-
|
173
|
-
|
174
|
-
|
205
|
+
@joined_tables[reflection] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
|
206
|
+
table
|
207
|
+
end.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
175
208
|
end
|
176
209
|
|
177
210
|
def walk(left, right, join_type)
|
@@ -202,7 +235,7 @@ module ActiveRecord
|
|
202
235
|
end
|
203
236
|
end
|
204
237
|
|
205
|
-
def construct(ar_parent, parent, row, seen, model_cache)
|
238
|
+
def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
|
206
239
|
return if ar_parent.nil?
|
207
240
|
|
208
241
|
parent.children.each do |node|
|
@@ -211,7 +244,7 @@ module ActiveRecord
|
|
211
244
|
other.loaded!
|
212
245
|
elsif ar_parent.association_cached?(node.reflection.name)
|
213
246
|
model = ar_parent.association(node.reflection.name).target
|
214
|
-
construct(model, node, row, seen, model_cache)
|
247
|
+
construct(model, node, row, seen, model_cache, strict_loading_value)
|
215
248
|
next
|
216
249
|
end
|
217
250
|
|
@@ -223,24 +256,25 @@ module ActiveRecord
|
|
223
256
|
next
|
224
257
|
end
|
225
258
|
|
226
|
-
model = seen[ar_parent
|
259
|
+
model = seen[ar_parent][node][id]
|
227
260
|
|
228
261
|
if model
|
229
|
-
construct(model, node, row, seen, model_cache)
|
262
|
+
construct(model, node, row, seen, model_cache, strict_loading_value)
|
230
263
|
else
|
231
|
-
model = construct_model(ar_parent, node, row, model_cache, id)
|
264
|
+
model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
|
232
265
|
|
233
|
-
seen[ar_parent
|
234
|
-
construct(model, node, row, seen, model_cache)
|
266
|
+
seen[ar_parent][node][id] = model
|
267
|
+
construct(model, node, row, seen, model_cache, strict_loading_value)
|
235
268
|
end
|
236
269
|
end
|
237
270
|
end
|
238
271
|
|
239
|
-
def construct_model(record, node, row, model_cache, id)
|
272
|
+
def construct_model(record, node, row, model_cache, id, strict_loading_value)
|
240
273
|
other = record.association(node.reflection.name)
|
241
274
|
|
242
275
|
model = model_cache[node][id] ||=
|
243
276
|
node.instantiate(row, aliases.column_aliases(node)) do |m|
|
277
|
+
m.strict_loading! if strict_loading_value
|
244
278
|
other.set_inverse_instance(m)
|
245
279
|
end
|
246
280
|
|
@@ -251,6 +285,7 @@ module ActiveRecord
|
|
251
285
|
end
|
252
286
|
|
253
287
|
model.readonly! if node.readonly?
|
288
|
+
model.strict_loading! if node.strict_loading?
|
254
289
|
model
|
255
290
|
end
|
256
291
|
end
|
@@ -14,7 +14,6 @@ module ActiveRecord
|
|
14
14
|
super(reflection.klass, children)
|
15
15
|
|
16
16
|
@reflection = reflection
|
17
|
-
@tables = nil
|
18
17
|
end
|
19
18
|
|
20
19
|
def match?(other)
|
@@ -24,25 +23,47 @@ module ActiveRecord
|
|
24
23
|
|
25
24
|
def join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
26
25
|
joins = []
|
26
|
+
chain = []
|
27
|
+
|
28
|
+
reflection.chain.each do |reflection|
|
29
|
+
table, terminated = yield reflection
|
30
|
+
@table ||= table
|
31
|
+
|
32
|
+
if terminated
|
33
|
+
foreign_table, foreign_klass = table, reflection.klass
|
34
|
+
break
|
35
|
+
end
|
36
|
+
|
37
|
+
chain << [reflection, table]
|
38
|
+
end
|
27
39
|
|
28
40
|
# The chain starts with the target table, but we want to end with it here (makes
|
29
41
|
# more sense in this context), so we reverse
|
30
|
-
|
31
|
-
table = tables[-i]
|
42
|
+
chain.reverse_each do |reflection, table|
|
32
43
|
klass = reflection.klass
|
33
44
|
|
34
|
-
|
45
|
+
scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
46
|
+
|
47
|
+
unless scope.references_values.empty?
|
48
|
+
associations = scope.eager_load_values | scope.includes_values
|
35
49
|
|
36
|
-
|
50
|
+
unless associations.empty?
|
51
|
+
scope.joins! scope.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
arel = scope.arel(alias_tracker.aliases)
|
37
56
|
nodes = arel.constraints.first
|
38
57
|
|
39
|
-
|
40
|
-
|
58
|
+
if nodes.is_a?(Arel::Nodes::And)
|
59
|
+
others = nodes.children.extract! do |node|
|
60
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
61
|
+
end
|
41
62
|
end
|
42
63
|
|
43
|
-
joins <<
|
64
|
+
joins << join_type.new(table, Arel::Nodes::On.new(nodes))
|
44
65
|
|
45
|
-
|
66
|
+
if others && !others.empty?
|
46
67
|
joins.concat arel.join_sources
|
47
68
|
append_constraints(joins.last, others)
|
48
69
|
end
|
@@ -54,24 +75,26 @@ module ActiveRecord
|
|
54
75
|
joins
|
55
76
|
end
|
56
77
|
|
57
|
-
def tables=(tables)
|
58
|
-
@tables = tables
|
59
|
-
@table = tables.first
|
60
|
-
end
|
61
|
-
|
62
78
|
def readonly?
|
63
79
|
return @readonly if defined?(@readonly)
|
64
80
|
|
65
81
|
@readonly = reflection.scope && reflection.scope_for(base_klass.unscoped).readonly_value
|
66
82
|
end
|
67
83
|
|
84
|
+
def strict_loading?
|
85
|
+
return @strict_loading if defined?(@strict_loading)
|
86
|
+
|
87
|
+
@strict_loading = reflection.scope && reflection.scope_for(base_klass.unscoped).strict_loading_value
|
88
|
+
end
|
89
|
+
|
68
90
|
private
|
69
91
|
def append_constraints(join, constraints)
|
70
92
|
if join.is_a?(Arel::Nodes::StringJoin)
|
71
|
-
join_string =
|
93
|
+
join_string = Arel::Nodes::And.new(constraints.unshift join.left)
|
72
94
|
join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
|
73
95
|
else
|
74
|
-
join.right
|
96
|
+
right = join.right
|
97
|
+
right.expr = Arel::Nodes::And.new(constraints.unshift right.expr)
|
75
98
|
end
|
76
99
|
end
|
77
100
|
end
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
# association.
|
18
18
|
attr_reader :base_klass, :children
|
19
19
|
|
20
|
-
delegate :table_name, :column_names, :primary_key, to: :base_klass
|
20
|
+
delegate :table_name, :column_names, :primary_key, :attribute_types, to: :base_klass
|
21
21
|
|
22
22
|
def initialize(base_klass, children)
|
23
23
|
@base_klass = base_klass
|
@@ -62,8 +62,8 @@ module ActiveRecord
|
|
62
62
|
hash
|
63
63
|
end
|
64
64
|
|
65
|
-
def instantiate(row, aliases, &block)
|
66
|
-
base_klass.instantiate(extract_record(row, aliases), &block)
|
65
|
+
def instantiate(row, aliases, column_types = {}, &block)
|
66
|
+
base_klass.instantiate(extract_record(row, aliases), column_types, &block)
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
@@ -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 Associations
|
5
7
|
# Implements the details of eager loading of Active Record associations.
|
@@ -58,7 +60,7 @@ module ActiveRecord
|
|
58
60
|
# == Parameters
|
59
61
|
# +records+ is an array of ActiveRecord::Base. This array needs not be flat,
|
60
62
|
# i.e. +records+ itself may also contain arrays of records. In any case,
|
61
|
-
# +preload_associations+ will preload
|
63
|
+
# +preload_associations+ will preload all associations records by
|
62
64
|
# flattening +records+.
|
63
65
|
#
|
64
66
|
# +associations+ specifies one or more associations that you want to
|
@@ -94,8 +96,11 @@ module ActiveRecord
|
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
97
|
-
|
99
|
+
def initialize(associate_by_default: true)
|
100
|
+
@associate_by_default = associate_by_default
|
101
|
+
end
|
98
102
|
|
103
|
+
private
|
99
104
|
# Loads all the given data into +records+ for the +association+.
|
100
105
|
def preloaders_on(association, records, scope, polymorphic_parent = false)
|
101
106
|
case association
|
@@ -112,7 +117,7 @@ module ActiveRecord
|
|
112
117
|
association.flat_map { |parent, child|
|
113
118
|
grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
|
114
119
|
loaders = preloaders_for_reflection(reflection, reflection_records, scope)
|
115
|
-
recs = loaders.flat_map(&:preloaded_records)
|
120
|
+
recs = loaders.flat_map(&:preloaded_records).uniq
|
116
121
|
child_polymorphic_parent = reflection && reflection.options[:polymorphic]
|
117
122
|
loaders.concat Array.wrap(child).flat_map { |assoc|
|
118
123
|
preloaders_on assoc, recs, scope, child_polymorphic_parent
|
@@ -143,7 +148,7 @@ module ActiveRecord
|
|
143
148
|
|
144
149
|
def preloaders_for_reflection(reflection, records, scope)
|
145
150
|
records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
|
146
|
-
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope).run
|
151
|
+
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope, @associate_by_default).run
|
147
152
|
end
|
148
153
|
end
|
149
154
|
|
@@ -158,7 +163,7 @@ module ActiveRecord
|
|
158
163
|
end
|
159
164
|
|
160
165
|
class AlreadyLoaded # :nodoc:
|
161
|
-
def initialize(klass, owners, reflection, preload_scope)
|
166
|
+
def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
|
162
167
|
@owners = owners
|
163
168
|
@reflection = reflection
|
164
169
|
end
|
@@ -172,8 +177,8 @@ module ActiveRecord
|
|
172
177
|
end
|
173
178
|
|
174
179
|
def records_by_owner
|
175
|
-
@records_by_owner ||= owners.
|
176
|
-
|
180
|
+
@records_by_owner ||= owners.index_with do |owner|
|
181
|
+
Array(owner.association(reflection.name).target)
|
177
182
|
end
|
178
183
|
end
|
179
184
|
|
@@ -185,7 +190,7 @@ module ActiveRecord
|
|
185
190
|
# and attach it to a relation. The class returned implements a `run` method
|
186
191
|
# that accepts a preloader.
|
187
192
|
def preloader_for(reflection, owners)
|
188
|
-
if owners.
|
193
|
+
if owners.all? { |o| o.association(reflection.name).loaded? }
|
189
194
|
return AlreadyLoaded
|
190
195
|
end
|
191
196
|
reflection.check_preloadable!
|