aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations.rb
diff options
context:
space:
mode:
authorMichael Koziarski <michael@koziarski.com>2006-02-09 09:17:40 +0000
committerMichael Koziarski <michael@koziarski.com>2006-02-09 09:17:40 +0000
commitd49a5fcb4cfe90824337dc3756bae7161cea768b (patch)
tree48af0b2f4c9301be8e0816e5ac759516862db2ef /activerecord/lib/active_record/associations.rb
parent803b9a41af46210da842afdba032c34109514942 (diff)
downloadrails-d49a5fcb4cfe90824337dc3756bae7161cea768b.tar.gz
rails-d49a5fcb4cfe90824337dc3756bae7161cea768b.tar.bz2
rails-d49a5fcb4cfe90824337dc3756bae7161cea768b.zip
* Fix pagination problems when using include
* Introduce Unit Tests for pagination * Allow count to work with :include by using count distinct. [Kevin Clark & Jeremy Hopple] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3553 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord/lib/active_record/associations.rb')
-rwxr-xr-xactiverecord/lib/active_record/associations.rb73
1 files changed, 59 insertions, 14 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index ea442021c5..6b461b5514 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -779,6 +779,11 @@ module ActiveRecord
end
end
end
+
+ def count_with_associations(options = {})
+ reflections = reflect_on_included_associations(options[:include])
+ return count_by_sql(construct_counter_sql_with_included_associations(options, reflections))
+ end
def find_with_associations(options = {})
reflections = reflect_on_included_associations(options[:include])
@@ -996,40 +1001,72 @@ module ActiveRecord
"#{name} Load Including Associations"
)
end
+
+ def construct_counter_sql_with_included_associations(options, reflections)
+ sql = "SELECT COUNT(DISTINCT #{table_name}.#{primary_key})"
+
+ # A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
+ if !Base.connection.supports_count_distinct?
+ sql = "SELECT COUNT(*) FROM (SELECT DISTINCT #{table_name}.#{primary_key}"
+ end
+
+ sql << " FROM #{table_name} "
+ sql << reflections.collect { |reflection| association_join(reflection) }.to_s
+ sql << "#{options[:joins]} " if options[:joins]
+
+ add_conditions!(sql, options[:conditions])
+ add_sti_conditions!(sql, reflections)
+ add_limited_ids_condition!(sql, options, reflections) if !using_limitable_reflections?(reflections) && options[:limit]
+
+ add_limit!(sql, options) if using_limitable_reflections?(reflections)
+
+ if !Base.connection.supports_count_distinct?
+ sql << ")"
+ end
+
+ return sanitize_sql(sql)
+ end
def construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections)
sql = "SELECT #{column_aliases(schema_abbreviations)} FROM #{table_name} "
sql << reflections.collect { |reflection| association_join(reflection) }.to_s
sql << "#{options[:joins]} " if options[:joins]
-
+
add_conditions!(sql, options[:conditions])
add_sti_conditions!(sql, reflections)
- add_limited_ids_condition!(sql, options) if !using_limitable_reflections?(reflections) && options[:limit]
+ add_limited_ids_condition!(sql, options, reflections) if !using_limitable_reflections?(reflections) && options[:limit]
sql << "ORDER BY #{options[:order]} " if options[:order]
-
+
add_limit!(sql, options) if using_limitable_reflections?(reflections)
-
+
return sanitize_sql(sql)
end
-
- def add_limited_ids_condition!(sql, options)
- unless (id_list = select_limited_ids_list(options)).empty?
+
+ def add_limited_ids_condition!(sql, options, reflections)
+ unless (id_list = select_limited_ids_list(options, reflections)).empty?
sql << "#{condition_word(sql)} #{table_name}.#{primary_key} IN (#{id_list}) "
end
end
-
- def select_limited_ids_list(options)
+
+ def select_limited_ids_list(options, reflections)
connection.select_values(
- construct_finder_sql_for_association_limiting(options),
+ construct_finder_sql_for_association_limiting(options, reflections),
"#{name} Load IDs For Limited Eager Loading"
).collect { |id| connection.quote(id) }.join(", ")
end
-
- def construct_finder_sql_for_association_limiting(options)
- raise(ArgumentError, "Limited eager loads and conditions on the eager tables is incompatible") if include_eager_conditions?(options)
+
+ def construct_finder_sql_for_association_limiting(options, reflections)
+ #sql = "SELECT DISTINCT #{table_name}.#{primary_key} FROM #{table_name} "
+ sql = "SELECT "
+ sql << "DISTINCT #{table_name}." if include_eager_conditions?(options) || include_eager_order?(options)
+ sql << "#{primary_key} FROM #{table_name} "
+
+ if include_eager_conditions?(options) || include_eager_order?(options)
+ sql << reflections.collect { |reflection| association_join(reflection) }.to_s
+ sql << "#{options[:joins]} " if options[:joins]
+ end
- sql = "SELECT #{primary_key} FROM #{table_name} "
add_conditions!(sql, options[:conditions])
sql << "ORDER BY #{options[:order]} " if options[:order]
add_limit!(sql, options)
@@ -1044,6 +1081,14 @@ module ActiveRecord
condition_table_name != table_name
end
end
+
+ def include_eager_order?(options)
+ order = options[:order]
+ return false unless order
+ order.scan(/(\w+)\.\w+/).flatten.any? do |order_table_name|
+ order_table_name != table_name
+ end
+ end
def using_limitable_reflections?(reflections)
reflections.reject { |r| [ :belongs_to, :has_one ].include?(r.macro) }.length.zero?