mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add Relation#construct_relation_for_association_calculations for calculations with includes
This commit is contained in:
parent
71d67fc6bd
commit
b9599502c9
4 changed files with 17 additions and 42 deletions
|
@ -2,8 +2,6 @@ module ActiveRecord
|
||||||
module Calculations #:nodoc:
|
module Calculations #:nodoc:
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from]
|
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
# Count operates using three different approaches.
|
# Count operates using three different approaches.
|
||||||
#
|
#
|
||||||
|
@ -147,25 +145,10 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def validate_calculation_options(options = {})
|
|
||||||
options.assert_valid_keys(CALCULATIONS_OPTIONS)
|
|
||||||
end
|
|
||||||
|
|
||||||
def construct_calculation_arel(options = {})
|
def construct_calculation_arel(options = {})
|
||||||
validate_calculation_options(options)
|
relation = scoped.apply_finder_options(options.except(:distinct))
|
||||||
options = options.except(:distinct)
|
(relation.eager_loading? || relation.includes_values.present?) ? relation.send(:construct_relation_for_association_calculations) : relation
|
||||||
|
|
||||||
merge_with_includes = current_scoped_methods ? current_scoped_methods.includes_values : []
|
|
||||||
includes = (merge_with_includes + Array.wrap(options[:include])).uniq
|
|
||||||
|
|
||||||
if includes.any?
|
|
||||||
merge_with_joins = current_scoped_methods ? current_scoped_methods.joins_values : []
|
|
||||||
joins = (merge_with_joins + Array.wrap(options[:joins])).uniq
|
|
||||||
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins))
|
|
||||||
construct_finder_arel_with_included_associations(options, join_dependency)
|
|
||||||
else
|
|
||||||
scoped.apply_finder_options(options)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,12 +45,10 @@ module ActiveRecord
|
||||||
def to_a
|
def to_a
|
||||||
return @records if loaded?
|
return @records if loaded?
|
||||||
|
|
||||||
eager_loading = @eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?)
|
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql)
|
||||||
|
|
||||||
@records = eager_loading ? find_with_associations : @klass.find_by_sql(arel.to_sql)
|
|
||||||
|
|
||||||
preload = @preload_values
|
preload = @preload_values
|
||||||
preload += @includes_values unless eager_loading
|
preload += @includes_values unless eager_loading?
|
||||||
preload.each {|associations| @klass.send(:preload_associations, @records, associations) }
|
preload.each {|associations| @klass.send(:preload_associations, @records, associations) }
|
||||||
|
|
||||||
# @readonly_value is true only if set explicity. @implicit_readonly is true if there are JOINS and no explicit SELECT.
|
# @readonly_value is true only if set explicity. @implicit_readonly is true if there are JOINS and no explicit SELECT.
|
||||||
|
@ -112,6 +110,7 @@ module ActiveRecord
|
||||||
|
|
||||||
def reset
|
def reset
|
||||||
@first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
|
@first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
|
||||||
|
@should_eager_load = @join_dependency = nil
|
||||||
@records = []
|
@records = []
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
@ -133,6 +132,10 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def eager_loading?
|
||||||
|
@should_eager_load ||= (@eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?))
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def method_missing(method, *args, &block)
|
def method_missing(method, *args, &block)
|
||||||
|
|
|
@ -53,6 +53,12 @@ module ActiveRecord
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def construct_relation_for_association_calculations
|
||||||
|
including = (@eager_load_values + @includes_values).uniq
|
||||||
|
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, arel.joins(arel))
|
||||||
|
construct_relation_for_association_find(join_dependency)
|
||||||
|
end
|
||||||
|
|
||||||
def construct_relation_for_association_find(join_dependency)
|
def construct_relation_for_association_find(join_dependency)
|
||||||
relation = except(:includes, :eager_load, :preload, :select).select(@klass.send(:column_aliases, join_dependency))
|
relation = except(:includes, :eager_load, :preload, :select).select(@klass.send(:column_aliases, join_dependency))
|
||||||
|
|
||||||
|
|
|
@ -246,23 +246,6 @@ class CalculationsTest < ActiveRecord::TestCase
|
||||||
assert_equal 8, c['Jadedpixel']
|
assert_equal 8, c['Jadedpixel']
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_reject_invalid_options
|
|
||||||
assert_nothing_raised do
|
|
||||||
# empty options are valid
|
|
||||||
Company.send(:validate_calculation_options)
|
|
||||||
# these options are valid for all calculations
|
|
||||||
[:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
|
|
||||||
Company.send(:validate_calculation_options, opt => true)
|
|
||||||
end
|
|
||||||
|
|
||||||
# :include is only valid on :count
|
|
||||||
Company.send(:validate_calculation_options, :include => true)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) }
|
|
||||||
assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_count_selected_field_with_include
|
def test_should_count_selected_field_with_include
|
||||||
assert_equal 6, Account.count(:distinct => true, :include => :firm)
|
assert_equal 6, Account.count(:distinct => true, :include => :firm)
|
||||||
assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
|
assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
|
||||||
|
|
Loading…
Reference in a new issue