diff --git a/lib/arel/nodes/infix_operation.rb b/lib/arel/nodes/infix_operation.rb index 3911a1e05e..a3f04da6fa 100644 --- a/lib/arel/nodes/infix_operation.rb +++ b/lib/arel/nodes/infix_operation.rb @@ -40,5 +40,10 @@ module Arel end end + class Concat < InfixOperation + def initialize left, right + super('||', left, right) + end + end end -end \ No newline at end of file +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index e9078e9c4b..81bf3b4d95 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -202,6 +202,10 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead. Nodes::Case.new(self).when quoted_node(right) end + def concat other + Nodes::Concat.new self, other + end + private def grouping_any method_id, others, *extras diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 2f71455580..fb21fb1e70 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -72,6 +72,7 @@ module Arel alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary + alias :visit_Arel_Nodes_Concat :binary alias :visit_Arel_Nodes_DeleteStatement :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index e0c02d717a..da75423523 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -176,6 +176,7 @@ module Arel alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary + alias :visit_Arel_Nodes_Concat :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary alias :visit_Arel_Nodes_GreaterThan :binary diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 724e0fc43e..ac3ad7b470 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -72,6 +72,14 @@ module Arel maybe_visit o.limit, collector end + def visit_Arel_Nodes_Concat o, collector + collector << " CONCAT(" + visit o.left, collector + collector << ", " + visit o.right, collector + collector << ") " + collector + end end end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 1a72789f83..81220b63a4 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -103,6 +103,7 @@ module Arel [ Arel::Nodes::Assignment, Arel::Nodes::Between, + Arel::Nodes::Concat, Arel::Nodes::DoesNotMatch, Arel::Nodes::Equality, Arel::Nodes::GreaterThan, diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 8e4b9e6861..30dcea3d36 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -55,6 +55,24 @@ module Arel compile(node).must_be_like "LOCK IN SHARE MODE" end end + + describe "concat" do + it "concats columns" do + @table = Table.new(:users) + query = @table[:name].concat(@table[:name]) + compile(query).must_be_like %{ + CONCAT("users"."name", "users"."name") + } + end + + it "concats a string" do + @table = Table.new(:users) + query = @table[:name].concat(Nodes.build_quoted('abc')) + compile(query).must_be_like %{ + CONCAT("users"."name", 'abc') + } + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index ea58039529..4162d970b5 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -469,13 +469,19 @@ module Arel compile(node).must_equal %(("products"."price" - 7)) end + it "should handle Concatination" do + table = Table.new(:users) + node = table[:name].concat(table[:name]) + compile(node).must_equal %("users"."name" || "users"."name") + end + it "should handle arbitrary operators" do node = Arel::Nodes::InfixOperation.new( - '||', + '&&', Arel::Attributes::String.new(Table.new(:products), :name), Arel::Attributes::String.new(Table.new(:products), :name) ) - compile(node).must_equal %("products"."name" || "products"."name") + compile(node).must_equal %("products"."name" && "products"."name") end end