diff options
Diffstat (limited to 'activerecord/lib/active_record/relation')
3 files changed, 54 insertions, 18 deletions
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 6bf698fe97..c8adaddfca 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -208,14 +208,16 @@ module ActiveRecord end def execute_grouped_calculation(operation, column_name, distinct) #:nodoc: - group_attr = @group_values.first - association = @klass.reflect_on_association(group_attr.to_sym) - associated = association && association.macro == :belongs_to # only count belongs_to associations - group_field = associated ? association.primary_key_name : group_attr - group_alias = column_alias_for(group_field) - group_column = column_for(group_field) + group_attr = @group_values + association = @klass.reflect_on_association(group_attr.first.to_sym) + associated = group_attr.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations + group_fields = Array(associated ? association.primary_key_name : group_attr) + group_aliases = group_fields.map { |field| column_alias_for(field) } + group_columns = group_aliases.zip(group_fields).map { |aliaz,field| + [aliaz, column_for(field)] + } - group = @klass.connection.adapter_name == 'FrontBase' ? group_alias : group_field + group = @klass.connection.adapter_name == 'FrontBase' ? group_aliases : group_fields if operation == 'count' && column_name == :all aggregate_alias = 'count_all' @@ -223,22 +225,33 @@ module ActiveRecord aggregate_alias = column_alias_for(operation, column_name) end - relation = except(:group).group(group) - relation.select_values = [ - operation_over_aggregate_column(aggregate_column(column_name), operation, distinct).as(aggregate_alias), - "#{group_field} AS #{group_alias}" + select_values = [ + operation_over_aggregate_column( + aggregate_column(column_name), + operation, + distinct).as(aggregate_alias) ] + select_values.concat group_fields.zip(group_aliases).map { |field,aliaz| + "#{field} AS #{aliaz}" + } + + relation = except(:group).group(group.join(',')) + relation.select_values = select_values + calculated_data = @klass.connection.select_all(relation.to_sql) if association - key_ids = calculated_data.collect { |row| row[group_alias] } + key_ids = calculated_data.collect { |row| row[group_aliases.first] } key_records = association.klass.base_class.find(key_ids) key_records = Hash[key_records.map { |r| [r.id, r] }] end ActiveSupport::OrderedHash[calculated_data.map do |row| - key = type_cast_calculated_value(row[group_alias], group_column) + key = group_columns.map { |aliaz, column| + type_cast_calculated_value(row[aliaz], column) + } + key = key.first if key.size == 1 key = key_records[key] if associated [key, type_cast_calculated_value(row[aggregate_alias], column_for(column_name), operation)] end] diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index c5428dccd6..32c7d08daa 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -25,6 +25,11 @@ module ActiveRecord attribute.in(values) when Range, Arel::Relation attribute.in(value) + when ActiveRecord::Base + attribute.eq(value.quoted_id) + when Class + # FIXME: I think we need to deprecate this behavior + attribute.eq(value.name) else attribute.eq(value) end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 9c399d3333..9e7503a60d 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -141,7 +141,7 @@ module ActiveRecord "#{@klass.table_name}.#{@klass.primary_key} DESC" : reverse_sql_order(order_clause).join(', ') - except(:order).order(Arel::SqlLiteral.new(order)) + except(:order).order(Arel.sql(order)) end def arel @@ -174,10 +174,7 @@ module ActiveRecord arel = build_joins(arel, @joins_values) unless @joins_values.empty? - (@where_values - ['']).uniq.each do |where| - where = Arel.sql(where) if String === where - arel = arel.where(Arel::Nodes::Grouping.new(where)) - end + arel = collapse_wheres(arel, (@where_values - ['']).uniq) arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty? @@ -198,6 +195,27 @@ module ActiveRecord private + def collapse_wheres(arel, wheres) + equalities = wheres.grep(Arel::Nodes::Equality) + + groups = equalities.group_by do |equality| + equality.left + end + + groups.each do |_, eqls| + test = eqls.inject(eqls.shift) do |memo, expr| + memo.or(expr) + end + arel = arel.where(test) + end + + (wheres - equalities).each do |where| + where = Arel.sql(where) if String === where + arel = arel.where(Arel::Nodes::Grouping.new(where)) + end + arel + end + def build_where(opts, other = []) case opts when String, Array |