aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/relational_calculations.rb
blob: 10eb992167d520cb45fd017bcde7b057ead54b79 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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