mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Fuse traversals of the record set when preloading
Although consuming code will almost certainly retraverse this set, we can avoid walking it twice here. As an extra upside, we can avoid the double-use of an identity-sensitive hash; this is convenient, because it is another collection we actually don't need to build.
This commit is contained in:
parent
9aa59f9d4a
commit
989dda36d6
1 changed files with 27 additions and 25 deletions
|
@ -27,40 +27,42 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def records_by_owner
|
||||
# owners can be duplicated when a relation has a collection association join
|
||||
# #compare_by_identity makes such owners different hash keys
|
||||
@records_by_owner ||= preloaded_records.each_with_object({}.compare_by_identity) do |record, result|
|
||||
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
||||
(result[owner] ||= []) << record
|
||||
end
|
||||
end
|
||||
load_records unless defined?(@records_by_owner)
|
||||
|
||||
@records_by_owner
|
||||
end
|
||||
|
||||
def preloaded_records
|
||||
return @preloaded_records if defined?(@preloaded_records)
|
||||
load_records unless defined?(@preloaded_records)
|
||||
|
||||
raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
|
||||
seen_records_by_owner = {}.compare_by_identity
|
||||
|
||||
@preloaded_records = raw_records.select do |record|
|
||||
assignments = []
|
||||
|
||||
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
||||
entries = (seen_records_by_owner[owner] ||= [])
|
||||
|
||||
if reflection.collection? || entries.empty?
|
||||
entries << record
|
||||
assignments << record
|
||||
end
|
||||
end
|
||||
|
||||
!assignments.empty?
|
||||
end
|
||||
@preloaded_records
|
||||
end
|
||||
|
||||
private
|
||||
attr_reader :owners, :reflection, :preload_scope, :model, :klass
|
||||
|
||||
def load_records
|
||||
# owners can be duplicated when a relation has a collection association join
|
||||
# #compare_by_identity makes such owners different hash keys
|
||||
@records_by_owner = {}.compare_by_identity
|
||||
raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
|
||||
|
||||
@preloaded_records = raw_records.select do |record|
|
||||
assignments = []
|
||||
|
||||
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
||||
entries = (@records_by_owner[owner] ||= [])
|
||||
|
||||
if reflection.collection? || entries.empty?
|
||||
entries << record
|
||||
assignments << record
|
||||
end
|
||||
end
|
||||
|
||||
!assignments.empty?
|
||||
end
|
||||
end
|
||||
|
||||
# The name of the key on the associated records
|
||||
def association_key_name
|
||||
reflection.join_primary_key(klass)
|
||||
|
|
Loading…
Reference in a new issue