提交 6b851c68 编写于 作者: A Aaron Patterson

joins can be created

上级 0403efa4
......@@ -10,3 +10,6 @@
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'
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
module Arel
module Nodes
class On
attr_accessor :expr
def initialize expr
@expr = expr
end
end
end
end
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
......@@ -8,12 +8,21 @@ def initialize engine
@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
......
......@@ -5,19 +5,30 @@ class Table
@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
......
......@@ -36,7 +36,7 @@ def visit_Arel_Nodes_InsertStatement o
}.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 @@ def visit_Arel_Nodes_SelectCore o
].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 @@ def visit_Arel_Nodes_Or o
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 @@ def visit_Arel_Attributes_Attribute o
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
......
......@@ -54,7 +54,7 @@ def execute sql
table = Table.new :users
manager = Arel::SelectManager.new engine
manager.from table
manager.update('foo = bar')
manager.update(SqlLiteral.new('foo = bar'))
engine.executed.last.should be_like %{ UPDATE "users" SET foo = bar }
end
......@@ -89,7 +89,7 @@ def execute sql
it 'takes strings' do
table = Table.new :users
manager = Arel::SelectManager.new Table.engine
manager.project '*'
manager.project Nodes::SqlLiteral.new('*')
manager.to_sql.should be_like %{
SELECT *
}
......@@ -149,6 +149,24 @@ def execute sql
end
end
describe "join" do
it "joins itself" do
left = Table.new :users
right = left.alias
predicate = left[:id].eq(right[:id])
mgr = left.join(right)
mgr.project Nodes::SqlLiteral.new('*')
check mgr.on(predicate).should == mgr
mgr.to_sql.should be_like %{
SELECT * FROM "users"
INNER JOIN "users" "users_2"
ON "users"."id" = "users_2"."id"
}
end
end
describe 'from' do
it "makes sql" do
table = Table.new :users
......
......@@ -6,6 +6,18 @@ module Arel
@relation = Table.new(:users)
end
describe 'alias' do
it 'should create a node that proxies to a table' do
check @relation.aliases.should == []
node = @relation.alias
check @relation.aliases.should == [node]
check node.name.should == 'users_2'
check node[:id].relation.should == node
check node[:id].relation.should != node
end
end
describe 'new' do
it 'should accept an engine' do
rel = Table.new :users, 'foo'
......
......@@ -21,7 +21,7 @@ module Arel
table = Table.new(:users)
um = Arel::UpdateManager.new Table.engine
um.table table
um.set "foo = bar"
um.set Nodes::SqlLiteral.new "foo = bar"
um.to_sql.should be_like %{ UPDATE "users" SET foo = bar }
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册