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

use a hash to store relation values

This commit is contained in:
Jon Leighton 2012-04-13 15:59:47 +01:00
parent 1480dfa3ba
commit 6311975fb3
5 changed files with 74 additions and 52 deletions

View file

@ -29,11 +29,7 @@ module ActiveRecord
@implicit_readonly = nil
@loaded = false
@default_scoped = false
SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)}
MULTI_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_values", [])}
@create_with_value = {}
@values = {}
end
def insert(values)
@ -84,7 +80,8 @@ module ActiveRecord
end
def initialize_copy(other)
@bind_values = @bind_values.dup
@values = @values.dup
@values[:bind] = @values[:bind].dup if @values[:bind]
reset
end
@ -174,17 +171,17 @@ module ActiveRecord
default_scoped = with_default_scope
if default_scoped.equal?(self)
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, @bind_values)
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
preload = @preload_values
preload += @includes_values unless eager_loading?
preload = preload_values
preload += includes_values unless eager_loading?
preload.each do |associations|
ActiveRecord::Associations::Preloader.new(@records, associations).run
end
# @readonly_value is true only if set explicitly. @implicit_readonly is true if there
# are JOINS and no explicit SELECT.
readonly = @readonly_value.nil? ? @implicit_readonly : @readonly_value
readonly = readonly_value.nil? ? @implicit_readonly : readonly_value
@records.each { |record| record.readonly! } if readonly
else
@records = default_scoped.to_a
@ -224,7 +221,7 @@ module ActiveRecord
if block_given?
to_a.many? { |*block_args| yield(*block_args) }
else
@limit_value ? to_a.many? : size > 1
limit_value ? to_a.many? : size > 1
end
end
@ -460,7 +457,7 @@ module ActiveRecord
end
def to_sql
@to_sql ||= klass.connection.to_sql(arel, @bind_values.dup)
@to_sql ||= klass.connection.to_sql(arel, bind_values.dup)
end
def where_values_hash
@ -482,8 +479,8 @@ module ActiveRecord
def eager_loading?
@should_eager_load ||=
@eager_load_values.any? ||
@includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
eager_load_values.any? ||
includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
end
# Joins that are also marked for preloading. In which case we should just eager load them.
@ -491,7 +488,7 @@ module ActiveRecord
# represent the same association, but that aren't matched by this. Also, we could have
# nested hashes which partially match, e.g. { :a => :b } & { :a => [:b, :c] }
def joined_includes_values
@includes_values & @joins_values
includes_values & joins_values
end
def ==(other)

View file

@ -216,7 +216,7 @@ module ActiveRecord
distinct = nil if column_name =~ /\s*DISTINCT\s+/i
end
if @group_values.any?
if group_values.any?
execute_grouped_calculation(operation, column_name, distinct)
else
execute_simple_calculation(operation, column_name, distinct)
@ -259,7 +259,7 @@ module ActiveRecord
end
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
group_attr = @group_values
group_attr = group_values
association = @klass.reflect_on_association(group_attr.first.to_sym)
associated = group_attr.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
group_fields = Array(associated ? association.foreign_key : group_attr)
@ -282,7 +282,7 @@ module ActiveRecord
operation,
distinct).as(aggregate_alias)
]
select_values += @select_values unless @having_values.empty?
select_values += select_values unless having_values.empty?
select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
"#{field} AS #{aliaz}"
@ -347,8 +347,8 @@ module ActiveRecord
end
def select_for_count
if @select_values.present?
select = @select_values.join(", ")
if select_values.present?
select = select_values.join(", ")
select if select !~ /[,*]/
end
end

View file

@ -236,12 +236,12 @@ module ActiveRecord
end
def construct_join_dependency_for_association_find
including = (@eager_load_values + @includes_values).uniq
including = (eager_load_values + includes_values).uniq
ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
end
def construct_relation_for_association_calculations
including = (@eager_load_values + @includes_values).uniq
including = (eager_load_values + includes_values).uniq
join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
relation = except(:includes, :eager_load, :preload)
apply_join_dependency(relation, join_dependency)
@ -340,7 +340,7 @@ module ActiveRecord
id = id.id if ActiveRecord::Base === id
column = columns_hash[primary_key]
substitute = connection.substitute_at(column, @bind_values.length)
substitute = connection.substitute_at(column, bind_values.length)
relation = where(table[primary_key].eq(substitute))
relation.bind_values += [[column, id]]
record = relation.first
@ -358,15 +358,15 @@ module ActiveRecord
result = where(table[primary_key].in(ids)).all
expected_size =
if @limit_value && ids.size > @limit_value
@limit_value
if limit_value && ids.size > limit_value
limit_value
else
ids.size
end
# 11 ids with limit 3, offset 9 should give 2 results.
if @offset_value && (ids.size - @offset_value < expected_size)
expected_size = ids.size - @offset_value
if offset_value && (ids.size - offset_value < expected_size)
expected_size = ids.size - offset_value
end
if result.size == expected_size

