aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/arel')
-rw-r--r--lib/arel/crud.rb1
-rw-r--r--lib/arel/nodes.rb5
-rw-r--r--lib/arel/nodes/inner_join.rb6
-rw-r--r--lib/arel/nodes/join.rb13
-rw-r--r--lib/arel/nodes/on.rb11
-rw-r--r--lib/arel/nodes/outer_join.rb6
-rw-r--r--lib/arel/nodes/table_alias.rb20
-rw-r--r--lib/arel/select_manager.rb14
-rw-r--r--lib/arel/table.rb13
-rw-r--r--lib/arel/visitors/to_sql.rb29
10 files changed, 111 insertions, 7 deletions
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 4d6db39aec..67568b5fd4 100644
--- a/lib/arel/nodes.rb
+++ b/lib/arel/nodes.rb
@@ -10,3 +10,8 @@ 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/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
new file mode 100644
index 0000000000..bf10eeac18
--- /dev/null
+++ b/lib/arel/nodes/inner_join.rb
@@ -0,0 +1,6 @@
+module Arel
+ module Nodes
+ 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/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/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/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..462b0765a5 100644
--- a/lib/arel/select_manager.rb
+++ b/lib/arel/select_manager.rb
@@ -8,6 +8,11 @@ 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
@@ -31,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/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..401bdb3255 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,28 @@ module Arel
].compact.join ' '
end
+ def visit_Arel_Nodes_TableAlias o
+ "#{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
+
+ 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 +87,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 +103,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