Refactor a bit (in anticipation of more set operations)
This commit is contained in:
parent
5c88391609
commit
08d97ad695
|
@ -2,21 +2,29 @@ module ActiveRecord
|
|||
class Relation
|
||||
module Union
|
||||
|
||||
SET_OPERATION_TO_AREL_CLASS = {
|
||||
"UNION" => Arel::Nodes::Union,
|
||||
"UNION ALL" => Arel::Nodes::UnionAll
|
||||
}
|
||||
|
||||
def union(relation_or_where_arg, *args)
|
||||
union_with_class(Arel::Nodes::Union, relation_or_where_arg, *args)
|
||||
set_operation("UNION", relation_or_where_arg, *args)
|
||||
end
|
||||
|
||||
def union_all(relation_or_where_arg, *args)
|
||||
union_with_class(Arel::Nodes::UnionAll, relation_or_where_arg, *args)
|
||||
set_operation("UNION ALL", relation_or_where_arg, *args)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def union_with_class(union_class, relation_or_where_arg, *args)
|
||||
other = relation_or_where_arg if args.size == 0 && Relation === relation_or_where_arg
|
||||
other ||= @klass.where(relation_or_where_arg, *args)
|
||||
def set_operation(operation, relation_or_where_arg, *args)
|
||||
other = if args.size == 0 && Relation === relation_or_where_arg
|
||||
relation_or_where_arg
|
||||
else
|
||||
@klass.where(relation_or_where_arg, *args)
|
||||
end
|
||||
|
||||
verify_union_relations!(self, other)
|
||||
verify_relations_for_set_operation!(operation, self, other)
|
||||
|
||||
# Postgres allows ORDER BY in the UNION subqueries if each subquery is surrounded by parenthesis
|
||||
# but SQLite does not allow parens around the subqueries; you will have to explicitly do `relation.reorder(nil)` in SQLite
|
||||
|
@ -26,9 +34,9 @@ module ActiveRecord
|
|||
left, right = Arel::Nodes::Grouping.new(self.ast), Arel::Nodes::Grouping.new(other.ast)
|
||||
end
|
||||
|
||||
union = union_class.new(left, right)
|
||||
set = SET_OPERATION_TO_AREL_CLASS[operation].new(left, right)
|
||||
from = Arel::Nodes::TableAlias.new(
|
||||
union,
|
||||
set,
|
||||
Arel::Nodes::SqlLiteral.new(@klass.arel_table.name)
|
||||
)
|
||||
|
||||
|
@ -37,20 +45,21 @@ module ActiveRecord
|
|||
relation
|
||||
end
|
||||
|
||||
def verify_union_relations!(*args)
|
||||
includes_relations = args.select { |r| r.includes_values.any? }
|
||||
def verify_relations_for_set_operation!(operation, *relations)
|
||||
includes_relations = relations.select { |r| r.includes_values.any? }
|
||||
|
||||
if includes_relations.any?
|
||||
raise ArgumentError.new("Cannot union relation with includes.")
|
||||
raise ArgumentError.new("Cannot #{operation} relation with includes.")
|
||||
end
|
||||
|
||||
preload_relations = args.select { |r| r.preload_values.any? }
|
||||
preload_relations = relations.select { |r| r.preload_values.any? }
|
||||
if preload_relations.any?
|
||||
raise ArgumentError.new("Cannot union relation with preload.")
|
||||
raise ArgumentError.new("Cannot #{operation} relation with preload.")
|
||||
end
|
||||
|
||||
eager_load_relations = args.select { |r| r.eager_load_values.any? }
|
||||
eager_load_relations = relations.select { |r| r.eager_load_values.any? }
|
||||
if eager_load_relations.any?
|
||||
raise ArgumentError.new("Cannot union relation with eager load.")
|
||||
raise ArgumentError.new("Cannot #{operation} relation with eager load.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue