mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
attributes do not need a column member
This commit is contained in:
parent
dbc1f65244
commit
40603729cc
12 changed files with 65 additions and 34 deletions
|
@ -1,6 +1,6 @@
|
|||
module Arel
|
||||
module Attributes
|
||||
class Attribute < Struct.new :relation, :name, :column
|
||||
class Attribute < Struct.new :relation, :name
|
||||
include Arel::Expressions
|
||||
include Arel::Predications
|
||||
end
|
||||
|
|
|
@ -4,6 +4,10 @@ module Arel
|
|||
alias :attribute :expr
|
||||
alias :attribute= :expr=
|
||||
|
||||
def relation
|
||||
@expr.relation
|
||||
end
|
||||
|
||||
def column
|
||||
@expr.column
|
||||
end
|
||||
|
|
|
@ -143,8 +143,8 @@ module Arel
|
|||
def join_sql
|
||||
return nil unless @ctx.froms
|
||||
|
||||
viz = Visitors::JoinSql.new @engine
|
||||
Nodes::SqlLiteral.new viz.accept @ctx
|
||||
sql = @visitor.dup.extend(Visitors::JoinSql).accept @ctx
|
||||
Nodes::SqlLiteral.new sql
|
||||
end
|
||||
|
||||
def order_clauses
|
||||
|
|
|
@ -17,7 +17,6 @@ module Arel
|
|||
|
||||
if Hash === engine
|
||||
@engine = engine[:engine] || Table.engine
|
||||
@columns = attributes_for engine[:columns]
|
||||
|
||||
# Sometime AR sends an :as parameter to table, to let the table know
|
||||
# that it is an Alias. We may want to override new, and return a
|
||||
|
@ -93,15 +92,18 @@ module Arel
|
|||
end
|
||||
|
||||
def columns
|
||||
if $VERBOSE
|
||||
warn <<-eowarn
|
||||
(#{caller.first}) Arel::Table#columns is deprecated and will be removed in
|
||||
Arel 2.2.0 with no replacement.
|
||||
eowarn
|
||||
end
|
||||
@columns ||=
|
||||
attributes_for @engine.connection.columns(@name, "#{@name} Columns")
|
||||
end
|
||||
|
||||
def [] name
|
||||
return nil unless table_exists?
|
||||
|
||||
name = name.to_sym
|
||||
columns.find { |column| column.name == name }
|
||||
::Arel::Attribute.new self, name.to_sym
|
||||
end
|
||||
|
||||
def select_manager
|
||||
|
@ -118,7 +120,7 @@ module Arel
|
|||
return nil unless columns
|
||||
|
||||
columns.map do |column|
|
||||
Attributes.for(column).new self, column.name.to_sym, column
|
||||
Attributes.for(column).new self, column.name.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ module Arel
|
|||
#
|
||||
# This visitor is used in SelectManager#join_sql and is for backwards
|
||||
# compatibility with Arel V1.0
|
||||
class JoinSql < Arel::Visitors::ToSql
|
||||
module JoinSql
|
||||
private
|
||||
|
||||
def visit_Arel_Nodes_SelectCore o
|
||||
|
|
|
@ -10,7 +10,8 @@ module Arel
|
|||
@last_column = nil
|
||||
@quoted_tables = {}
|
||||
@quoted_columns = {}
|
||||
@column_cache = {}
|
||||
@column_cache = Hash.new { |h,k| h[k] = {} }
|
||||
@table_exists = {}
|
||||
end
|
||||
|
||||
def accept object
|
||||
|
@ -67,17 +68,35 @@ module Arel
|
|||
o.alias ? " AS #{visit o.alias}" : ''}"
|
||||
end
|
||||
|
||||
def column_for relation, name
|
||||
name = name.to_s
|
||||
table = relation.name
|
||||
def table_exists? name
|
||||
return true if @table_exists.key? name
|
||||
if @connection.table_exists?(name)
|
||||
@table_exists[name] = true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
columns = @connection.columns(table, "#{table} Columns")
|
||||
columns.find { |col| col.name.to_s == name }
|
||||
def column_for attr
|
||||
name = attr.name.to_sym
|
||||
table = attr.relation.name
|
||||
|
||||
return nil unless table_exists? table
|
||||
|
||||
# If we don't have this column cached, get a list of columns and
|
||||
# cache them for this table
|
||||
unless @column_cache.key? table
|
||||
#$stderr.puts "MISS: #{self.class.name} #{object_id} #{table.inspect} : #{name.inspect}"
|
||||
columns = @connection.columns(table, "#{table}(#{name}) Columns")
|
||||
@column_cache[table] = Hash[columns.map { |c| [c.name.to_sym, c] }]
|
||||
end
|
||||
|
||||
@column_cache[table][name]
|
||||
end
|
||||
|
||||
def visit_Arel_Nodes_Values o
|
||||
"VALUES (#{o.expressions.zip(o.columns).map { |value, attr|
|
||||
quote(value, attr && column_for(attr.relation, attr.name))
|
||||
quote(value, attr && column_for(attr))
|
||||
}.join ', '})"
|
||||
end
|
||||
|
||||
|
@ -235,7 +254,7 @@ module Arel
|
|||
end
|
||||
|
||||
def visit_Arel_Nodes_Assignment o
|
||||
right = quote(o.right, o.left.column)
|
||||
right = quote(o.right, column_for(o.left))
|
||||
"#{visit o.left} = #{right}"
|
||||
end
|
||||
|
||||
|
@ -268,7 +287,7 @@ module Arel
|
|||
end
|
||||
|
||||
def visit_Arel_Attributes_Attribute o
|
||||
@last_column = o.column
|
||||
@last_column = column_for o
|
||||
join_name = o.relation.table_alias || o.relation.name
|
||||
"#{quote_table_name join_name}.#{quote_column_name o.name}"
|
||||
end
|
||||
|
|
|
@ -13,7 +13,8 @@ module Arel
|
|||
|
||||
def visit object
|
||||
send DISPATCH[object.class], object
|
||||
rescue NoMethodError
|
||||
rescue NoMethodError => e
|
||||
raise e if respond_to?(DISPATCH[object.class], true)
|
||||
warn "visiting #{object.class} via superclass, this will be removed in arel 2.2.0" if $VERBOSE
|
||||
superklass = object.class.ancestors.find { |klass|
|
||||
respond_to?(DISPATCH[klass], true)
|
||||
|
|
|
@ -326,7 +326,7 @@ module Arel
|
|||
|
||||
describe '#eq' do
|
||||
it 'should return an equality node' do
|
||||
attribute = Attribute.new nil, nil, nil
|
||||
attribute = Attribute.new nil, nil
|
||||
equality = attribute.eq 1
|
||||
equality.left.must_equal attribute
|
||||
equality.right.must_equal 1
|
||||
|
@ -485,7 +485,7 @@ module Arel
|
|||
end
|
||||
|
||||
it 'should return an in node' do
|
||||
attribute = Attribute.new nil, nil, nil
|
||||
attribute = Attribute.new nil, nil
|
||||
node = Nodes::In.new attribute, [1,2,3]
|
||||
node.left.must_equal attribute
|
||||
node.right.must_equal [1, 2, 3]
|
||||
|
@ -538,7 +538,7 @@ module Arel
|
|||
end
|
||||
|
||||
it 'should return a NotIn node' do
|
||||
attribute = Attribute.new nil, nil, nil
|
||||
attribute = Attribute.new nil, nil
|
||||
node = Nodes::NotIn.new attribute, [1,2,3]
|
||||
node.left.must_equal attribute
|
||||
node.right.must_equal [1, 2, 3]
|
||||
|
|
|
@ -26,6 +26,13 @@ module Arel
|
|||
def quote_table_name thing; @engine.connection.quote_table_name thing end
|
||||
def quote_column_name thing; @engine.connection.quote_column_name thing end
|
||||
def quote thing, column; @engine.connection.quote thing, column end
|
||||
def columns table, message = nil
|
||||
@engine.connection.columns table, message
|
||||
end
|
||||
|
||||
def table_exists? name
|
||||
@engine.connection.table_exists? name
|
||||
end
|
||||
|
||||
def execute sql, name = nil, *args
|
||||
@executed << sql
|
||||
|
|
|
@ -174,13 +174,6 @@ module Arel
|
|||
it "manufactures an attribute if the symbol names an attribute within the relation" do
|
||||
column = @relation[:id]
|
||||
column.name.must_equal :id
|
||||
column.must_be_kind_of Attributes::Integer
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when table does not exist' do
|
||||
it 'returns nil' do
|
||||
@relation[:foooo].must_be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,8 @@ module Arel
|
|||
module Visitors
|
||||
describe 'the join_sql visitor' do
|
||||
before do
|
||||
@visitor = JoinSql.new Table.engine
|
||||
@visitor = ToSql.new Table.engine
|
||||
@visitor.extend(JoinSql)
|
||||
end
|
||||
|
||||
describe 'inner join' do
|
||||
|
|
|
@ -84,7 +84,7 @@ module Arel
|
|||
end
|
||||
|
||||
it "should visit visit_Arel_Attributes_Time" do
|
||||
attr = Attributes::Time.new(@attr.relation, @attr.name, @attr.column)
|
||||
attr = Attributes::Time.new(@attr.relation, @attr.name)
|
||||
@visitor.accept attr
|
||||
end
|
||||
|
||||
|
@ -143,7 +143,9 @@ module Arel
|
|||
end
|
||||
in_node = Nodes::In.new @attr, %w{ a b c }
|
||||
visitor = visitor.new(Table.engine)
|
||||
visitor.expected = @attr.column
|
||||
visitor.expected = Table.engine.connection.columns(:users).find { |x|
|
||||
x.name == 'name'
|
||||
}
|
||||
visitor.accept(in_node).must_equal %("users"."name" IN ('a', 'b', 'c'))
|
||||
end
|
||||
end
|
||||
|
@ -189,7 +191,9 @@ module Arel
|
|||
end
|
||||
in_node = Nodes::NotIn.new @attr, %w{ a b c }
|
||||
visitor = visitor.new(Table.engine)
|
||||
visitor.expected = @attr.column
|
||||
visitor.expected = Table.engine.connection.columns(:users).find { |x|
|
||||
x.name == 'name'
|
||||
}
|
||||
visitor.accept(in_node).must_equal %("users"."name" NOT IN ('a', 'b', 'c'))
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue