Module: NoBrainer::Document::Association::EagerLoader::Generic

Included in:
BelongsTo::Metadata, HasMany::Metadata
Defined in:
lib/no_brainer/document/association/eager_loader.rb

Instance Method Summary collapse

Instance Method Details

#eager_load(docs, additional_criteria = nil) ⇒ Object

Used in associations to declare generic eager loading capabilities The association should implement loaded?, preload, eager_load_owner_key and eager_load_target_key.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/no_brainer/document/association/eager_loader.rb', line 10

def eager_load(docs, additional_criteria = nil)
  owner_key  = eager_load_owner_key
  owner_type = eager_load_owner_type
  target_key = eager_load_target_key

  if is_a?(NoBrainer::Document::Association::BelongsTo::Metadata) && owner_type
    target_class = docs.first.__send__(owner_type)

    if docs.detect { |doc| doc.__send__(owner_type) != target_class }
      raise NoBrainer::Error::PolymorphicAssociationWithDifferentTypes,
            "The documents to be eager loaded doesn't have the same " \
            'type, which is not supported'
    end
  end

  criteria = target_class ? base_criteria(target_class) : base_criteria
  criteria = criteria.merge(additional_criteria) if additional_criteria

  unloaded_docs = docs.reject { |doc| doc.associations[self].loaded? }

  owner_keys = unloaded_docs.map(&owner_key).compact.uniq
  if owner_keys.present?
    targets = criteria.where(target_key.in => owner_keys)
    .map { |target| [target.read_attribute(target_key), target] }
    .each_with_object(Hash.new { |k,v| k[v] = [] }) { |(k,v),h| h[k] << v }

    unloaded_docs.each do |doc|
      doc_targets = targets[doc.read_attribute(owner_key)]
      doc.associations[self].preload(doc_targets)
    end
  end

  docs.map { |doc| doc.associations[self].read }.flatten.compact.uniq
end