Permalink
Browse files

Add first/last methods to associations/named_scope. [#226 state:resol…

…ved]

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
  • Loading branch information...
ryanb authored and lifo committed May 20, 2008
1 parent ebb642f commit 73c59638549686fccc749ffd3ac53cb533c5fd61
@@ -1,3 +1,5 @@
* Add first/last methods to associations/named_scope. Resolved #226. [Ryan Bates]
*2.1.0 RC1 (May 11th, 2008)*
* Ensure hm:t preloading honours reflection options. Resolves #137. [Frederick Cheung]
@@ -48,6 +48,26 @@ def find(*args)
end
end
# fetch first using SQL if possible
def first(*args)
if fetch_first_or_last_using_find? args
find(:first, *args)
else
load_target unless loaded?
@target.first(*args)
end
end
# fetch last using SQL if possible
def last(*args)
if fetch_first_or_last_using_find? args
find(:last, *args)
else
load_target unless loaded?
@target.last(*args)
end
end
def to_ary
load_target
@target.to_ary
@@ -330,7 +350,10 @@ def ensure_owner_is_not_new
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
end
end
def fetch_first_or_last_using_find?(args)
args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || !@target.blank? || args.first.kind_of?(Integer))
end
end
end
end
@@ -102,7 +102,13 @@ def named_scope(name, options = {}, &block)
class Scope
attr_reader :proxy_scope, :proxy_options
[].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate)/ }
[].methods.each do |m|
unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last)/
delegate m, :to => :proxy_found
end
end
delegate :scopes, :with_scope, :to => :proxy_scope
def initialize(proxy_scope, options, &block)
@@ -115,6 +121,22 @@ def reload
load_found; self
end
def first(*args)
if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
proxy_found.first(*args)
else
find(:first, *args)
end
end
def last(*args)
if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
proxy_found.last(*args)
else
find(:last, *args)
end
end
protected
def proxy_found
@found || load_found
@@ -401,6 +401,8 @@ def test_find_in_association
def test_include_uses_array_include_after_loaded
project = projects(:active_record)
project.developers.class # force load target
developer = project.developers.first
assert_no_queries do
@@ -818,6 +818,8 @@ def test_has_many_through_respects_hash_conditions
def test_include_uses_array_include_after_loaded
firm = companies(:first_firm)
firm.clients.class # force load target
client = firm.clients.first
assert_no_queries do
@@ -857,4 +859,68 @@ def test_include_returns_false_for_non_matching_record_to_verify_scoping
assert ! firm.clients.include?(client)
end
def test_calling_first_or_last_on_association_should_not_load_association
firm = companies(:first_firm)
firm.clients.first
firm.clients.last
assert !firm.clients.loaded?
end
def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query
firm = companies(:first_firm)
firm.clients.class # force load target
assert firm.clients.loaded?
assert_no_queries do
firm.clients.first
assert_equal 2, firm.clients.first(2).size
firm.clients.last
assert_equal 2, firm.clients.last(2).size
end
end
def test_calling_first_or_last_on_existing_record_with_build_should_load_association
firm = companies(:first_firm)
firm.clients.build(:name => 'Foo')
assert !firm.clients.loaded?
assert_queries 1 do
firm.clients.first
firm.clients.last
end
assert firm.clients.loaded?
end
def test_calling_first_or_last_on_new_record_should_not_run_queries
firm = Firm.new
assert_no_queries do
firm.clients.first
firm.clients.last
end
end
def test_calling_first_or_last_with_find_options_on_loaded_association_should_fetch_with_query
firm = companies(:first_firm)
firm.clients.class # force load target
assert_queries 2 do
assert firm.clients.loaded?
firm.clients.first(:order => 'name')
firm.clients.last(:order => 'name')
end
end
def test_calling_first_or_last_with_integer_on_association_should_load_association
firm = companies(:first_firm)
assert_queries 1 do
firm.clients.first(2)
firm.clients.last(2)
end
assert firm.clients.loaded?
end
end
@@ -664,6 +664,8 @@ def test_belongs_to_shared_parent
def test_has_many_through_include_uses_array_include_after_loaded
david = authors(:david)
david.categories.class # force load target
category = david.categories.first
assert_no_queries do
@@ -99,12 +99,12 @@ def test_proxy_accessors
david = authors(:david)
assert_equal david, david.posts.proxy_owner
assert_equal david.class.reflect_on_association(:posts), david.posts.proxy_reflection
david.posts.first # force load target
david.posts.class # force load target
assert_equal david.posts, david.posts.proxy_target
assert_equal david, david.posts_with_extension.testing_proxy_owner
assert_equal david.class.reflect_on_association(:posts_with_extension), david.posts_with_extension.testing_proxy_reflection
david.posts_with_extension.first # force load target
david.posts_with_extension.class # force load target
assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target
end
@@ -118,4 +118,32 @@ def test_proxy_options
assert_equal expected_proxy_options, Topic.approved.proxy_options
end
def test_first_and_last_should_support_find_options
assert_equal Topic.base.first(:order => 'title'), Topic.base.find(:first, :order => 'title')
assert_equal Topic.base.last(:order => 'title'), Topic.base.find(:last, :order => 'title')
end
def test_first_and_last_should_allow_integers_for_limit
assert_equal Topic.base.first(2), Topic.base.to_a.first(2)
assert_equal Topic.base.last(2), Topic.base.to_a.last(2)
end
def test_first_and_last_should_not_use_query_when_results_are_loaded
topics = Topic.base
topics.reload # force load
assert_no_queries do
topics.first
topics.last
end
end
def test_first_and_last_find_options_should_use_query_when_results_are_loaded
topics = Topic.base
topics.reload # force load
assert_queries(2) do
topics.first(:order => 'title')
topics.last(:order => 'title')
end
end
end

0 comments on commit 73c5963

Please sign in to comment.