class ActionBlocks::SelectionsViaWhereEngine

Data Engine

Attributes

joins[RW]
root_klass[RW]
selection_filter_reqs[RW]
selection_match_reqs[RW]
selects[RW]
tables[RW]

Public Class Methods

new(root_klass, user: nil, table_alias_prefix: nil, type: :many_to_many, selection_filter_reqs: [], selection_match_reqs: [], additional_where: nil) click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 6
def initialize(root_klass, user: nil, table_alias_prefix: nil, type: :many_to_many, selection_filter_reqs: [], selection_match_reqs: [], additional_where: nil)
  @root_klass = root_klass
  @table_alias_prefix = table_alias_prefix
  @tables = {}
  @joins = {}
  @wheres = []
  @froms = []
  @type = type

  @additional_where = additional_where

  # I named them selection_match_reqs because
  # the DataEngine may work with match_reqs in
  # different contexts.  It may use them for
  # summary fields or it may use them for
  # a filtering a query to the children of some
  # base models 'children'
  @selection_match_reqs = selection_match_reqs
  @selection_filter_reqs = selection_filter_reqs
end

Public Instance Methods

froms() click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 92
def froms
  if @type == :many_to_many
    [@root_table]
  else
    @froms
  end
end
ordered_joins() click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 100
def ordered_joins
  if @type == :many_to_many
    []
  else
    @joins.values
  end
end
process() click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 27
def process
  @root_table = @root_klass.arel_table.alias([@table_alias_prefix, @root_klass.to_s.underscore.pluralize].compact.join('_'))
  root_key = [@table_alias_prefix, @root_klass.to_s.underscore.pluralize].compact.join('_').to_sym

  @froms << @root_table
  # Add base table to tables
  @tables[root_key.to_sym] = @root_table

  [@selection_match_reqs, @selection_filter_reqs].flatten.compact.each do |matchreq|
    node, *rest = matchreq[:base_path]
    # puts "base node: #{node} rest #{rest}"
    base_expression = walk_selection_match_path(@root_klass, node, root_key, rest)

    node, *rest = matchreq[:related_path]
    # puts "related node: #{node} rest #{rest}"
    related_expression = walk_selection_match_path(@root_klass, node, root_key, rest)

    where = if base_expression.class.ancestors.include?(Arel::Attributes::Attribute)
              base_expression.send(matchreq[:predicate], related_expression)
            else
              related_expression.send(matchreq[:predicate], base_expression)
            end
    @wheres << where
  end
end
query() click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 128
def query
  @root_klass
   .joins(ordered_joins)
    .where(wheres)
end
subquery_for_many_to_many_selections() click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 119
def subquery_for_many_to_many_selections
  # Arel::Distinct.new(@rook_klasas[:id])
  @root_klass
    .from([@froms].flatten)
    .select(@root_table[:id])
    .joins(@joins.values)
    .where(@wheres.reduce(&:and))
end
walk_selection_match_path(klass, node, parent_key, col_path) click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 53
def walk_selection_match_path(klass, node, parent_key, col_path)
  # puts "klass: #{klass} node: #{node} parent_key #{parent_key.inspect} col_path #{col_path.inspect}"
  # pp [key, rest_col_path]
  key = if node.class == Class
          [@table_alias_prefix, node.to_s.underscore.pluralize].compact.join('_').to_sym
        else
          [@table_alias_prefix, parent_key, node].compact.join('_').to_sym
        end
  return node if node.class != Symbol && node.class != Class
  if !col_path.empty?
    # Create Arel Table Alias
    if node.class != Class
      relation = klass.reflections[node.to_s]
      klass = relation.klass
      @tables[key] = klass.arel_table.alias(key) unless @tables[key]
      # Create Join
      fk = relation.join_foreign_key
      pk = relation.join_primary_key
      join_on = @tables[key].create_on(@tables[parent_key][fk].eq(@tables[key][pk]))
      @joins[key] = @tables[parent_key].create_join(@tables[key], join_on, Arel::Nodes::OuterJoin)
    else
      klass = node
      unless @tables[key]
        @tables[key] = klass.arel_table.alias(key) unless @tables[key]
        @froms << @tables[key]
      end
    end
    # Recurse
    next_node, *rest = col_path
    return walk_selection_match_path(klass, next_node, key, rest)
  else
    # Return expression
    # puts "parent_key: #{node.to_sym}"
    # puts "node: #{node.to_sym}"
    return @tables[parent_key][node.to_sym]
  end
end
wheres() click to toggle source
# File lib/action_blocks/data_engine/selections_via_where_engine.rb, line 108
def wheres
  @wheres << @additional_where if @additional_where
  if @type == :many_to_many && (!@selection_match_reqs.empty? || !@selection_filter_reqs.empty?)
    subquery_arel = subquery_for_many_to_many_selections.arel
    # w = Arel::Nodes::In.new(@root_table[:id], subquery.ast)
    @root_table[:id].in(subquery_arel)
  else
    @wheres.reduce(&:and)
  end
end