Module: OccamsRecord::EagerLoaders::Builder

Included in:
Query, RawQuery
Defined in:
lib/occams-record/eager_loaders.rb

Overview

Methods for adding eager loading to a query.

Instance Method Summary collapse

Instance Method Details

#eager_load(assoc, scope = nil, select: nil, use: nil, as: nil) { ... } ⇒ OccamsRecord::Query

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.

Parameters:

  • assoc (Symbol)

    name of association

  • scope (Proc) (defaults to: nil)

    a scope to apply to the query (optional). It will be passed an

  • select (String) (defaults to: nil)

    a custom SELECT statement, minus the SELECT (optional)

  • use (Array<Module>) (defaults to: nil)

    optional Module to include in the result class (single or array)

  • as (Symbol) (defaults to: nil)

    Load the association usign a different attribute name

Yields:

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

Returns:



32
33
34
35
36
37
38
39
# File 'lib/occams-record/eager_loaders.rb', line 32

def eager_load(assoc, scope = nil, select: nil, use: nil, as: nil, &eval_block)
  ref = @model ? @model.reflections[assoc.to_s] : nil
  ref ||= @model.subclasses.map(&:reflections).detect { |x| x.has_key? assoc.to_s }&.[](assoc.to_s) if @model
  raise "OccamsRecord: No assocation `:#{assoc}` on `#{@model&.name || '<model missing>'}` or subclasses" if ref.nil?
  scope ||= ->(q) { q.select select } if select
  @eager_loaders << eager_loader_for_association(ref).new(ref, scope, use: use, as: as, &eval_block)
  self
end

#eager_load_many(name, mapping, sql, binds: {}, model: nil, use: nil) { ... } ⇒ Object

Specify some arbitrary SQL to be loaded into some arbitrary attribute (“name”). The attribute will hold an array of 0 or more associated records.

In the example below, :parts is NOT an association on Widget. Though if it where it would be a has_many. The mapping argument says “The widget_id column in this table (parts) maps to the id column in the other table (widgets)”. The %ids bind param will be provided for you, and in this case will be all the id values from the main query.

res = OccamsRecord.
  query(Widget.order("name")).
  eager_load_many(:parts, {:widget_id => :id}, %(
    SELECT * FROM parts WHERE widget_id IN (%{ids}) AND sku NOT IN (%{bad_skus})
  ), binds: {
    bad_skus: ["G90023ASDf0"]
  }).
  run

Parameters:

  • name (Symbol)

    name of attribute to load records into

  • mapping (Hash)

    a one element Hash with the key being the local/child id and the value being the foreign/parent id

  • sql (String)

    the SQL to query the associated records. Include a bind params called ‘%ids’ for the foreign/parent ids.

  • use (Array<Module>) (defaults to: nil)

    optional - Ruby modules to include in the result objects (single or array)

  • binds (Hash) (defaults to: {})

    any additional binds for your query.

  • model (ActiveRecord::Base) (defaults to: nil)

    optional - ActiveRecord model that represents what you’re loading. required when using Sqlite.

Yields:

  • eager load associations nested under this one



98
99
100
101
# File 'lib/occams-record/eager_loaders.rb', line 98

def eager_load_many(name, mapping, sql, binds: {}, model: nil, use: nil, &eval_block)
  @eager_loaders << EagerLoaders::AdHocMany.new(name, mapping, sql, binds: binds, model: model, use: use, &eval_block)
  self
end

#eager_load_one(name, mapping, sql, binds: {}, model: nil, use: nil) { ... } ⇒ Object

Specify some arbitrary SQL to be loaded into some arbitrary attribute (“name”). The attribute will hold either one record or none.

In the example below, :category is NOT an association on Widget. Though if it where it would be a belongs_to. The mapping argument says “The id column in this table (categories) maps to the category_id column in the other table (widgets)”. The %ids bind param will be provided for you, and in this case will be all the category_id values from the main query.

res = OccamsRecord.
  query(Widget.order("name")).
  eager_load_one(:category, {:id => :category_id}, %(
    SELECT * FROM categories WHERE id IN (%{ids}) AND name != %{bad_name}
  ), binds: {
    bad_name: "Bad Category"
  }).
  run

Parameters:

  • name (Symbol)

    name of attribute to load records into

  • mapping (Hash)

    a one element Hash with the key being the local/child id and the value being the foreign/parent id

  • sql (String)

    the SQL to query the associated records. Include a bind params called ‘%ids’ for the foreign/parent ids.

  • binds (Hash) (defaults to: {})

    any additional binds for your query.

  • model (ActiveRecord::Base) (defaults to: nil)

    optional - ActiveRecord model that represents what you’re loading. required when using Sqlite.

  • use (Array<Module>) (defaults to: nil)

    optional - Ruby modules to include in the result objects (single or array)

Yields:

  • eager load associations nested under this one



67
68
69
70
# File 'lib/occams-record/eager_loaders.rb', line 67

def eager_load_one(name, mapping, sql, binds: {}, model: nil, use: nil, &eval_block)
  @eager_loaders << EagerLoaders::AdHocOne.new(name, mapping, sql, binds: binds, model: model, use: use, &eval_block)
  self
end