PYTHON-821 - Implement insert_one.

This commit is contained in:
Bernie Hackett 2015-02-11 12:48:50 -08:00
parent 7416e6595c
commit df4e5269b3
4 changed files with 91 additions and 9 deletions

View File

@ -16,6 +16,9 @@
.. autodata:: pymongo.cursor.TAILABLE_AWAIT
.. autodata:: pymongo.cursor.EXHAUST
.. autoclass:: pymongo.collection.InsertOneResult
:members:
.. autoclass:: pymongo.collection.ReturnDocument
.. autoattribute:: Before
@ -39,6 +42,7 @@
.. autoattribute:: read_preference
.. autoattribute:: write_concern
.. automethod:: with_options
.. automethod:: insert_one
.. automethod:: insert(doc_or_docs[, manipulate=True[, check_keys=True[, continue_on_error=False[, **kwargs]]]])
.. automethod:: save(to_save[, manipulate=True[, check_keys=True[, **kwargs]]])
.. automethod:: update(spec, document[, upsert=False[, manipulate=False[, multi=False[, check_keys=True[, **kwargs]]]]])

View File

@ -231,7 +231,7 @@ class BulkWriteResult(object):
@property
def acknowledged(self):
"""Was this bulk write operation acknowledged?"""
"""Is this the result of an acknowledged bulk write operation?"""
return self.__acknowledged
@property

View File

@ -39,6 +39,7 @@ from pymongo.errors import ConfigurationError, InvalidName, OperationFailure
from pymongo.helpers import _check_write_command_response, _command
from pymongo.message import _INSERT, _UPDATE, _DELETE
from pymongo.read_preferences import ReadPreference
from pymongo.write_concern import WriteConcern
try:
@ -50,6 +51,26 @@ except ImportError:
_NO_OBJ_ERROR = "No matching object found"
class InsertOneResult(object):
"""The return type for :meth:`Collection.insert_one`."""
__slots__ = ("__inserted_id", "__acknowledged")
def __init__(self, inserted_id, acknowledged):
self.__inserted_id = inserted_id
self.__acknowledged = acknowledged
@property
def inserted_id(self):
"""The inserted document's _id."""
return self.__inserted_id
@property
def acknowledged(self):
"""Is this the result of an acknowledged write operation?"""
return self.__acknowledged
class ReturnDocument(object):
"""An enum used with :meth:`Collection.find_one_and_replace` and
:meth:`Collection.find_one_and_update`.
@ -483,8 +504,34 @@ class Collection(common.BaseObject):
.. mongodoc:: insert
"""
write_concern = None
if kwargs:
write_concern = WriteConcern(**kwargs)
return self.__insert(doc_or_docs, not continue_on_error,
check_keys, manipulate, write_concern)
def insert_one(self, document):
"""Insert a single document.
:Parameters:
- `document`: The document to insert. Must be a mutable mapping
type. If the document does not have an _id field one will be
added automatically.
:Returns:
- An instance of :class:`InsertOneResult`.
"""
if not isinstance(document, collections.MutableMapping):
raise TypeError("document must be a mutable mapping type")
if "_id" not in document:
document["_id"] = ObjectId()
return InsertOneResult(self.__insert(document),
self.write_concern.acknowledged)
def __insert(self, docs, ordered=True,
check_keys=True, manipulate=False, write_concern=None):
"""Internal insert helper."""
client = self.database.connection
docs = doc_or_docs
return_one = False
if isinstance(docs, collections.MutableMapping):
return_one = True
@ -512,13 +559,13 @@ class Collection(common.BaseObject):
ids.append(doc.get('_id'))
yield doc
concern = kwargs or self.write_concern.document
concern = (write_concern or self.write_concern).document
safe = concern.get("w") != 0
if client._writable_max_wire_version() > 1 and safe:
# Insert command
command = SON([('insert', self.name),
('ordered', not continue_on_error)])
('ordered', ordered)])
if concern:
command['writeConcern'] = concern
@ -530,9 +577,8 @@ class Collection(common.BaseObject):
else:
# Legacy batched OP_INSERT
message._do_batched_insert(self.__full_name, gen(), check_keys,
safe, concern, continue_on_error,
safe, concern, not ordered,
self.codec_options, client)
if return_one:
return ids[0]
else:

View File

@ -35,10 +35,11 @@ from bson.son import SON
from pymongo import (ASCENDING, DESCENDING, GEO2D,
GEOHAYSTACK, GEOSPHERE, HASHED, TEXT)
from pymongo import MongoClient
from pymongo.collection import Collection, ReturnDocument
from pymongo.collection import Collection, ReturnDocument, InsertOneResult
from pymongo.command_cursor import CommandCursor
from pymongo.cursor import EXHAUST
from pymongo.errors import (DocumentTooLarge,
from pymongo.errors import (ConfigurationError,
DocumentTooLarge,
DuplicateKeyError,
InvalidDocument,
InvalidName,
@ -605,6 +606,37 @@ class TestCollection(IntegrationTest):
qcheck.check_unittest(self, remove_insert_find_one,
qcheck.gen_mongo_dict(3))
def test_insert_one(self):
db = self.db
db.test.drop()
document = {"_id": 1000}
result = db.test.insert_one(document)
self.assertTrue(isinstance(result, InsertOneResult))
self.assertTrue(isinstance(result.inserted_id, int))
self.assertEqual(document["_id"], result.inserted_id)
self.assertTrue(result.acknowledged)
self.assertIsNotNone(db.test.find_one({"_id": document["_id"]}))
self.assertEqual(1, db.test.count())
document = {"foo": "bar"}
result = db.test.insert_one(document)
self.assertTrue(isinstance(result, InsertOneResult))
self.assertTrue(isinstance(result.inserted_id, ObjectId))
self.assertEqual(document["_id"], result.inserted_id)
self.assertTrue(result.acknowledged)
self.assertIsNotNone(db.test.find_one({"_id": document["_id"]}))
db = db.connection.get_database(db.name,
write_concern=WriteConcern(w=0))
result = db.test.insert_one(document)
self.assertTrue(isinstance(result, InsertOneResult))
self.assertTrue(isinstance(result.inserted_id, ObjectId))
self.assertEqual(document["_id"], result.inserted_id)
self.assertFalse(result.acknowledged)
# The insert failed duplicate key...
self.assertEqual(2, db.test.count())
def test_generator_insert(self):
db = self.db
db.test.remove({})
@ -1231,7 +1263,7 @@ class TestCollection(IntegrationTest):
wtimeout_err(coll.remove, {"x": 1}, w=w, wtimeout=1)
# can't use fsync and j options together
self.assertRaises(OperationFailure, self.db.test.insert,
self.assertRaises(ConfigurationError, self.db.test.insert,
{"_id": 1}, j=True, fsync=True)
def test_manual_last_error(self):