Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #118 against 4-0-stable #239

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ lib/arel/factory_methods.rb
lib/arel/insert_manager.rb
lib/arel/math.rb
lib/arel/nodes.rb
lib/arel/nodes/and.rb
lib/arel/nodes/ascending.rb
lib/arel/nodes/binary.rb
lib/arel/nodes/count.rb
Expand All @@ -39,6 +38,7 @@ lib/arel/nodes/inner_join.rb
lib/arel/nodes/insert_statement.rb
lib/arel/nodes/join_source.rb
lib/arel/nodes/named_function.rb
lib/arel/nodes/nary.rb
lib/arel/nodes/node.rb
lib/arel/nodes/outer_join.rb
lib/arel/nodes/over.rb
Expand Down
2 changes: 1 addition & 1 deletion lib/arel/nodes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
require 'arel/nodes/over'

# nary
require 'arel/nodes/and'
require 'arel/nodes/nary'

# function
# FIXME: Function + Alias can be rewritten as a Function and Alias node.
Expand Down
34 changes: 0 additions & 34 deletions lib/arel/nodes/and.rb

This file was deleted.

5 changes: 0 additions & 5 deletions lib/arel/nodes/binary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ def eql? other
Matches
NotEqual
NotIn
Or
Union
UnionAll
Intersect
Except
}.each do |name|
const_set name, Class.new(Binary)
end
Expand Down
64 changes: 64 additions & 0 deletions lib/arel/nodes/nary.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module Arel
module Nodes
class Nary < Arel::Nodes::Node
attr_reader :children

def initialize children, right = nil
super()
unless Array === children
warn "(#{caller.first}) #{ self.class.to_s.sub(/.*::/, '').upcase } nodes should be created with a list"
children = [children, right]
end
@children = children
end

def initialize_copy other
super
@children = @children.map {|child| child.clone}
end

def left
children.first
end

def left= child
children[0] = child
end

def right
children[1]
end

def right= child
children[1] = child
end

def << child
children << child
end

def hash
children.hash
end

def eql? other
self.class == other.class &&
self.children == other.children
end
alias :== :eql?
end

%w{
And
Or
Union
UnionAll
Except
ExceptAll
Intersect
IntersectAll
}.each do |name|
const_set name, Class.new(Nary)
end
end
end
2 changes: 1 addition & 1 deletion lib/arel/nodes/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def not
# Factory method to create a Nodes::Grouping node that has an Nodes::Or
# node as a child.
def or right
Nodes::Grouping.new Nodes::Or.new(self, right)
Nodes::Grouping.new Nodes::Or.new [self, right]
end

###
Expand Down
1 change: 1 addition & 0 deletions lib/arel/nodes/select_statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class SelectStatement < Arel::Nodes::Node

def initialize cores = [SelectCore.new]
super()
cores = [ cores ] unless Array === cores
@cores = cores
@orders = []
@limit = nil
Expand Down
1 change: 0 additions & 1 deletion lib/arel/nodes/unary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def eql? other
Offset
On
Ordering
Top
Lock
DistinctOn
}.each do |name|
Expand Down
6 changes: 3 additions & 3 deletions lib/arel/predications.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ def not_in other
elsif other.exclude_end?
left = Nodes::LessThan.new(self, other.begin)
right = Nodes::GreaterThanOrEqual.new(self, other.end)
Nodes::Or.new left, right
Nodes::Or.new [left, right]
else
left = Nodes::LessThan.new(self, other.begin)
right = Nodes::GreaterThan.new(self, other.end)
Nodes::Or.new left, right
Nodes::Or.new [left, right]
end
else
Nodes::NotIn.new self, other
Expand Down Expand Up @@ -169,7 +169,7 @@ def lteq_all others
def grouping_any method_id, others
nodes = others.map {|expr| send(method_id, expr)}
Nodes::Grouping.new nodes.inject { |memo,node|
Nodes::Or.new(memo, node)
Nodes::Or.new [memo, node]
}
end

Expand Down
46 changes: 28 additions & 18 deletions lib/arel/select_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ module Arel
class SelectManager < Arel::TreeManager
include Arel::Crud

def initialize engine, table = nil
def initialize engine, table = nil, cores = nil
super(engine)
@ast = Nodes::SelectStatement.new
@ctx = @ast.cores.last
from table
if cores
@ast = Nodes::SelectStatement.new cores
else
@ast = Nodes::SelectStatement.new
end
@ctx = @ast.cores.last
from table if table
end

def initialize_copy other
Expand Down Expand Up @@ -182,22 +186,15 @@ def where_sql
end

def union operation, other = nil
if other
node_class = Nodes.const_get("Union#{operation.to_s.capitalize}")
else
other = operation
node_class = Nodes::Union
end

node_class.new self.ast, other.ast
set_agreggation :union, operation, other
end

def intersect other
Nodes::Intersect.new ast, other.ast
def intersect operation, other = nil
set_agreggation :intersect, operation, other
end

def except other
Nodes::Except.new ast, other.ast
def except operation, other = nil
set_agreggation :except, operation, other
end
alias :minus :except

Expand All @@ -215,10 +212,8 @@ def with *subqueries
def take limit
if limit
@ast.limit = Nodes::Limit.new(limit)
@ctx.top = Nodes::Top.new(limit)
else
@ast.limit = nil
@ctx.top = nil
end
self
end
Expand Down Expand Up @@ -315,5 +310,20 @@ def collapse exprs, existing = nil
create_and exprs
end
end

def set_agreggation operator, variant, others = nil
if others
variant = '' if operator.to_s == :distinct.to_s
node_class = Nodes.const_get("#{operator.to_s.capitalize}#{variant.to_s.capitalize}")
else
others = variant
node_class = Nodes.const_get("#{operator.to_s.capitalize}")
end

