From 6451188abf647d6aa855d22db8d2d62a2b2c4542 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 19 Aug 2010 10:37:50 -0700 Subject: [PATCH] adding outer joins --- lib/arel/crud.rb | 1 + lib/arel/nodes.rb | 2 ++ lib/arel/nodes/inner_join.rb | 9 +-------- lib/arel/nodes/join.rb | 13 +++++++++++++ lib/arel/nodes/outer_join.rb | 6 ++++++ lib/arel/select_manager.rb | 13 +++++++++---- lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/select_manager_spec.rb | 24 ++++++++++++++++++++++++ spec/arel/table_spec.rb | 4 ++-- 9 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 lib/arel/nodes/join.rb create mode 100644 lib/arel/nodes/outer_join.rb diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 6861ff016c..2bf5f85823 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -7,6 +7,7 @@ module Arel um = UpdateManager.new @engine if String === values + values = SqlLiteral.new values um.table @ctx.froms.last else um.table values.first.first.relation diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 7183a60591..67568b5fd4 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -11,5 +11,7 @@ require 'arel/nodes/update_statement' require 'arel/nodes/delete_statement' require 'arel/nodes/unqualified_column' require 'arel/nodes/table_alias' +require 'arel/nodes/join' require 'arel/nodes/inner_join' +require 'arel/nodes/outer_join' require 'arel/nodes/on' diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb index a39ded9f1c..bf10eeac18 100644 --- a/lib/arel/nodes/inner_join.rb +++ b/lib/arel/nodes/inner_join.rb @@ -1,13 +1,6 @@ module Arel module Nodes - class InnerJoin - attr_accessor :left, :right, :constraint - - def initialize left, right, constraint - @left = left - @right = right - @constraint = constraint - end + class InnerJoin < Arel::Nodes::Join end end end diff --git a/lib/arel/nodes/join.rb b/lib/arel/nodes/join.rb new file mode 100644 index 0000000000..6dede632c5 --- /dev/null +++ b/lib/arel/nodes/join.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class Join + attr_accessor :left, :right, :constraint + + def initialize left, right, constraint + @left = left + @right = right + @constraint = constraint + end + end + end +end diff --git a/lib/arel/nodes/outer_join.rb b/lib/arel/nodes/outer_join.rb new file mode 100644 index 0000000000..bea5578b95 --- /dev/null +++ b/lib/arel/nodes/outer_join.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class OuterJoin < Arel::Nodes::Join + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 533911e635..462b0765a5 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -19,10 +19,6 @@ module Arel end def project projection - projection = ::String == projection.class ? - Nodes::SqlLiteral.new(projection) : - projection - @ctx.projections << projection self end @@ -40,5 +36,14 @@ module Arel @head.limit = limit self end + + def join_sql + viz = Visitors::ToSql.new @engine + @ctx.froms.grep(Nodes::Join).map { |x| viz.accept x }.join ', ' + end + + def joins manager + manager.join_sql + end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 3b0a0dc5df..401bdb3255 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -61,6 +61,10 @@ module Arel "#{visit o.relation} #{quote_table_name o.name}" end + def visit_Arel_Nodes_OuterJoin o + "#{visit o.left} OUTER JOIN #{visit o.right} #{visit o.constraint}" + end + def visit_Arel_Nodes_InnerJoin o "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint}" end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 74e2db408b..331d9714a7 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -23,6 +23,30 @@ module Arel end describe 'select manager' do + describe 'joins' do + it 'returns join sql' do + table = Table.new :users + aliaz = table.alias + manager = Arel::SelectManager.new Table.engine + manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) + manager.join_sql.should be_like %{ + "users" INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" + } + check manager.joins(manager).should == manager.join_sql + end + + it 'returns outer join sql' do + table = Table.new :users + aliaz = table.alias + manager = Arel::SelectManager.new Table.engine + manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) + manager.join_sql.should be_like %{ + "users" OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" + } + check manager.joins(manager).should == manager.join_sql + end + end + describe 'delete' do it "copies from" do engine = EngineProxy.new Table.engine diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 58ccc9e7be..702608ed85 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -33,14 +33,14 @@ module Arel describe 'take' do it "should add a limit" do manager = @relation.take 1 - manager.project '*' + manager.project SqlLiteral.new '*' manager.to_sql.should be_like %{ SELECT * FROM "users" LIMIT 1 } end end describe 'project' do it 'can project' do - manager = @relation.project '*' + manager = @relation.project SqlLiteral.new '*' manager.to_sql.should be_like %{ SELECT * FROM "users"