Skip to content

Commit df2b74b

Browse files
authored
Merge pull request #481 from lautis/lateral
Lateral expressions for PostgreSQL
2 parents 6cf061e + d8f463a commit df2b74b

File tree

6 files changed

+40
-1
lines changed

6 files changed

+40
-1
lines changed

lib/arel/nodes/select_core.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def initialize
1010
@source = JoinSource.new nil
1111
@top = nil
1212

13-
# http://savage.net.au/SQL/sql-92.bnf.html#set%20quantifier
13+
# https://ronsavage.github.io/SQL/sql-92.bnf.html#set%20quantifier
1414
@set_quantifier = nil
1515
@projections = []
1616
@wheres = []

lib/arel/nodes/unary.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def eql? other
2828
Group
2929
GroupingElement
3030
GroupingSet
31+
Lateral
3132
Limit
3233
Lock
3334
Not

lib/arel/select_manager.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ def except other
202202
end
203203
alias :minus :except
204204

205+
def lateral table_name = nil
206+
base = table_name.nil? ? ast : as(table_name)
207+
Nodes::Lateral.new(base)
208+
end
209+
205210
def with *subqueries
206211
if subqueries.first.is_a? Symbol
207212
node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}")

lib/arel/visitors/depth_first.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def unary o
2525
alias :visit_Arel_Nodes_GroupingElement :unary
2626
alias :visit_Arel_Nodes_Grouping :unary
2727
alias :visit_Arel_Nodes_Having :unary
28+
alias :visit_Arel_Nodes_Lateral :unary
2829
alias :visit_Arel_Nodes_Limit :unary
2930
alias :visit_Arel_Nodes_Not :unary
3031
alias :visit_Arel_Nodes_Offset :unary

lib/arel/visitors/postgresql.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class PostgreSQL < Arel::Visitors::ToSql
55
CUBE = 'CUBE'
66
ROLLUP = 'ROLLUP'
77
GROUPING_SET = 'GROUPING SET'
8+
LATERAL = 'LATERAL'
89

910
private
1011

@@ -69,6 +70,23 @@ def visit_Arel_Nodes_GroupingSet o, collector
6970
grouping_array_or_grouping_element o, collector
7071
end
7172

73+
def visit_Arel_Nodes_Lateral o, collector
74+
collector << LATERAL
75+
collector << SPACE
76+
grouping_parentheses o, collector
77+
end
78+
79+
# Used by Lateral visitor to enclose select queries in parentheses
80+
def grouping_parentheses o, collector
81+
if o.expr.is_a? Nodes::SelectStatement
82+
collector << "("
83+
visit o.expr, collector
84+
collector << ")"
85+
else
86+
visit o.expr, collector
87+
end
88+
end
89+
7290
# Utilized by GroupingSet, Cube & RollUp visitors to
7391
# handle grouping aggregation semantics
7492
def grouping_array_or_grouping_element o, collector

test/visitors/test_postgres.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ def compile node
5151
assert_equal 'SELECT DISTINCT', compile(core)
5252
end
5353

54+
it 'encloses LATERAL queries in parens' do
55+
subquery = @table.project(:id).where(@table[:name].matches('foo%'))
56+
compile(subquery.lateral).must_be_like %{
57+
LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%')
58+
}
59+
end
60+
61+
it 'produces LATERAL queries with alias' do
62+
subquery = @table.project(:id).where(@table[:name].matches('foo%'))
63+
compile(subquery.lateral('bar')).must_be_like %{
64+
LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') bar
65+
}
66+
end
67+
5468
describe "Nodes::Matches" do
5569
it "should know how to visit" do
5670
node = @table[:name].matches('foo%')

0 commit comments

Comments
 (0)