Skip to content
Browse files

Cache the loaded relations

  • Loading branch information...
1 parent 9d3d60c commit 3c5a7dcaf55f427f3a48e206feb06410d011ca4f @lifo lifo committed Dec 26, 2009
Showing with 75 additions and 33 deletions.
  1. +43 −32 activerecord/lib/active_record/relation.rb
  2. +32 −1 activerecord/test/cases/relations_test.rb
View
75 activerecord/lib/active_record/relation.rb
@@ -9,6 +9,7 @@ def initialize(klass, relation, readonly = false, preload = [], eager_load = [])
@readonly = readonly
@associations_to_preload = preload
@eager_load_associations = eager_load
+ @loaded = false
end
def preload(*associations)
@@ -23,38 +24,6 @@ def readonly
create_new_relation(@relation, true)
end
- def to_a
- records = if @eager_load_associations.any?
- catch :invalid_query do
- return @klass.send(:find_with_associations, {
- :select => @relation.send(:select_clauses).join(', '),
- :joins => @relation.joins(relation),
- :group => @relation.send(:group_clauses).join(', '),
- :order => @relation.send(:order_clauses).join(', '),
- :conditions => @relation.send(:where_clauses).join("\n\tAND "),
- :limit => @relation.taken,
- :offset => @relation.skipped
- },
- ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, @eager_load_associations, nil))
- end
- []
- else
- @klass.find_by_sql(@relation.to_sql)
- end
-
- @associations_to_preload.each {|associations| @klass.send(:preload_associations, records, associations) }
- records.each { |record| record.readonly! } if @readonly
-
- records
- end
-
- alias all to_a
-
- def first
- @relation = @relation.take(1)
- to_a.first
- end
-
def select(selects)
create_new_relation(@relation.project(selects))
end
@@ -109,6 +78,48 @@ def respond_to?(method)
@relation.respond_to?(method) || Array.method_defined?(method) || super
end
+ def to_a
+ return @records if loaded?
+
+ @records = if @eager_load_associations.any?
+ catch :invalid_query do
+ return @klass.send(:find_with_associations, {
+ :select => @relation.send(:select_clauses).join(', '),
+ :joins => @relation.joins(relation),
+ :group => @relation.send(:group_clauses).join(', '),
+ :order => @relation.send(:order_clauses).join(', '),
+ :conditions => @relation.send(:where_clauses).join("\n\tAND "),
+ :limit => @relation.taken,
+ :offset => @relation.skipped
+ },
+ ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, @eager_load_associations, nil))
+ end
+ []
+ else
+ @klass.find_by_sql(@relation.to_sql)
+ end
+
+ @associations_to_preload.each {|associations| @klass.send(:preload_associations, @records, associations) }
+ @records.each { |record| record.readonly! } if @readonly
+
+ @loaded = true
+ @records
+ end
+
+ alias all to_a
+
+ def first
+ if loaded?
+ @records.first
+ else
+ @first ||= limit(1).to_a[0]
+ end
+ end
+
+ def loaded?
+ @loaded
+ end
+
private
def method_missing(method, *args, &block)
View
33 activerecord/test/cases/relations_test.rb
@@ -24,6 +24,37 @@ def test_scoped_all
assert_no_queries { assert_equal 4, topics.size }
end
+ def test_loaded_all
+ topics = Topic.scoped
+
+ assert_queries(1) do
+ 2.times { assert_equal 4, topics.all.size }
+ end
+
+ assert topics.loaded?
+ end
+
+ def test_scoped_first
+ topics = Topic.scoped
+
+ assert_queries(1) do
+ 2.times { assert_equal "The First Topic", topics.first.title }
+ end
+
+ assert ! topics.loaded?
+ end
+
+ def test_loaded_first
+ topics = Topic.scoped
+
+ assert_queries(1) do
+ topics.all # force load
+ 2.times { assert_equal "The First Topic", topics.first.title }
+ end
+
+ assert topics.loaded?
+ end
+
def test_finding_with_conditions
assert_equal ["David"], Author.where(:name => 'David').map(&:name)
assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name)
@@ -141,7 +172,7 @@ def test_find_with_included_associations
end
end
- def test_default_scope_with_conditions_string
+ def test_default_scope_with_conditions_string
assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.to_a.map(&:id).sort
assert_equal nil, DeveloperCalledDavid.create!.name
end

0 comments on commit 3c5a7dc

Please sign in to comment.
Something went wrong with that request. Please try again.