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:
parent
1480dfa3ba
commit
6311975fb3
5 changed files with 74 additions and 52 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue