Added transformer concept.
Can be passed to find/find_one, which in turn is passed to cursor. It is an optional block that makes it easier to turn documents that are returned into hashes. cursor = collection.find({...}, :transformer => Proc.new { |doc| User.load(doc) }) cursor.next # returns instance of User instead of ordered hash This will allow MongoMapper, ToyStore and other object mappers to take better advantage of Cursors. No more calling to_a and mapping to instances.
This commit is contained in:
parent
5cdae46b56
commit
53ad43fedc
|
@ -157,6 +157,8 @@ module Mongo
|
|||
# the normal cursor timeout behavior of the mongod process. When +false+, the returned cursor will never timeout. Note
|
||||
# that disabling timeout will only work when #find is invoked with a block. This is to prevent any inadvertant failure to
|
||||
# close the cursor, as the cursor is explicitly closed when block code finishes.
|
||||
# @options opts [Block] :transformer optional block that can be handed to cursor for tranforming returned documents. Most valuable
|
||||
# use is for converting hashes to instances of a class.
|
||||
#
|
||||
# @raise [ArgumentError]
|
||||
# if timeout is set to false and find is not invoked in a block
|
||||
|
@ -175,6 +177,7 @@ module Mongo
|
|||
snapshot = opts.delete(:snapshot)
|
||||
batch_size = opts.delete(:batch_size)
|
||||
timeout = (opts.delete(:timeout) == false) ? false : true
|
||||
transformer = opts.delete(:transformer)
|
||||
|
||||
if timeout == false && !block_given?
|
||||
raise ArgumentError, "Collection#find must be invoked with a block when timeout is disabled."
|
||||
|
@ -188,8 +191,18 @@ module Mongo
|
|||
|
||||
raise RuntimeError, "Unknown options [#{opts.inspect}]" unless opts.empty?
|
||||
|
||||
cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
|
||||
:order => sort, :hint => hint, :snapshot => snapshot, :timeout => timeout, :batch_size => batch_size)
|
||||
cursor = Cursor.new(self, {
|
||||
:selector => selector,
|
||||
:fields => fields,
|
||||
:skip => skip,
|
||||
:limit => limit,
|
||||
:order => sort,
|
||||
:hint => hint,
|
||||
:snapshot => snapshot,
|
||||
:timeout => timeout,
|
||||
:batch_size => batch_size,
|
||||
:transformer => transformer,
|
||||
})
|
||||
|
||||
if block_given?
|
||||
yield cursor
|
||||
|
|
|
@ -23,7 +23,7 @@ module Mongo
|
|||
|
||||
attr_reader :collection, :selector, :fields,
|
||||
:order, :hint, :snapshot, :timeout,
|
||||
:full_collection_name
|
||||
:full_collection_name, :transformer
|
||||
|
||||
# Create a new cursor.
|
||||
#
|
||||
|
@ -52,6 +52,7 @@ module Mongo
|
|||
@tailable = opts[:tailable] || false
|
||||
@closed = false
|
||||
@query_run = false
|
||||
@transformer = opts[:transformer]
|
||||
batch_size(opts[:batch_size] || 0)
|
||||
|
||||
@full_collection_name = "#{@collection.db.name}.#{@collection.name}"
|
||||
|
@ -86,7 +87,11 @@ module Mongo
|
|||
raise OperationFailure, err
|
||||
end
|
||||
|
||||
doc
|
||||
if @transformer.nil?
|
||||
doc
|
||||
else
|
||||
@transformer.call(doc) if doc
|
||||
end
|
||||
end
|
||||
alias :next :next_document
|
||||
|
||||
|
|
|
@ -592,6 +592,20 @@ class TestCollection < Test::Unit::TestCase
|
|||
assert_equal 1, x
|
||||
end
|
||||
|
||||
def test_find_with_transformer
|
||||
klass = Struct.new(:id, :a)
|
||||
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
||||
cursor = @@test.find({}, :transformer => transformer)
|
||||
assert_equal(transformer, cursor.transformer)
|
||||
end
|
||||
|
||||
def test_find_one_with_transformer
|
||||
klass = Struct.new(:id, :a)
|
||||
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
||||
id = @@test.insert('a' => 1)
|
||||
doc = @@test.find_one(id, :transformer => transformer)
|
||||
assert_instance_of(klass, doc)
|
||||
end
|
||||
|
||||
def test_ensure_index
|
||||
@@test.drop_indexes
|
||||
|
|
|
@ -454,4 +454,30 @@ class CursorTest < Test::Unit::TestCase
|
|||
assert_equal 100, cursor.map {|doc| doc }.length
|
||||
end
|
||||
|
||||
def test_transformer
|
||||
transformer = Proc.new { |doc| doc }
|
||||
cursor = Cursor.new(@@coll, :transformer => transformer)
|
||||
assert_equal(transformer, cursor.transformer)
|
||||
end
|
||||
|
||||
def test_instance_transformation_with_next
|
||||
klass = Struct.new(:id, :a)
|
||||
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
||||
cursor = Cursor.new(@@coll, :transformer => transformer)
|
||||
instance = cursor.next
|
||||
|
||||
assert_instance_of(klass, instance)
|
||||
assert_instance_of(BSON::ObjectId, instance.id)
|
||||
assert_equal(1, instance.a)
|
||||
end
|
||||
|
||||
def test_instance_transformation_with_each
|
||||
klass = Struct.new(:id, :a)
|
||||
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
||||
cursor = Cursor.new(@@coll, :transformer => transformer)
|
||||
|
||||
cursor.each do |instance|
|
||||
assert_instance_of(klass, instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue