Class: LcpRuby::DataSource::ApiPreloader

Inherits:
Object
  • Object
show all
Defined in:
lib/lcp_ruby/data_source/api_preloader.rb

Overview

Batch preloads API associations to prevent N+1 data source calls. Collects FK values from records, makes a single find_many call, and distributes results via instance variables.

Class Method Summary collapse

Class Method Details

.preload(records, assoc_name, assoc_def) ⇒ Object

Parameters:

  • records (Array)

    records to preload associations for

  • assoc_name (String, Symbol)

    the association name

  • assoc_def (AssociationDefinition)

    the association metadata



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
# File 'lib/lcp_ruby/data_source/api_preloader.rb', line 10

def self.preload(records, assoc_name, assoc_def)
  return if records.blank?

  target_model_name = assoc_def.target_model
  target_def = LcpRuby.loader.model_definitions[target_model_name]
  return unless target_def&.api_model?

  fk = assoc_def.foreign_key
  return unless fk

  target_class = LcpRuby.registry.model_for(target_model_name)
  return unless target_class.respond_to?(:lcp_api_model?) && target_class.lcp_api_model?

  # Collect unique FK values
  fk_values = records.filter_map do |r|
    r.respond_to?(fk) ? r.send(fk) : r[fk]
  end.uniq.compact

  return if fk_values.empty?

  # Batch fetch
  fetched = target_class.find_many(fk_values)
  by_id = fetched.index_by { |r| r.id.to_s }

  # Distribute to records via instance variables
  ivar = :"@_api_assoc_#{assoc_name}"
  records.each do |record|
    fk_value = record.respond_to?(fk) ? record.send(fk) : record[fk]
    target = fk_value ? by_id[fk_value.to_s] : nil
    record.instance_variable_set(ivar, target)
  end
end