1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Defer Arel attribute lookup to the model class

This still isn't as separated as I'd like, but it at least moves most of
the burden of alias mapping in one place.
This commit is contained in:
Matthew Draper 2016-02-04 08:02:45 +10:30
parent 7710d7f432
commit cdc112e3ea
12 changed files with 34 additions and 31 deletions

View file

@ -75,7 +75,7 @@ module ActiveRecord
column = klass.columns_hash[reflection.type.to_s] column = klass.columns_hash[reflection.type.to_s]
binds << Relation::QueryAttribute.new(column.name, value, klass.type_for_attribute(column.name)) binds << Relation::QueryAttribute.new(column.name, value, klass.type_for_attribute(column.name))
constraint = constraint.and table[reflection.type].eq(Arel::Nodes::BindParam.new) constraint = constraint.and klass.arel_attribute(reflection.type, table).eq(Arel::Nodes::BindParam.new)
end end
joins << table.create_join(table, table.create_on(constraint), join_type) joins << table.create_join(table, table.create_on(constraint), join_type)

View file

@ -47,7 +47,7 @@ module ActiveRecord
# This is overridden by HABTM as the condition should be on the foreign_key column in # This is overridden by HABTM as the condition should be on the foreign_key column in
# the join table # the join table
def association_key def association_key
table[association_key_name] klass.arel_attribute(association_key_name, table)
end end
# The name of the key on the model which declares the association # The name of the key on the model which declares the association

View file

@ -256,6 +256,11 @@ module ActiveRecord
end end
end end
def arel_attribute(name, table) # :nodoc:
name = attribute_alias(name) if attribute_alias?(name)
table[name]
end
def predicate_builder # :nodoc: def predicate_builder # :nodoc:
@predicate_builder ||= PredicateBuilder.new(table_metadata) @predicate_builder ||= PredicateBuilder.new(table_metadata)
end end

View file

@ -192,7 +192,7 @@ module ActiveRecord
end end
def type_condition(table = arel_table) def type_condition(table = arel_table)
sti_column = table[inheritance_column] sti_column = arel_attribute(inheritance_column, table)
sti_names = ([self] + descendants).map(&:sti_name) sti_names = ([self] + descendants).map(&:sti_name)
sti_column.in(sti_names) sti_column.in(sti_names)

View file

@ -47,7 +47,7 @@ module ActiveRecord
if !primary_key_value && connection.prefetch_primary_key?(klass.table_name) if !primary_key_value && connection.prefetch_primary_key?(klass.table_name)
primary_key_value = connection.next_sequence_value(klass.sequence_name) primary_key_value = connection.next_sequence_value(klass.sequence_name)
values[klass.arel_table[klass.primary_key]] = primary_key_value values[klass.arel_attribute(klass.primary_key, table)] = primary_key_value
end end
end end
@ -373,9 +373,9 @@ module ActiveRecord
stmt.table(table) stmt.table(table)
if joins_values.any? if joins_values.any?
@klass.connection.join_to_update(stmt, arel, table[primary_key]) @klass.connection.join_to_update(stmt, arel, @klass.arel_attribute(primary_key, table))
else else
stmt.key = table[primary_key] stmt.key = @klass.arel_attribute(primary_key, table)
stmt.take(arel.limit) stmt.take(arel.limit)
stmt.order(*arel.orders) stmt.order(*arel.orders)
stmt.wheres = arel.constraints stmt.wheres = arel.constraints
@ -527,7 +527,7 @@ module ActiveRecord
stmt.from(table) stmt.from(table)
if joins_values.any? if joins_values.any?
@klass.connection.join_to_delete(stmt, arel, table[primary_key]) @klass.connection.join_to_delete(stmt, arel, @klass.arel_attribute(primary_key, table))
else else
stmt.wheres = arel.constraints stmt.wheres = arel.constraints
end end

View file

@ -204,15 +204,15 @@ module ActiveRecord
yield yielded_relation yield yielded_relation
break if ids.length < of break if ids.length < of
batch_relation = relation.where(table[primary_key].gt(primary_key_offset)) batch_relation = relation.where(klass.arel_attribute(primary_key, table).gt(primary_key_offset))
end end
end end
private private
def apply_limits(relation, start, finish) def apply_limits(relation, start, finish)
relation = relation.where(table[primary_key].gteq(start)) if start relation = relation.where(klass.arel_attribute(primary_key, table).gteq(start)) if start
relation = relation.where(table[primary_key].lteq(finish)) if finish relation = relation.where(klass.arel_attribute(primary_key, table).lteq(finish)) if finish
relation relation
end end

