class ActiveRecord::Associations::ClassMethods::JoinDependency

:nodoc:

def build(associations, parent = nil)

def build(associations, parent = nil)
  parent ||= @joins.last
  case associations
    when Symbol, String
      reflection = parent.reflections[associations.to_s.intern] or
      raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
      @reflections << reflection
      @joins << build_join_association(reflection, parent)
    when Array
      associations.each do |association|
        build(association, parent)
      end
    when Hash
      associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
        build(name, parent)
        build(associations[name])
      end
    else
      raise ConfigurationError, associations.inspect
  end
end

def build_join_association(reflection, parent)

overridden in InnerJoinDependency subclass
def build_join_association(reflection, parent)
  JoinAssociation.new(reflection, self, parent)
end

def construct(parent, associations, joins, row)

def construct(parent, associations, joins, row)
  case associations
    when Symbol, String
      join = joins.detect{|j| j.reflection.name.to_s == associations.to_s && j.parent_table_name == parent.class.table_name }
      raise(ConfigurationError, "No such association") if join.nil?
      joins.delete(join)
      construct_association(parent, join, row)
    when Array
      associations.each do |association|
        construct(parent, association, joins, row)
      end
    when Hash
      associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
        join = joins.detect{|j| j.reflection.name.to_s == name.to_s && j.parent_table_name == parent.class.table_name }
        raise(ConfigurationError, "No such association") if join.nil?
        association = construct_association(parent, join, row)
        joins.delete(join)
        construct(association, associations[name], joins, row) if association
      end
    else
      raise ConfigurationError, associations.inspect
  end
end

def construct_association(record, join, row)

def construct_association(record, join, row)
  case join.reflection.macro
    when :has_many, :has_and_belongs_to_many
      collection = record.send(join.reflection.name)
      collection.loaded
      return nil if record.id.to_s != join.parent.record_id(row).to_s or row[join.aliased_primary_key].nil?
      association = join.instantiate(row)
      collection.target.push(association)
      collection.__send__(:set_inverse_instance, association, record)
    when :has_one
      return if record.id.to_s != join.parent.record_id(row).to_s
      return if record.instance_variable_defined?("@#{join.reflection.name}")
      association = join.instantiate(row) unless row[join.aliased_primary_key].nil?
      set_target_and_inverse(join, association, record)
    when :belongs_to
      return if record.id.to_s != join.parent.record_id(row).to_s or row[join.aliased_primary_key].nil?
      association = join.instantiate(row)
      set_target_and_inverse(join, association, record)
    else
      raise ConfigurationError, "unknown macro: #{join.reflection.macro}"
  end
  return association
end

def initialize(base, associations, joins)

def initialize(base, associations, joins)
  @joins                 = [JoinBase.new(base, joins)]
  @associations          = associations
  @reflections           = []
  @base_records_hash     = {}
  @base_records_in_order = []
  @table_aliases         = Hash.new { |aliases, table| aliases[table] = 0 }
  @table_aliases[base.table_name] = 1
  build(associations)
end

def instantiate(rows)

def instantiate(rows)
  rows.each_with_index do |row, i|
    primary_id = join_base.record_id(row)
    unless @base_records_hash[primary_id]
      @base_records_in_order << (@base_records_hash[primary_id] = join_base.instantiate(row))
    end
    construct(@base_records_hash[primary_id], @associations, join_associations.dup, row)
  end
  remove_duplicate_results!(join_base.active_record, @base_records_in_order, @associations)
  return @base_records_in_order
end

def join_associations

def join_associations
  @joins[1..-1].to_a
end

def join_base

def join_base
  @joins[0]
end

def join_for_table_name(table_name)

def join_for_table_name(table_name)
  join = (@joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first) rescue nil
  return join unless join.nil?
  @joins.select{|j|j.is_a?(JoinAssociation) && j.aliased_join_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil
end

def joins_for_table_name(table_name)

def joins_for_table_name(table_name)
  join = join_for_table_name(table_name)
  result = nil
  if join && join.is_a?(JoinAssociation)
    result = [join]
    if join.parent && join.parent.is_a?(JoinAssociation)
      result = joins_for_table_name(join.parent.aliased_table_name) +
               result
    end
  end
  result
end

def remove_duplicate_results!(base, records, associations)

def remove_duplicate_results!(base, records, associations)
  case associations
    when Symbol, String
      reflection = base.reflections[associations]
      if reflection && reflection.collection?
        records.each { |record| record.send(reflection.name).target.uniq! }
      end
    when Array
      associations.each do |association|
        remove_duplicate_results!(base, records, association)
      end
    when Hash
      associations.keys.each do |name|
        reflection = base.reflections[name]
        parent_records = records.map do |record|
          descendant = record.send(reflection.name)
          next unless descendant
          descendant.target.uniq! if reflection.collection?
          descendant
        end.flatten.compact
        remove_duplicate_results!(reflection.klass, parent_records, associations[name]) unless parent_records.empty?
      end
  end
end

def set_target_and_inverse(join, association, record)

def set_target_and_inverse(join, association, record)
  association_proxy = record.send("set_#{join.reflection.name}_target", association)
  association_proxy.__send__(:set_inverse_instance, association, record)
end