class ActionBlocks::FilterEngine

Data Engine

Attributes

filter_reqs[RW]
froms[RW]
joins[RW]
root_key[RW]
root_klass[RW]
selects[RW]
tables[RW]
wheres[RW]

Public Class Methods

new(root_klass, user: nil, filter_reqs: []) click to toggle source
# File lib/action_blocks/data_engine/filter_engine.rb, line 7
def initialize(root_klass, user: nil, filter_reqs: [])
  @root_klass = root_klass
  @filter_reqs = filter_reqs
  @tables = {}
  @joins = {}
  @wheres = []
  @froms = []
end

Public Instance Methods

ordered_joins() click to toggle source
# File lib/action_blocks/data_engine/filter_engine.rb, line 73
def ordered_joins
  @joins.values
end
process() click to toggle source
# File lib/action_blocks/data_engine/filter_engine.rb, line 16
def process
  @root_table = @root_klass.arel_table
  @root_key = @root_klass.to_s.underscore.to_sym

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

  [@filter_reqs].flatten.each do |matchreq|
    node, *rest = matchreq[:path1]
    # puts "base node: #{node} rest #{rest}"
    base_expression = walk_filter_path(@root_klass, node, @root_key, rest)

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

    if base_expression.class.ancestors.include?(Arel::Attributes::Attribute)
      where = base_expression.send(matchreq[:predicate], related_expression)
    else
      where = related_expression.send(matchreq[:predicate], base_expression)
    end
    @wheres << where

  end

end
query() click to toggle source
# File lib/action_blocks/data_engine/filter_engine.rb, line 81
def query
  @root_klass
    .from(froms)
    .joins(ordered_joins)
    .where(wheres)
end
walk_filter_path(klass, node, parent_key, col_path) click to toggle source
# File lib/action_blocks/data_engine/filter_engine.rb, line 43
def walk_filter_path(klass, node, parent_key, col_path)
  key = [parent_key, node].compact.join('_').to_sym
  if node.class != Symbol
    return node
  end
  if !col_path.empty?
    # Create Arel Table Alias
    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)
    # Recurse
    next_node, *rest = col_path
    return walk_filter_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