From 6296617c159d5cee0ba1c76f4ea983e3b5e26b6b Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 7 Mar 2014 13:15:33 +0000 Subject: [PATCH] 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