API CHANGE no longer save internal array for to_a - means you can't call each or to_a after calling to_a already, doc updates

This commit is contained in:
Mike Dirolf 2009-08-21 14:11:59 -04:00
parent 6a43aaa94f
commit fd3b927771
3 changed files with 24 additions and 49 deletions

View File

@ -35,9 +35,7 @@ module Mongo
@num_to_return = @query.number_to_return || 0
@cache = []
@closed = false
@can_call_to_a = true
@query_run = false
@rows = nil
end
# Return the next object or nil if there are no more. Raises an error
@ -75,53 +73,34 @@ module Mongo
raise OperationFailure, "Count failed: #{response['errmsg']}"
end
# Iterate over each object, yielding it to the given block. At most
# @num_to_return records are returned (or all of them, if
# @num_to_return is 0).
# Iterate over each document in this cursor, yielding it to the given
# block.
#
# If #to_a has already been called then this method uses the array
# that we store internally. In that case, #each can be called multiple
# times because it re-uses that array.
#
# You can call #each after calling #to_a (multiple times even, because
# it will use the internally-stored array), but you can't call #to_a
# after calling #each unless you also called it before calling #each.
# If you try to do that, an error will be raised.
# Iterating over an entire cursor will close it.
def each
if @rows # Already turned into an array
@rows.each { |row| yield row }
else
num_returned = 0
while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
yield next_object()
num_returned += 1
end
@can_call_to_a = false
num_returned = 0
while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
yield next_object()
num_returned += 1
end
end
# Return all of the rows (up to the +num_to_return+ value specified in
# #new) as an array. Calling this multiple times will work fine; it
# always returns the same array.
# Return all of the documents in this cursor as an array of hashes.
#
# Don't use this if you're expecting large amounts of data, of course.
# All of the returned rows are kept in an array stored in this object
# so it can be reused.
# Raises InvalidOperation if this cursor has already been used (including
# any previous calls to this method).
#
# You can call #each after calling #to_a (multiple times even, because
# it will use the internally-stored array), but you can't call #to_a
# after calling #each unless you also called it before calling #each.
# If you try to do that, an error will be raised.
# Use of this method is discouraged - iterating over a cursor is much
# more efficient in most cases.
def to_a
return @rows if @rows
raise "can't call Cursor#to_a after calling Cursor#each" unless @can_call_to_a
@rows = []
raise InvalidOperation, "can't call Cursor#to_a on a used cursor" if @query_run
rows = []
num_returned = 0
while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
@rows << next_object()
rows << next_object()
num_returned += 1
end
@rows
rows
end
# Returns an explain plan record for this cursor.

View File

@ -18,6 +18,9 @@ module Mongo
# Raised when a database operation fails.
class OperationFailure < RuntimeError; end
# Raised when a client attempts to perform an invalid operation.
class InvalidOperation < RuntimeError; end
# Raised when an invalid name is used.
class InvalidName < RuntimeError; end
end

View File

@ -500,25 +500,18 @@ class DBAPITest < Test::Unit::TestCase
cursor = @@coll.find()
rows = cursor.to_a
# Make sure we get back exactly the same array the next time we ask
rows2 = cursor.to_a
assert_same rows, rows2
assert_raise InvalidOperation do
cursor.to_a
end
# Make sure we can still iterate after calling to_a
rows_with_each = cursor.collect{|row| row}
assert_equal rows, rows_with_each
# Make sure we can iterate more than once after calling to_a
cursor.each { |doc| fail "should be no docs in each now" }
end
def test_to_a_after_each
cursor = @@coll.find
cursor.each { |row| row }
begin
assert_raise InvalidOperation do
cursor.to_a
fail "expected \"can't call\" error"
rescue => ex
assert_equal "can't call Cursor#to_a after calling Cursor#each", ex.to_s
end
end