View file

@ -155,15 +155,7 @@ module ActiveRecord
# See also #ids. # See also #ids.
# #
def pluck(*column_names) def pluck(*column_names)
column_names.map! do |column_name| if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
if column_name.is_a?(Symbol) && attribute_alias?(column_name)
attribute_alias(column_name)
else
column_name.to_s
end
end
if loaded? && (column_names - @klass.column_names).empty?
return @records.pluck(*column_names) return @records.pluck(*column_names)
end end
@ -172,7 +164,7 @@ module ActiveRecord
else else
relation = spawn relation = spawn
relation.select_values = column_names.map { |cn| relation.select_values = column_names.map { |cn|
columns_hash.key?(cn) ? arel_table[cn] : cn @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? klass.arel_attribute(cn, table) : cn
} }
result = klass.connection.select_all(relation.arel, nil, bound_attributes) result = klass.connection.select_all(relation.arel, nil, bound_attributes)
result.cast_values(klass.attribute_types) result.cast_values(klass.attribute_types)

View file

@ -147,7 +147,7 @@ module ActiveRecord
def last(limit = nil) def last(limit = nil)
if limit if limit
if order_values.empty? && primary_key if order_values.empty? && primary_key
order(arel_table[primary_key].desc).limit(limit).reverse order(klass.arel_attribute(primary_key, table).desc).limit(limit).reverse
else else
to_a.last(limit) to_a.last(limit)
end end
@ -514,7 +514,7 @@ module ActiveRecord
# TODO: once the offset argument is removed from find_nth, # TODO: once the offset argument is removed from find_nth,
# find_nth_with_limit_and_offset can be merged into this method # find_nth_with_limit_and_offset can be merged into this method
relation = if order_values.empty? && primary_key relation = if order_values.empty? && primary_key
order(arel_table[primary_key].asc) order(klass.arel_attribute(primary_key, table).asc)
else else
self self
end end

View file

@ -3,7 +3,7 @@ module ActiveRecord
class RelationHandler # :nodoc: class RelationHandler # :nodoc:
def call(attribute, value) def call(attribute, value)
if value.select_values.empty? if value.select_values.empty?
value = value.select(value.klass.arel_table[value.klass.primary_key]) value = value.select(value.klass.arel_attribute(value.klass.primary_key, value.klass.arel_table))
end end
attribute.in(value.arel) attribute.in(value.arel)

View file

@ -1093,8 +1093,8 @@ module ActiveRecord
def arel_columns(columns) def arel_columns(columns)
columns.map do |field| columns.map do |field|
if (Symbol === field || String === field) && columns_hash.key?(field.to_s) && !from_clause.value if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
arel_table[field] klass.arel_attribute(field, table)
elsif Symbol === field elsif Symbol === field
connection.quote_table_name(field.to_s) connection.quote_table_name(field.to_s)
else else
@ -1105,7 +1105,7 @@ module ActiveRecord
def reverse_sql_order(order_query) def reverse_sql_order(order_query)
if order_query.empty? if order_query.empty?
return [table[primary_key].desc] if primary_key return [klass.arel_attribute(primary_key, table).desc] if primary_key
raise IrreversibleOrderError, raise IrreversibleOrderError,
"Relation has no current order and table has no primary key to be used as default order" "Relation has no current order and table has no primary key to be used as default order"
end end
@ -1170,12 +1170,10 @@ module ActiveRecord
order_args.map! do |arg| order_args.map! do |arg|
case arg case arg
when Symbol when Symbol
arg = klass.attribute_alias(arg) if klass.attribute_alias?(arg) klass.arel_attribute(arg, table).asc
table[arg].asc
when Hash when Hash
arg.map { |field, dir| arg.map { |field, dir|
field = klass.attribute_alias(field) if klass.attribute_alias?(field) klass.arel_attribute(field, table).send(dir.downcase)
table[field].send(dir.downcase)
} }
else else
arg arg

View file

@ -22,7 +22,11 @@ module ActiveRecord
end end
def arel_attribute(column_name) def arel_attribute(column_name)
arel_table[column_name] if klass
klass.arel_attribute(column_name, arel_table)
else
arel_table[column_name]
end
end end
def type(column_name) def type(column_name)

View file

@ -26,6 +26,10 @@ module ActiveRecord
def sanitize_sql_for_order(sql) def sanitize_sql_for_order(sql)
sql sql
end end
def arel_attribute(name, table)
table[name]
end
end end
def relation def relation