diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2017-12-28 10:35:15 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-28 10:35:15 -0800 |
commit | df2b74b53664cc3ce3a49156c555b84c134bb75a (patch) | |
tree | 89d2a363ead699b4e8916c9ddb7ffccd8d429f1d | |
parent | 6cf061ed6f3f9c8128385765c07eaa4f8a43bd34 (diff) | |
parent | d8f463a3b87ff9f69eef2a3ed5718b198c2072a1 (diff) | |
download | rails-df2b74b53664cc3ce3a49156c555b84c134bb75a.tar.gz rails-df2b74b53664cc3ce3a49156c555b84c134bb75a.tar.bz2 rails-df2b74b53664cc3ce3a49156c555b84c134bb75a.zip |
Merge pull request #481 from lautis/lateral
Lateral expressions for PostgreSQL
-rw-r--r-- | lib/arel/nodes/select_core.rb | 2 | ||||
-rw-r--r-- | lib/arel/nodes/unary.rb | 1 | ||||
-rw-r--r-- | lib/arel/select_manager.rb | 5 | ||||
-rw-r--r-- | lib/arel/visitors/depth_first.rb | 1 | ||||
-rw-r--r-- | lib/arel/visitors/postgresql.rb | 18 | ||||
-rw-r--r-- | test/visitors/test_postgres.rb | 14 |
6 files changed, 40 insertions, 1 deletions
diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 264fa46591..fa1c026107 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -10,7 +10,7 @@ module Arel @source = JoinSource.new nil @top = nil - # http://savage.net.au/SQL/sql-92.bnf.html#set%20quantifier + # https://ronsavage.github.io/SQL/sql-92.bnf.html#set%20quantifier @set_quantifier = nil @projections = [] @wheres = [] diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 5711d91dce..e458d87ab3 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -28,6 +28,7 @@ module Arel Group GroupingElement GroupingSet + Lateral Limit Lock Not diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index a88dcd320c..0f3b0dc6a0 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -202,6 +202,11 @@ module Arel end alias :minus :except + def lateral table_name = nil + base = table_name.nil? ? ast : as(table_name) + Nodes::Lateral.new(base) + end + def with *subqueries if subqueries.first.is_a? Symbol node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}") diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 5416a285f5..b3bbc9bd40 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -25,6 +25,7 @@ module Arel alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary + alias :visit_Arel_Nodes_Lateral :unary alias :visit_Arel_Nodes_Limit :unary alias :visit_Arel_Nodes_Not :unary alias :visit_Arel_Nodes_Offset :unary diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 2a935e4318..047f71aaa6 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -5,6 +5,7 @@ module Arel CUBE = 'CUBE' ROLLUP = 'ROLLUP' GROUPING_SET = 'GROUPING SET' + LATERAL = 'LATERAL' private @@ -69,6 +70,23 @@ module Arel grouping_array_or_grouping_element o, collector end + def visit_Arel_Nodes_Lateral o, collector + collector << LATERAL + collector << SPACE + grouping_parentheses o, collector + end + + # Used by Lateral visitor to enclose select queries in parentheses + def grouping_parentheses o, collector + if o.expr.is_a? Nodes::SelectStatement + collector << "(" + visit o.expr, collector + collector << ")" + else + visit o.expr, collector + end + end + # Utilized by GroupingSet, Cube & RollUp visitors to # handle grouping aggregation semantics def grouping_array_or_grouping_element o, collector diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index beae117ef5..b28c0f3c18 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -51,6 +51,20 @@ module Arel assert_equal 'SELECT DISTINCT', compile(core) end + it 'encloses LATERAL queries in parens' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + compile(subquery.lateral).must_be_like %{ + LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') + } + end + + it 'produces LATERAL queries with alias' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + compile(subquery.lateral('bar')).must_be_like %{ + LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') bar + } + end + describe "Nodes::Matches" do it "should know how to visit" do node = @table[:name].matches('foo%') |