API CHANGE Add :safe option for Collection#insert and Collection#save
The API change is minor: Collection#insert({...}, {...}, {...}) no longer works for inserting multiple documents - instead you must pass an explicit Array: Collection#insert([{...}, {...}, {...}])
This commit is contained in:
parent
7e0a1b9721
commit
6cb8c9f49b
|
@ -97,29 +97,50 @@ module XGen
|
||||||
cursor.next_object # don't need to explicitly close b/c of limit
|
cursor.next_object # don't need to explicitly close b/c of limit
|
||||||
end
|
end
|
||||||
|
|
||||||
# Save a document in this collection
|
# Save a document in this collection.
|
||||||
#
|
#
|
||||||
# If +to_save+ already has an '_id' then an update (upsert) operation
|
# If +to_save+ already has an '_id' then an update (upsert) operation
|
||||||
# is performed and any existing document with that _id is overwritten.
|
# is performed and any existing document with that _id is overwritten.
|
||||||
# Otherwise an insert operation is performed.
|
# Otherwise an insert operation is performed. Returns the _id of the
|
||||||
|
# saved document.
|
||||||
#
|
#
|
||||||
# :to_save :: the document (a hash) to be saved
|
# :to_save :: the document (a hash) to be saved
|
||||||
def save(to_save)
|
#
|
||||||
|
# Options:
|
||||||
|
# :safe :: if true, check that the save succeeded. OperationFailure
|
||||||
|
# will be raised on an error. Checking for safety requires an extra
|
||||||
|
# round-trip to the database
|
||||||
|
def save(to_save, options={})
|
||||||
if id = to_save[:_id] || to_save['_id']
|
if id = to_save[:_id] || to_save['_id']
|
||||||
update({:_id => id}, to_save, :upsert => true)
|
update({:_id => id}, to_save, :upsert => true, :safe => options.delete(:safe))
|
||||||
id
|
id
|
||||||
else
|
else
|
||||||
insert(to_save)
|
insert(to_save, :safe => options.delete(:safe))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Insert +objects+, which are hashes. "<<" is aliased to this method.
|
# Insert a document(s) into this collection.
|
||||||
# Returns either the single inserted object or a new array containing
|
#
|
||||||
# +objects+. The object(s) may have been modified by the database's PK
|
# "<<" is aliased to this method. Returns the _id of the inserted
|
||||||
# factory, if it has one.
|
# document or a list of _ids of the inserted documents. The object(s)
|
||||||
def insert(*objects)
|
# may have been modified by the database's PK factory, if it has one.
|
||||||
objects = objects.first if objects.size == 1 && objects.first.is_a?(Array)
|
#
|
||||||
res = @db.insert_into_db(@name, objects)
|
# :doc_or_docs :: a document (as a hash) or Array of documents to be
|
||||||
|
# inserted
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# :safe :: if true, check that the insert succeeded. OperationFailure
|
||||||
|
# will be raised on an error. Checking for safety requires an extra
|
||||||
|
# round-trip to the database
|
||||||
|
def insert(doc_or_docs, options={})
|
||||||
|
doc_or_docs = [doc_or_docs] if !doc_or_docs.is_a?(Array)
|
||||||
|
res = @db.insert_into_db(@name, doc_or_docs)
|
||||||
|
if options.delete(:safe)
|
||||||
|
error = @db.error
|
||||||
|
if error
|
||||||
|
raise OperationFailure, error
|
||||||
|
end
|
||||||
|
end
|
||||||
res.size > 1 ? res : res.first
|
res.size > 1 ? res : res.first
|
||||||
end
|
end
|
||||||
alias_method :<<, :insert
|
alias_method :<<, :insert
|
||||||
|
|
|
@ -491,8 +491,8 @@ module XGen
|
||||||
end
|
end
|
||||||
|
|
||||||
# Insert +objects+ into +collection_name+. Normally called by
|
# Insert +objects+ into +collection_name+. Normally called by
|
||||||
# Collection#insert. Returns a new array containing +objects+,
|
# Collection#insert. Returns a new array containing the _ids
|
||||||
# possibly modified by @pk_factory.
|
# of the inserted documents.
|
||||||
def insert_into_db(collection_name, objects)
|
def insert_into_db(collection_name, objects)
|
||||||
_synchronize {
|
_synchronize {
|
||||||
if @pk_factory
|
if @pk_factory
|
||||||
|
|
|
@ -31,6 +31,18 @@ class TestCollection < Test::Unit::TestCase
|
||||||
@@test.drop()
|
@@test.drop()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_safe_insert
|
||||||
|
a = {"hello" => "world"}
|
||||||
|
@@test.insert(a)
|
||||||
|
a = @@test.find_first() # TODO we need this because insert doesn't add _id
|
||||||
|
@@test.insert(a)
|
||||||
|
assert @@db.error.include? "E11000"
|
||||||
|
|
||||||
|
assert_raise OperationFailure do
|
||||||
|
@@test.insert(a, :safe => true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_update
|
def test_update
|
||||||
id1 = @@test.save("x" => 5)
|
id1 = @@test.save("x" => 5)
|
||||||
@@test.update({}, {"$inc" => {"x" => 1}})
|
@@test.update({}, {"$inc" => {"x" => 1}})
|
||||||
|
@ -62,5 +74,17 @@ class TestCollection < Test::Unit::TestCase
|
||||||
@@test.update({}, {"$inc" => {"x" => 1}}, :safe => true)
|
@@test.update({}, {"$inc" => {"x" => 1}}, :safe => true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_safe_save
|
||||||
|
@@test.create_index("hello", true)
|
||||||
|
|
||||||
|
@@test.save("hello" => "world")
|
||||||
|
@@test.save("hello" => "world")
|
||||||
|
assert @@db.error.include? "E11000"
|
||||||
|
|
||||||
|
assert_raise OperationFailure do
|
||||||
|
@@test.save({"hello" => "world"}, :safe => true)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ class DBAPITest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_insert_multiple
|
def test_insert_multiple
|
||||||
ids = @@coll.insert({'a' => 2}, {'b' => 3})
|
ids = @@coll.insert([{'a' => 2}, {'b' => 3}])
|
||||||
|
|
||||||
ids.each do |i|
|
ids.each do |i|
|
||||||
assert_kind_of ObjectID, i
|
assert_kind_of ObjectID, i
|
||||||
|
|
Loading…
Reference in New Issue