Class: OccamsRecord::EagerLoaders::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/occams-record/eager_loaders/context.rb

Overview

A container for all eager loading on a particular Active Record model. Usually the context is initialized with the model, and all eager loaders are immediately initialized. Any errors (like a wrong association name ) will be thrown immediately and before any queries are run.

However, in certain situations the model cannot be known until runtime (e.g. eager loading off of a polymorphic association). In these cases the model won’t be set, or the eager loaders fully initialized, until the parent queries have run. This means that certain errors (like a wrong association name) won’t be noticed until very late, after queries have started running.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model = nil, polymorphic: false) ⇒ Context

Initialize a new eager loading context.



23
24
25
26
27
# File 'lib/occams-record/eager_loaders/context.rb', line 23

def initialize(model = nil, polymorphic: false)
  @model, @polymorphic = model, polymorphic
  @loaders = []
  @dynamic_loaders = []
end

Instance Attribute Details

#modelActiveRecord::Base



15
16
17
# File 'lib/occams-record/eager_loaders/context.rb', line 15

def model
  @model
end

Instance Method Details

#<<(loader) ⇒ OccamsRecord::EagerLoaders::Base

Append an already-initialized eager loader.



58
59
60
61
# File 'lib/occams-record/eager_loaders/context.rb', line 58

def <<(loader)
  @loaders << loader
  loader
end

#add(assoc, scope = nil, select: nil, use: nil, as: nil, from: nil, optimizer: :select) { ... } ⇒ OccamsRecord::EagerLoaders::Base

Specify an association to be eager-loaded. For maximum memory savings, only SELECT the colums you actually need.

ActiveRecord::Relation on which you may call all the normal query hethods (select, where, etc) as well as any scopes you’ve defined on the model.

Yields:

  • a block where you may perform eager loading on this association (optional)



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/occams-record/eager_loaders/context.rb', line 78

def add(assoc, scope = nil, select: nil, use: nil, as: nil, from: nil, optimizer: :select, &builder)
  if from
    real_assoc = from
    custom_name = assoc
  elsif as
    real_assoc = assoc
    custom_name = as
  else
    real_assoc = assoc
    custom_name = nil
  end

  if @model
    loader = build_loader!(real_assoc, custom_name, scope, select, use, optimizer, builder)
    @loaders << loader
    loader
  else
    @dynamic_loaders << [real_assoc, custom_name, scope, select, use, optimizer, builder]
    nil
  end
end

#namesArray<String>

Return the names of the associations being loaded.



47
48
49
50
# File 'lib/occams-record/eager_loaders/context.rb', line 47

def names
  @loaders.map(&:name) |
    @loaders.select { |l| l.respond_to? :through_name }.map(&:through_name) # TODO make not hacky
end

#run!(rows, query_logger: nil, measurements: nil) ⇒ Object

Performs all eager loading in this context (and in any nested ones).



106
107
108
109
110
111
112
# File 'lib/occams-record/eager_loaders/context.rb', line 106

def run!(rows, query_logger: nil, measurements: nil)
  raise "Cannot run eager loaders when @model has not been set!" if @dynamic_loaders.any? and @model.nil?
  @loaders.each { |loader|
    loader.run(rows, query_logger: query_logger, measurements: measurements)
  }
  nil
end