From 6b851c686faefe54efce0857f8b7b7b0c04bb673 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 18 Aug 2010 16:32:32 -0700 Subject: joins can be created --- lib/arel/nodes.rb | 3 +++ lib/arel/nodes/inner_join.rb | 13 +++++++++++++ lib/arel/nodes/on.rb | 11 +++++++++++ lib/arel/nodes/table_alias.rb | 20 ++++++++++++++++++++ lib/arel/select_manager.rb | 9 +++++++++ lib/arel/table.rb | 13 ++++++++++++- lib/arel/visitors/to_sql.rb | 25 +++++++++++++++++++------ 7 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 lib/arel/nodes/inner_join.rb create mode 100644 lib/arel/nodes/on.rb create mode 100644 lib/arel/nodes/table_alias.rb (limited to 'lib/arel') diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 4d6db39aec..7183a60591 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -10,3 +10,6 @@ require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' require 'arel/nodes/delete_statement' require 'arel/nodes/unqualified_column' +require 'arel/nodes/table_alias' +require 'arel/nodes/inner_join' +require 'arel/nodes/on' diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb new file mode 100644 index 0000000000..a39ded9f1c --- /dev/null +++ b/lib/arel/nodes/inner_join.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class InnerJoin + 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/on.rb b/lib/arel/nodes/on.rb new file mode 100644 index 0000000000..4cc76b70db --- /dev/null +++ b/lib/arel/nodes/on.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class On + attr_accessor :expr + + def initialize expr + @expr = expr + end + end + end +end diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb new file mode 100644 index 0000000000..4f1d70ee54 --- /dev/null +++ b/lib/arel/nodes/table_alias.rb @@ -0,0 +1,20 @@ +module Arel + module Nodes + class TableAlias + attr_reader :name, :relation, :columns + + def initialize name, relation + @name = name + @relation = relation + @columns = relation.columns.map { |column| + column.dup.tap { |col| col.relation = self } + } + end + + def [] name + name = name.to_s + columns.find { |column| column.name == name } + end + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f278465c51..533911e635 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -8,12 +8,21 @@ module Arel @ctx = @head.cores.last end + def on expr + @ctx.froms.last.constraint = Nodes::On.new(expr) + self + end + def from table @ctx.froms << table self end def project projection + projection = ::String == projection.class ? + Nodes::SqlLiteral.new(projection) : + projection + @ctx.projections << projection self end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 2df20e50e8..5a66db0627 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -5,19 +5,30 @@ module Arel @engine = nil class << self; attr_accessor :engine; end - attr_reader :name, :engine + attr_reader :name, :engine, :aliases def initialize name, engine = Table.engine @name = name @engine = engine @engine = engine[:engine] if Hash === engine @columns = nil + @aliases = [] + end + + def alias + Nodes::TableAlias.new("#{name}_2", self).tap do |node| + @aliases << node + end end def tm SelectManager.new(@engine).from(self) end + def join relation + SelectManager.new(@engine).from(Nodes::InnerJoin.new(self, relation, nil)) + end + def where condition tm.where condition end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 0e5998c573..3b0a0dc5df 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -36,7 +36,7 @@ module Arel }.join ', '})" unless o.columns.empty?), ("VALUES (#{o.values.map { |value| - value ? quote(visit(value)) : 'NULL' + value ? visit(value) : 'NULL' }.join ', '})" unless o.values.empty?), ].compact.join ' ' @@ -57,12 +57,24 @@ module Arel ].compact.join ' ' end + def visit_Arel_Nodes_TableAlias o + "#{visit o.relation} #{quote_table_name o.name}" + end + + def visit_Arel_Nodes_InnerJoin o + "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint}" + end + + def visit_Arel_Nodes_On o + "ON #{visit o.expr}" + end + def visit_Arel_Table o quote_table_name o.name end def visit_Arel_Nodes_In o - "#{visit o.left} IN (#{o.right.map { |x| quote visit x }.join ', '})" + "#{visit o.left} IN (#{o.right.map { |x| visit x }.join ', '})" end def visit_Arel_Nodes_Or o @@ -71,7 +83,7 @@ module Arel def visit_Arel_Nodes_Equality o right = o.right - right = right ? quote(visit(right)) : 'NULL' + right = right ? visit(right) : 'NULL' "#{visit o.left} = #{right}" end @@ -87,12 +99,13 @@ module Arel alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute def visit_Fixnum o; o end - alias :visit_Time :visit_Fixnum - alias :visit_String :visit_Fixnum - alias :visit_TrueClass :visit_Fixnum alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated + def visit_TrueClass o; quote(o) end + def visit_String o; quote(o) end + def visit_Time o; quote(o) end + DISPATCH = {} def visit object send "visit_#{object.class.name.gsub('::', '_')}", object -- cgit v1.2.3