Module: CompositePrimaryKeys::ActiveRecord::Calculations

Included in:
CompositeRelation
Defined in:
lib/composite_primary_keys/relation/calculations.rb

Instance Method Summary collapse

Instance Method Details

#aggregate_column(column_name) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/composite_primary_keys/relation/calculations.rb', line 4

def aggregate_column(column_name)
  # CPK
  if column_name.kind_of?(Array)
    # Note: Test don't seem to run this code?
    column_name.map do |column|
      @klass.arel_table[column]
    end
  elsif @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
    @klass.arel_table[column_name]
  else
    Arel.sql(column_name == :all ? "*" : column_name.to_s)
  end
end

#build_count_subquery(relation, column_name, distinct) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/composite_primary_keys/relation/calculations.rb', line 60

def build_count_subquery(relation, column_name, distinct)
  if column_name == :all
    column_alias = Arel.star
    # CPK
    # relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
    relation.select_values = [ Arel.sql(::ActiveRecord::FinderMethods::ONE_AS_ONE) ] unless distinct
  elsif column_name.is_a?(Array)
    column_alias = Arel.star
    relation.select_values = column_name.map do |column|
      Arel::Attribute.new(@klass.unscoped.table, column)
    end
  else
    column_alias = Arel.sql("count_column")
    relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
  end

  subquery_alias = Arel.sql("subquery_for_count")
  select_value = operation_over_aggregate_column(column_alias, "count", false)

  relation.build_subquery(subquery_alias, select_value)
end

#calculate(operation, column_name) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/composite_primary_keys/relation/calculations.rb', line 82

def calculate(operation, column_name)
  if has_include?(column_name)
    relation = apply_join_dependency

    if operation.to_s.downcase == "count"
      unless distinct_value || distinct_select?(column_name || select_for_count)
        relation.distinct!
        # CPK
        # relation.select_values = [ klass.primary_key || table[Arel.star] ]
        if klass.primary_key.present? && klass.primary_key.is_a?(Array)
          relation.select_values = klass.primary_key.map do |k|
            "#{connection.quote_table_name(klass.table_name)}.#{connection.quote_column_name(k)}"
          end
        else
          relation.select_values = [ klass.primary_key || table[Arel.star] ]
        end
      end
      # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
      relation.order_values = [] if group_values.empty?
    end

    relation.calculate(operation, column_name)
  else
    perform_calculation(operation, column_name)
  end
end

#execute_simple_calculation(operation, column_name, distinct) ⇒ Object

:nodoc:



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
53
54
55
56
57
58
# File 'lib/composite_primary_keys/relation/calculations.rb', line 18

def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
  column_alias = column_name

  # CPK
  # if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
  #   # Shortcut when limit is zero.
  #   return 0 if limit_value == 0
  #
  #   query_builder = build_count_subquery(spawn, column_name, distinct)
  if operation == "count"
    relation = unscope(:order)
    query_builder = build_count_subquery(spawn, column_name, distinct)
  else
    # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
    relation = unscope(:order).distinct!(false)

    column = aggregate_column(column_name)
    select_value = operation_over_aggregate_column(column, operation, distinct)
    select_value.distinct = true if operation == "sum" && distinct

    relation.select_values = [select_value]

    query_builder = relation.arel
  end

  result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }

  if operation != "count"
    type = column.try(:type_caster) ||
      lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
    type = type.subtype if ::ActiveRecord::Enum::EnumType === type
  end

  type_cast_calculated_value(result.cast_values.first, operation, type) do |value|
    type = column.try(:type_caster) ||
      # CPK
      # lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
      lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
    type.deserialize(value)
  end
end