diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 2cfd528f2c..7031c67539 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -48,6 +48,7 @@ module ActiveRecord autoload :Attributes autoload :AutosaveAssociation autoload :Relation + autoload :RelationalCalculations autoload :Base autoload :Batches autoload :Calculations diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index cb252eea70..291e97ff83 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -4,6 +4,7 @@ module ActiveRecord delegate :length, :collect, :map, :each, :all?, :to => :to_a attr_reader :relation, :klass, :associations_to_preload, :eager_load_associations + include RelationalCalculations def initialize(klass, relation, readonly = false, preload = [], eager_load = []) @klass, @relation = klass, relation @readonly = readonly @@ -204,20 +205,6 @@ module ActiveRecord end end - def count(*args) - column_name, options = construct_count_options_from_args(*args) - distinct = options[:distinct] ? true : false - - column = if @klass.column_names.include?(column_name.to_s) - Arel::Attribute.new(@relation.table, column_name) - else - Arel::SqlLiteral.new(column_name == :all ? "*" : column_name.to_s) - end - - relation = select(column.count(distinct)) - @klass.connection.select_value(relation.to_sql).to_i - end - def destroy_all to_a.each {|object| object.destroy} reset @@ -351,36 +338,5 @@ module ActiveRecord }.join(',') end - def construct_count_options_from_args(*args) - options = {} - column_name = :all - - # We need to handle - # count() - # count(:column_name=:all) - # count(options={}) - # count(column_name=:all, options={}) - # selects specified by scopes - - # TODO : relation.projections only works when .select() was last in the chain. Fix it! - case args.size - when 0 - column_name = @relation.send(:select_clauses).join(', ') if @relation.respond_to?(:projections) && @relation.projections.present? - when 1 - if args[0].is_a?(Hash) - column_name = @relation.send(:select_clauses).join(', ') if @relation.respond_to?(:projections) && @relation.projections.present? - options = args[0] - else - column_name = args[0] - end - when 2 - column_name, options = args - else - raise ArgumentError, "Unexpected parameters passed to count(): #{args.inspect}" - end - - [column_name || :all, options] - end - end end diff --git a/activerecord/lib/active_record/relational_calculations.rb b/activerecord/lib/active_record/relational_calculations.rb new file mode 100644 index 0000000000..10eb992167 --- /dev/null +++ b/activerecord/lib/active_record/relational_calculations.rb @@ -0,0 +1,52 @@ +module ActiveRecord + module RelationalCalculations + + def count(*args) + column_name, options = construct_count_options_from_args(*args) + distinct = options[:distinct] ? true : false + + column = if @klass.column_names.include?(column_name.to_s) + Arel::Attribute.new(@relation.table, column_name) + else + Arel::SqlLiteral.new(column_name == :all ? "*" : column_name.to_s) + end + + relation = select(column.count(distinct)) + @klass.connection.select_value(relation.to_sql).to_i + end + + private + + def construct_count_options_from_args(*args) + options = {} + column_name = :all + + # We need to handle + # count() + # count(:column_name=:all) + # count(options={}) + # count(column_name=:all, options={}) + # selects specified by scopes + + # TODO : relation.projections only works when .select() was last in the chain. Fix it! + case args.size + when 0 + column_name = @relation.send(:select_clauses).join(', ') if @relation.respond_to?(:projections) && @relation.projections.present? + when 1 + if args[0].is_a?(Hash) + column_name = @relation.send(:select_clauses).join(', ') if @relation.respond_to?(:projections) && @relation.projections.present? + options = args[0] + else + column_name = args[0] + end + when 2 + column_name, options = args + else + raise ArgumentError, "Unexpected parameters passed to count(): #{args.inspect}" + end + + [column_name || :all, options] + end + + end +end