View file

@ -5,12 +5,37 @@ module ActiveRecord
module QueryMethods
extend ActiveSupport::Concern
attr_accessor :includes_values, :eager_load_values, :preload_values,
:select_values, :group_values, :order_values, :joins_values,
:where_values, :having_values, :bind_values,
:limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value,
:from_value, :reordering_value, :reverse_order_value,
:uniq_value, :references_values, :extending_values
Relation::MULTI_VALUE_METHODS.each do |name|
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}_values # def select_values
@values[:#{name}] || [] # @values[:select] || []
end # end
#
def #{name}_values=(values) # def select_values=(values)
@values[:#{name}] = values # @values[:select] = values
end # end
CODE
end
(Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}_value # def readonly_value
@values[:#{name}] # @values[:readonly]
end # end
#
def #{name}_value=(value) # def readonly_value=(value)
@values[:#{name}] = value # @values[:readonly] = value
end # end
CODE
end
def create_with_value
@values[:create_with] || {}
end
def create_with_value=(value)
@values[:create_with] = value
end
alias extensions extending_values
@ -372,26 +397,26 @@ module ActiveRecord
def build_arel
arel = table.from table
build_joins(arel, @joins_values) unless @joins_values.empty?
build_joins(arel, joins_values) unless joins_values.empty?
collapse_wheres(arel, (@where_values - ['']).uniq)
collapse_wheres(arel, (where_values - ['']).uniq)
arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
arel.having(*having_values.uniq.reject{|h| h.blank?}) unless having_values.empty?
arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
arel.skip(@offset_value.to_i) if @offset_value
arel.take(connection.sanitize_limit(limit_value)) if limit_value
arel.skip(offset_value.to_i) if offset_value
arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty?
arel.group(*group_values.uniq.reject{|g| g.blank?}) unless group_values.empty?
order = @order_values
order = reverse_sql_order(order) if @reverse_order_value
order = order_values
order = reverse_sql_order(order) if reverse_order_value
arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty?
build_select(arel, @select_values.uniq)
build_select(arel, select_values.uniq)
arel.distinct(@uniq_value)
arel.from(@from_value) if @from_value
arel.lock(@lock_value) if @lock_value
arel.distinct(uniq_value)
arel.from(from_value) if from_value
arel.lock(lock_value) if lock_value
arel
end

View file

@ -43,19 +43,19 @@ module ActiveRecord
relation = Relation.new :a, :b
assert_equal({}, relation.where_values_hash)
relation.where_values << :hello
relation.where! :hello
assert_equal({}, relation.where_values_hash)
end
def test_has_values
relation = Relation.new Post, Post.arel_table
relation.where_values << relation.table[:id].eq(10)
relation.where! relation.table[:id].eq(10)
assert_equal({:id => 10}, relation.where_values_hash)
end
def test_values_wrong_table
relation = Relation.new Post, Post.arel_table
relation.where_values << Comment.arel_table[:id].eq(10)
relation.where! Comment.arel_table[:id].eq(10)
assert_equal({}, relation.where_values_hash)
end
@ -64,7 +64,7 @@ module ActiveRecord
left = relation.table[:id].eq(10)
right = relation.table[:id].eq(10)
combine = left.and right
relation.where_values << combine
relation.where! combine
assert_equal({}, relation.where_values_hash)
end
@ -87,7 +87,7 @@ module ActiveRecord
def test_create_with_value_with_wheres
relation = Relation.new Post, Post.arel_table
relation.where_values << relation.table[:id].eq(10)
relation.where! relation.table[:id].eq(10)
relation.create_with_value = {:hello => 'world'}
assert_equal({:hello => 'world', :id => 10}, relation.scope_for_create)
end
@ -97,7 +97,7 @@ module ActiveRecord
relation = Relation.new Post, Post.arel_table
assert_equal({}, relation.scope_for_create)
relation.where_values << relation.table[:id].eq(10)
relation.where! relation.table[:id].eq(10)
assert_equal({}, relation.scope_for_create)
relation.create_with_value = {:hello => 'world'}
@ -111,7 +111,7 @@ module ActiveRecord
def test_eager_load_values
relation = Relation.new :a, :b
relation.eager_load_values << :b
relation.eager_load! :b
assert relation.eager_loading?
end