From 4cb02380116b102142f85d92b7923c11882f94c7 Mon Sep 17 00:00:00 2001 From: Stephen Prater & Fire-Dragon-DoL Date: Wed, 31 Jul 2013 01:08:22 +0200 Subject: Added right and full outer joins --- lib/arel/nodes.rb | 2 ++ lib/arel/nodes/full_outer_join.rb | 6 ++++++ lib/arel/nodes/right_outer_join.rb | 6 ++++++ lib/arel/visitors/depth_first.rb | 2 ++ lib/arel/visitors/dot.rb | 4 +++- lib/arel/visitors/to_sql.rb | 8 ++++++++ test/test_select_manager.rb | 16 ++++++++++++++++ test/test_table.rb | 14 ++++++++++++++ test/visitors/test_depth_first.rb | 12 ++++++++++++ test/visitors/test_join_sql.rb | 26 ++++++++++++++++++++++++++ 10 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/full_outer_join.rb create mode 100644 lib/arel/nodes/right_outer_join.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 6ce1ed7dba..a68e327983 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -45,8 +45,10 @@ require 'arel/nodes/named_function' require 'arel/nodes/window' # joins +require 'arel/nodes/full_outer_join' require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' +require 'arel/nodes/right_outer_join' require 'arel/nodes/string_join' require 'arel/nodes/sql_literal' diff --git a/lib/arel/nodes/full_outer_join.rb b/lib/arel/nodes/full_outer_join.rb new file mode 100644 index 0000000000..708f161c9a --- /dev/null +++ b/lib/arel/nodes/full_outer_join.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class FullOuterJoin < Arel::Nodes::Join + end + end +end diff --git a/lib/arel/nodes/right_outer_join.rb b/lib/arel/nodes/right_outer_join.rb new file mode 100644 index 0000000000..ea1ddb7d52 --- /dev/null +++ b/lib/arel/nodes/right_outer_join.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class RightOuterJoin < Arel::Nodes::Join + end + end +end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 1770ab21d5..7043e5d527 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -67,6 +67,7 @@ module Arel alias :visit_Arel_Nodes_DeleteStatement :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary + alias :visit_Arel_Nodes_FullOuterJoin :binary alias :visit_Arel_Nodes_GreaterThan :binary alias :visit_Arel_Nodes_GreaterThanOrEqual :binary alias :visit_Arel_Nodes_In :binary @@ -80,6 +81,7 @@ module Arel alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_OuterJoin :binary + alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index b2fa6bfbd5..99f4c467d2 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -54,7 +54,9 @@ module Arel visit_edge o, "left" visit_edge o, "right" end - alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin def visit_Arel_Nodes_DeleteStatement o visit_edge o, "relation" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 0c2e649995..84a88e1899 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -446,10 +446,18 @@ module Arel visit o.left end + def visit_Arel_Nodes_FullOuterJoin o + "FULL OUTER JOIN #{visit o.left} #{visit o.right}" + end + def visit_Arel_Nodes_OuterJoin o "LEFT OUTER JOIN #{visit o.left} #{visit o.right}" end + def visit_Arel_Nodes_RightOuterJoin o + "RIGHT OUTER JOIN #{visit o.left} #{visit o.right}" + end + def visit_Arel_Nodes_InnerJoin o s = "INNER JOIN #{visit o.left}" if o.right diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 7f025f7a02..a0981476fe 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -517,6 +517,14 @@ module Arel assert_equal 'bar', join.right end + it 'should create join nodes with a klass' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin + assert_kind_of Arel::Nodes::FullOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + it 'should create join nodes with a klass' do relation = Arel::SelectManager.new Table.engine join = relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin @@ -525,6 +533,14 @@ module Arel assert_equal 'bar', join.right end + it 'should create join nodes with a klass' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin + assert_kind_of Arel::Nodes::RightOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + describe 'join' do it 'responds to join' do left = Table.new :users diff --git a/test/test_table.rb b/test/test_table.rb index 431a919de1..b4c2a65fcd 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -19,6 +19,13 @@ module Arel assert_equal 'bar', join.right end + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin + assert_kind_of Arel::Nodes::FullOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + it 'should create join nodes with a klass' do join = @relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin assert_kind_of Arel::Nodes::OuterJoin, join @@ -26,6 +33,13 @@ module Arel assert_equal 'bar', join.right end + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin + assert_kind_of Arel::Nodes::RightOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + it 'should return an insert manager' do im = @relation.compile_insert 'VALUES(NULL)' assert_kind_of Arel::InsertManager, im diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index cbaa780dae..baa8f64184 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -81,12 +81,24 @@ module Arel assert_equal [:a, :b, join], @collector.calls end + def test_full_outer_join + join = Nodes::FullOuterJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + def test_outer_join join = Nodes::OuterJoin.new :a, :b @visitor.accept join assert_equal [:a, :b, join], @collector.calls end + def test_right_outer_join + join = Nodes::RightOuterJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + [ Arel::Nodes::Assignment, Arel::Nodes::Between, diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index ea71c05d79..34378dafe7 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -25,6 +25,19 @@ module Arel end end + describe 'FULL outer join' do + it 'should visit left if left is a join' do + t = Table.new :users + sm = t.select_manager + sm.join(t, Nodes::FullOuterJoin).on(t[:id]).join( + t, Nodes::FullOuterJoin).on(t[:id]) + sm.join_sql.must_be_like %{ + FULL OUTER JOIN "users" ON "users"."id" + FULL OUTER JOIN "users" ON "users"."id" + } + end + end + describe 'outer join' do it 'should visit left if left is a join' do t = Table.new :users @@ -37,6 +50,19 @@ module Arel } end end + + describe 'right outer join' do + it 'should visit left if left is a join' do + t = Table.new :users + sm = t.select_manager + sm.join(t, Nodes::RightOuterJoin).on(t[:id]).join( + t, Nodes::RightOuterJoin).on(t[:id]) + sm.join_sql.must_be_like %{ + RIGHT OUTER JOIN "users" ON "users"."id" + RIGHT OUTER JOIN "users" ON "users"."id" + } + end + end end end end -- cgit v1.2.3 From 8e3e04f47dd356ec6a0adba32a440ce388767faa Mon Sep 17 00:00:00 2001 From: Kazuki Hasegawa Date: Thu, 3 Apr 2014 12:38:26 +0900 Subject: flatten object.children in visit_Arel_Node_And --- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_to_sql.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 84a88e1899..2d81022a7a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -500,7 +500,7 @@ module Arel end def visit_Arel_Nodes_And o - o.children.map { |x| visit x}.join ' AND ' + o.children.flatten.map { |x| visit x}.join ' AND ' end def visit_Arel_Nodes_Or o diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b142ecd695..0a7af91397 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -237,9 +237,9 @@ module Arel end it "should visit_Arel_Nodes_And" do - node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] + node = Nodes::And.new [@attr.eq(10), [@attr.eq(11), @attr.eq(12)]] @visitor.accept(node).must_be_like %{ - "users"."id" = 10 AND "users"."id" = 11 + "users"."id" = 10 AND "users"."id" = 11 AND "users"."id" = 12 } end -- cgit v1.2.3 From 7515445966b265dd9e90ce4457bff972e1fc3746 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 7 Apr 2014 10:04:40 -0700 Subject: Revert "Merge pull request #253 from corrupt952/master" This reverts commit 6d3ed6d96c4a3ac85b97d81bad95b7254b2aa2d4, reversing changes made to a35fede61ac1a2fcff519ad052f2fcb8808922b9. --- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_to_sql.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2d81022a7a..84a88e1899 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -500,7 +500,7 @@ module Arel end def visit_Arel_Nodes_And o - o.children.flatten.map { |x| visit x}.join ' AND ' + o.children.map { |x| visit x}.join ' AND ' end def visit_Arel_Nodes_Or o diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 0a7af91397..b142ecd695 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -237,9 +237,9 @@ module Arel end it "should visit_Arel_Nodes_And" do - node = Nodes::And.new [@attr.eq(10), [@attr.eq(11), @attr.eq(12)]] + node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] @visitor.accept(node).must_be_like %{ - "users"."id" = 10 AND "users"."id" = 11 AND "users"."id" = 12 + "users"."id" = 10 AND "users"."id" = 11 } end -- cgit v1.2.3 From 6296617c159d5cee0ba1c76f4ea983e3b5e26b6b Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 7 Mar 2014 13:15:33 +0000 Subject: Add Regexp and NotRegexp nodes for PostgreSQL --- lib/arel/nodes/binary.rb | 2 ++ lib/arel/visitors/depth_first.rb | 2 ++ lib/arel/visitors/postgresql.rb | 8 ++++++++ lib/arel/visitors/to_sql.rb | 8 ++++++++ test/visitors/test_postgres.rb | 34 ++++++++++++++++++++++++++++++++++ test/visitors/test_to_sql.rb | 20 ++++++++++++++++++++ 6 files changed, 74 insertions(+) diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 0e7e281b4b..939684957f 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -40,7 +40,9 @@ module Arel Matches NotEqual NotIn + NotRegexp Or + Regexp Union UnionAll Intersect diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 7043e5d527..4d2ecfa5e1 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -79,8 +79,10 @@ module Arel alias :visit_Arel_Nodes_Matches :binary alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary + alias :visit_Arel_Nodes_NotRegexp :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_OuterJoin :binary + alias :visit_Arel_Nodes_Regexp :binary alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 812710181c..49f7482e7d 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -11,6 +11,14 @@ module Arel "#{visit o.left} NOT ILIKE #{visit o.right}" end + def visit_Arel_Nodes_Regexp o + "#{visit o.left} ~ #{visit o.right}" + end + + def visit_Arel_Nodes_NotRegexp o + "#{visit o.left} !~ #{visit o.right}" + end + def visit_Arel_Nodes_DistinctOn o "DISTINCT ON ( #{visit o.expr} )" end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 84a88e1899..c1c192fa1a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -435,6 +435,14 @@ module Arel "#{visit o.left} NOT LIKE #{visit o.right}" end + def visit_Arel_Nodes_Regexp o + raise NotImplementedError, '~ not implemented for this db' + end + + def visit_Arel_Nodes_NotRegexp o + raise NotImplementedError, '!~ not implemented for this db' + end + def visit_Arel_Nodes_JoinSource o [ (visit(o.left) if o.left), diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 4287baaf14..995e9bf515 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -79,6 +79,40 @@ module Arel } end end + + describe "Nodes::Regexp" do + it "should know how to visit" do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + @visitor.accept(node).must_be_like %{ + "users"."name" ~ 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo%') + } + end + end + + describe "Nodes::NotRegexp" do + it "should know how to visit" do + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) + @visitor.accept(node).must_be_like %{ + "users"."name" !~ 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo%') + } + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b142ecd695..644951d71c 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -526,6 +526,26 @@ module Arel end end end + + describe 'Nodes::Regexp' do + it 'raises not implemented error' do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + + assert_raises(NotImplementedError) do + @visitor.accept(node) + end + end + end + + describe 'Nodes::NotRegexp' do + it 'raises not implemented error' do + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) + + assert_raises(NotImplementedError) do + @visitor.accept(node) + end + end + end end end end -- cgit v1.2.3 From d4cc1e33b80a546a58bcd2eaa49ea4c5e9682cbc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 7 Apr 2014 17:10:27 -0700 Subject: fix whitespace and unsupported method args --- lib/arel/visitors/to_sql.rb | 2 +- lib/arel/visitors/visitor.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 84a88e1899..5b71291f0b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -567,7 +567,7 @@ module Arel quote(o, column_for(a)) end - def unsupported o, a + def unsupported o raise "unsupported: #{o.class.name}" end diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 0540445088..0730c15794 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -19,7 +19,7 @@ module Arel end def visit object - send dispatch[object.class], object + send dispatch[object.class], object rescue NoMethodError => e raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| -- cgit v1.2.3 From 55c0071ce3685a78b4f039be24b2ab40b8779467 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 16:16:32 -0700 Subject: remove order_clauses since we do not use it --- lib/arel/select_manager.rb | 7 ------- lib/arel/visitors.rb | 1 - lib/arel/visitors/order_clauses.rb | 11 ----------- test/test_select_manager.rb | 10 ---------- 4 files changed, 29 deletions(-) delete mode 100644 lib/arel/visitors/order_clauses.rb diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 5ab2778778..f49f76d98f 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -220,13 +220,6 @@ module Arel Nodes::SqlLiteral.new sql end - def order_clauses - visitor = Visitors::OrderClauses.new(@engine.connection) - visitor.accept(@ast).map { |x| - Nodes::SqlLiteral.new x - } - end - def join_sources @ctx.source.right end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 8276eace2b..3986ad9ce5 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -8,7 +8,6 @@ require 'arel/visitors/mssql' require 'arel/visitors/oracle' require 'arel/visitors/join_sql' require 'arel/visitors/where_sql' -require 'arel/visitors/order_clauses' require 'arel/visitors/dot' require 'arel/visitors/ibm_db' require 'arel/visitors/informix' diff --git a/lib/arel/visitors/order_clauses.rb b/lib/arel/visitors/order_clauses.rb deleted file mode 100644 index 11dbfdad2a..0000000000 --- a/lib/arel/visitors/order_clauses.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Arel - module Visitors - class OrderClauses < Arel::Visitors::ToSql - private - - def visit_Arel_Nodes_SelectStatement o - o.orders.map { |x| visit x } - end - end - end -end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index a0981476fe..6258705e2f 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -628,16 +628,6 @@ module Arel end end - describe 'order_clauses' do - it 'returns order clauses as a list' do - table = Table.new :users - manager = Arel::SelectManager.new Table.engine - manager.from table - manager.order table[:id] - manager.order_clauses.first.must_be_like %{ "users"."id" } - end - end - describe 'group' do it 'takes an attribute' do table = Table.new :users -- cgit v1.2.3