module CompositePrimaryKeys module ActiveRecord module Calculations 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 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 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 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 end end end