others = [others] unless Array === others
set_node = node_class.new([self.ast] + others.map{|o| o.ast})

SelectManager.new self.engine, nil, set_node
end
end
end
3 changes: 1 addition & 2 deletions lib/arel/visitors/depth_first.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ def unary o, a
alias :visit_Arel_Nodes_Ordering :unary
alias :visit_Arel_Nodes_Ascending :unary
alias :visit_Arel_Nodes_Descending :unary
alias :visit_Arel_Nodes_Top :unary
alias :visit_Arel_Nodes_UnqualifiedColumn :unary

def function o, a
Expand Down Expand Up @@ -56,6 +55,7 @@ def nary o, a
o.children.each { |child| visit child, a }
end
alias :visit_Arel_Nodes_And :nary
alias :visit_Arel_Nodes_Or :nary

def binary o, a
visit o.left, a
Expand All @@ -78,7 +78,6 @@ def binary o, a
alias :visit_Arel_Nodes_Matches :binary
alias :visit_Arel_Nodes_NotEqual :binary
alias :visit_Arel_Nodes_NotIn :binary
alias :visit_Arel_Nodes_Or :binary
alias :visit_Arel_Nodes_OuterJoin :binary
alias :visit_Arel_Nodes_TableAlias :binary
alias :visit_Arel_Nodes_Values :binary
Expand Down
3 changes: 1 addition & 2 deletions lib/arel/visitors/dot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ def unary o, a
alias :visit_Arel_Nodes_Not :unary
alias :visit_Arel_Nodes_Offset :unary
alias :visit_Arel_Nodes_On :unary
alias :visit_Arel_Nodes_Top :unary
alias :visit_Arel_Nodes_UnqualifiedColumn :unary
alias :visit_Arel_Nodes_Preceding :unary
alias :visit_Arel_Nodes_Following :unary
Expand Down Expand Up @@ -162,6 +161,7 @@ def nary o, a
end
end
alias :visit_Arel_Nodes_And :nary
alias :visit_Arel_Nodes_Or :nary

def binary o, a
visit_edge o, a, "left"
Expand All @@ -181,7 +181,6 @@ def binary o, a
alias :visit_Arel_Nodes_Matches :binary
alias :visit_Arel_Nodes_NotEqual :binary
alias :visit_Arel_Nodes_NotIn :binary
alias :visit_Arel_Nodes_Or :binary
alias :visit_Arel_Nodes_Over :binary

def visit_String o, a
Expand Down
7 changes: 0 additions & 7 deletions lib/arel/visitors/mssql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@ module Visitors
class MSSQL < Arel::Visitors::ToSql
private

# `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate
# "select top 10 distinct first_name from users", which is invalid query! it should be
# "select distinct top 10 first_name from users"
def visit_Arel_Nodes_Top o, a
""
end

def visit_Arel_Nodes_SelectStatement o, a
if !o.limit && !o.offset
return super o, a
Expand Down
27 changes: 15 additions & 12 deletions lib/arel/visitors/to_sql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def visit_Arel_Nodes_SelectStatement o, a
str << SPACE
end

o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x, a) }
o.cores.each { |x| str << visit(x, a) }

unless o.orders.empty?
str << SPACE
Expand Down Expand Up @@ -256,19 +256,27 @@ def visit_Arel_Nodes_WithRecursive o, a
end

def visit_Arel_Nodes_Union o, a
"( #{visit o.left, a} UNION #{visit o.right, a} )"
"( #{ o.children.map { |x| visit x, a }.join ' ) UNION ( ' } )"
end

def visit_Arel_Nodes_UnionAll o, a
"( #{visit o.left, a} UNION ALL #{visit o.right, a} )"
"( #{ o.children.map { |x| visit x, a }.join ' ) UNION ALL ( ' } )"
end

def visit_Arel_Nodes_Intersect o, a
"( #{visit o.left, a} INTERSECT #{visit o.right, a} )"
"( #{ o.children.map { |x| visit x, a }.join ' ) INTERSECT ( ' } )"
end

def visit_Arel_Nodes_IntersectAll o, a
"( #{ o.children.map { |x| visit x, a }.join ' ) INTERSECT ALL ( ' } )"
end

def visit_Arel_Nodes_Except o, a
"( #{visit o.left, a} EXCEPT #{visit o.right, a} )"
"( #{ o.children.map { |x| visit x, a }.join ' ) EXCEPT ( ' } )"
end

def visit_Arel_Nodes_ExceptAll o, a
"( #{ o.children.map { |x| visit x, a }.join ' ) EXCEPT ALL ( ' } )"
end

def visit_Arel_Nodes_NamedWindow o, a
Expand Down Expand Up @@ -336,11 +344,6 @@ def visit_Arel_Nodes_Limit o, a
"LIMIT #{visit o.expr, a}"
end

# FIXME: this does nothing on most databases, but does on MSSQL
def visit_Arel_Nodes_Top o, a
""
end

def visit_Arel_Nodes_Lock o, a
visit o.expr, a
end
Expand All @@ -350,7 +353,7 @@ def visit_Arel_Nodes_Grouping o, a
end

def visit_Arel_SelectManager o, a
"(#{o.to_sql.rstrip})"
"( #{o.to_sql.rstrip} )"
end

def visit_Arel_Nodes_Ascending o, a
Expand Down Expand Up @@ -503,7 +506,7 @@ def visit_Arel_Nodes_And o, a
end

def visit_Arel_Nodes_Or o, a
"#{visit o.left, a} OR #{visit o.right, a}"
o.children.map { |x| visit x, a }.join ' OR '
end

def visit_Arel_Nodes_Assignment o, a
Expand Down
Loading