class Joiner::Joins

Constants

JoinDependency

Attributes

join_association_class[W]
model[R]

Public Class Methods

new(model) click to toggle source
# File lib/joiner/joins.rb, line 10
def initialize(model)
  @model       = model
  @base        = JoinDependency.new model, [], []
  @joins_cache = ActiveSupport::OrderedHash.new
end

Public Instance Methods

add_join_to(path) click to toggle source
# File lib/joiner/joins.rb, line 16
def add_join_to(path)
  @joins_cache[path] ||= build_join(path)
end
alias_for(path) click to toggle source
# File lib/joiner/joins.rb, line 20
def alias_for(path)
  return model.table_name if path.empty?
  add_join_to(path).aliased_table_name
end
join_association_class() click to toggle source
# File lib/joiner/joins.rb, line 25
def join_association_class
  @join_association_class || JoinDependency::JoinAssociation
end
join_values() click to toggle source
# File lib/joiner/joins.rb, line 29
def join_values
  @base
end

Private Instance Methods

build_join(path) click to toggle source
# File lib/joiner/joins.rb, line 35
def build_join(path)
  if join = find_join(path)
    return join
  end

  base_node, short_path = relative_path(path)

  join = build_join_association(short_path, base_node.base_klass)
  base_node.children << join
  construct_tables! base_node, join

  find_join(path)
end
build_join_association(path, base_class) click to toggle source
# File lib/joiner/joins.rb, line 49
def build_join_association(path, base_class)
  return nil if path.empty?

  step = path.first
  reflection = find_reflection(step, base_class)
  reflection.check_validity!

  join_association_class.new reflection,
    [build_join_association(path[1..-1], reflection.klass)].compact
end
construct_tables!(parent, node) click to toggle source
# File lib/joiner/joins.rb, line 96
def construct_tables!(parent, node)
  node.tables = table_aliases_for(parent, node)
  node.children.each { |child| construct_tables! node, child }
end
find_join(path, base = nil) click to toggle source
# File lib/joiner/joins.rb, line 60
def find_join(path, base = nil)
  base ||= @base.join_root

  return base if path.empty?

  if next_step = base.children.detect{ |c| c.reflection.name == path.first }
    find_join path[1..-1], next_step
  end
end
find_reflection(name, klass) click to toggle source
# File lib/joiner/joins.rb, line 83
def find_reflection(name, klass)
  klass._reflect_on_association(name)
end
relative_path(path) click to toggle source
# File lib/joiner/joins.rb, line 70
def relative_path(path)
  short_path = []
  test_path = path.dup

  while test_path.size > 1
    short_path << test_path.pop
    node = find_join(test_path)
    return [node, short_path] if node
  end

  [@base.join_root, path]
end
table_alias_for(reflection, parent, join) click to toggle source
# File lib/joiner/joins.rb, line 101
def table_alias_for(reflection, parent, join)
  name = "#{reflection.plural_name}_#{parent.table_name}"
  name << "_join" if join
  name
end
table_aliases_for(parent, node) click to toggle source
# File lib/joiner/joins.rb, line 87
def table_aliases_for(parent, node)
  node.reflection.chain.map { |reflection|
    @base.alias_tracker.aliased_table_for(
      reflection.table_name,
      table_alias_for(reflection, parent, reflection != node.reflection)
    )
  }
end