aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/relation
diff options
context:
space:
mode:
authorJohn Mileham <jmileham@gmail.com>2011-03-03 23:26:45 -0500
committerJohn Mileham <jmileham@gmail.com>2011-03-03 23:26:45 -0500
commitd5994ee48af14d67f0eec7d23863d4b19211b078 (patch)
tree652e3356fe87d39dd37d1389544ceb8e59e406cd /activerecord/lib/active_record/relation
parent1db4969dc9cabed9db162e7194b9353d43c967d7 (diff)
downloadrails-d5994ee48af14d67f0eec7d23863d4b19211b078.tar.gz
rails-d5994ee48af14d67f0eec7d23863d4b19211b078.tar.bz2
rails-d5994ee48af14d67f0eec7d23863d4b19211b078.zip
Change behavior of count(:limit => x, :offset => y) to limit/offset before counting.
Diffstat (limited to 'activerecord/lib/active_record/relation')
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb40
1 files changed, 26 insertions, 14 deletions
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index c1842b1a96..7bfeb20a2b 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -183,10 +183,13 @@ module ActiveRecord
end
end
- def aggregate_column(column_name)
+ def aggregate_column(column_name, subquery_alias = nil)
if @klass.column_names.include?(column_name.to_s)
- Arel::Attribute.new(@klass.unscoped.table, column_name)
+ Arel::Attribute.new(subquery_alias || @klass.unscoped.table, column_name)
else
+ if subquery_alias && (split_name = column_name.to_s.split(".")).length > 1
+ column_name = split_name.last
+ end
Arel.sql(column_name == :all ? "*" : column_name.to_s)
end
end
@@ -196,24 +199,22 @@ module ActiveRecord
end
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
- column = aggregate_column(column_name)
-
# Postgresql doesn't like ORDER BY when there are no GROUP BY
relation = except(:order)
- select_value = operation_over_aggregate_column(column, operation, distinct)
- relation.select_values = [select_value]
+ if operation == "count" && (relation.limit_value || relation.offset_value)
+ # Shortcut when limit is zero.
+ return 0 if relation.limit_value == 0
- query_builder = relation.arel
+ query_builder = build_count_subquery(relation, column_name, distinct)
+ else
+ column = aggregate_column(column_name)
- if operation == "count"
- limit = relation.limit_value
- offset = relation.offset_value
+ select_value = operation_over_aggregate_column(column, operation, distinct)
- unless limit && offset
- query_builder.limit = nil
- query_builder.offset = nil
- end
+ relation.select_values = [select_value]
+
+ query_builder = relation.arel
end
type_cast_calculated_value(@klass.connection.select_value(query_builder.to_sql), column_for(column_name), operation)
@@ -312,5 +313,16 @@ module ActiveRecord
select if select !~ /(,|\*)/
end
end
+
+ def build_count_subquery(relation, column_name, distinct)
+ # Arel doesn't do subqueries
+ subquery_alias = arel_table.alias("subquery_for_count")
+ aliased_column = aggregate_column(column_name, subquery_alias)
+ select_value = operation_over_aggregate_column(aliased_column, 'count', distinct)
+
+ relation.select_values = [(column_name == :all ? 1 : aggregate_column(column_name))]
+ subquery_sql = "(#{relation.arel.to_sql}) #{subquery_alias.name}"
+ subquery_alias.relation.select_manager.project(select_value).from(subquery_sql)
+ end
end
end