module ActiveRelation
class Join < Relation
attr_reader :join_sql, :relation1, :relation2, :predicates
def initialize(join_sql, relation1, relation2, *predicates)
@join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates
end
def ==(other)
self.class == other.class and
predicates == other.predicates and (
(relation1 == other.relation1 and relation2 == other.relation2) or
(relation2 == other.relation1 and relation1 == other.relation2)
)
end
def qualify
Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify))
end
def attributes
[
relation1.aggregation?? relation1.attributes.collect(&:to_attribute) : relation1.attributes,
relation2.aggregation?? relation2.attributes.collect(&:to_attribute) : relation2.attributes,
].flatten.collect { |a| a.bind(self) }
end
def prefix_for(attribute)
(relation1[attribute] && relation1.aliased_prefix_for(attribute)) ||
(relation2[attribute] && relation2.aliased_prefix_for(attribute))
end
alias_method :aliased_prefix_for, :prefix_for
protected
def joins
[relation1.joins, relation2.joins, join].compact.join(" ")
end
def selects
[
(relation1.send(:selects) unless relation1.aggregation?),
(relation2.send(:selects) unless relation2.aggregation?)
].compact.flatten
end
def table_sql
relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql)
end
private
def join
[join_sql, right_table_sql, "ON", predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ")
end
def right_table_sql
relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql)
end
end
end