Merge pull request #1005 from touilleMan/master

Raise error if save_condition fails #991
This commit is contained in:
Omer Katz 2015-06-11 22:25:17 +03:00
commit 8909d1d144
4 changed files with 16 additions and 5 deletions

View File

@ -223,3 +223,4 @@ that much better:
* Kiryl Yermakou (https://github.com/rma4ok) * Kiryl Yermakou (https://github.com/rma4ok)
* Matthieu Rigal (https://github.com/MRigal) * Matthieu Rigal (https://github.com/MRigal)
* Charanpal Dhanjal (https://github.com/charanpald) * Charanpal Dhanjal (https://github.com/charanpald)
* Emmanuel Leblond (https://github.com/touilleMan)

View File

@ -20,6 +20,7 @@ Changes in 0.9.X - DEV
- Support for PyMongo 3+ #946 - Support for PyMongo 3+ #946
- Fix for issue where FileField deletion did not free space in GridFS. - Fix for issue where FileField deletion did not free space in GridFS.
- No_dereference() not respected on embedded docs containing reference. #517 - No_dereference() not respected on embedded docs containing reference. #517
- Document save raise an exception if save_condition fails #1005
Changes in 0.9.0 Changes in 0.9.0
================ ================

View File

@ -266,7 +266,8 @@ class Document(BaseDocument):
to cascading saves. Implies ``cascade=True``. to cascading saves. Implies ``cascade=True``.
:param _refs: A list of processed references used in cascading saves :param _refs: A list of processed references used in cascading saves
:param save_condition: only perform save if matching record in db :param save_condition: only perform save if matching record in db
satisfies condition(s) (e.g., version number) satisfies condition(s) (e.g. version number).
Raises :class:`OperationError` if the conditions are not satisfied
.. versionchanged:: 0.5 .. versionchanged:: 0.5
In existing documents it only saves changed fields using In existing documents it only saves changed fields using
@ -284,6 +285,8 @@ class Document(BaseDocument):
.. versionchanged:: 0.8.5 .. versionchanged:: 0.8.5
Optional save_condition that only overwrites existing documents Optional save_condition that only overwrites existing documents
if the condition is satisfied in the current db record. if the condition is satisfied in the current db record.
.. versionchanged:: 0.10
:class:`OperationError` exception raised if save_condition fails.
""" """
signals.pre_save.send(self.__class__, document=self) signals.pre_save.send(self.__class__, document=self)
@ -348,6 +351,9 @@ class Document(BaseDocument):
upsert = save_condition is None upsert = save_condition is None
last_error = collection.update(select_dict, update_query, last_error = collection.update(select_dict, update_query,
upsert=upsert, **write_concern) upsert=upsert, **write_concern)
if not upsert and last_error['nModified'] == 0:
raise OperationError('Race condition preventing'
' document update detected')
created = is_new_object(last_error) created = is_new_object(last_error)
if cascade is None: if cascade is None:

View File

@ -954,11 +954,12 @@ class InstanceTest(unittest.TestCase):
self.assertEqual(w1.save_id, UUID(1)) self.assertEqual(w1.save_id, UUID(1))
self.assertEqual(w1.count, 0) self.assertEqual(w1.count, 0)
# mismatch in save_condition prevents save # mismatch in save_condition prevents save and raise exception
flip(w1) flip(w1)
self.assertTrue(w1.toggle) self.assertTrue(w1.toggle)
self.assertEqual(w1.count, 1) self.assertEqual(w1.count, 1)
w1.save(save_condition={'save_id': UUID(42)}) self.assertRaises(OperationError,
w1.save, save_condition={'save_id': UUID(42)})
w1.reload() w1.reload()
self.assertFalse(w1.toggle) self.assertFalse(w1.toggle)
self.assertEqual(w1.count, 0) self.assertEqual(w1.count, 0)
@ -986,7 +987,8 @@ class InstanceTest(unittest.TestCase):
self.assertEqual(w1.count, 2) self.assertEqual(w1.count, 2)
flip(w2) flip(w2)
flip(w2) flip(w2)
w2.save(save_condition={'save_id': old_id}) self.assertRaises(OperationError,
w2.save, save_condition={'save_id': old_id})
w2.reload() w2.reload()
self.assertFalse(w2.toggle) self.assertFalse(w2.toggle)
self.assertEqual(w2.count, 2) self.assertEqual(w2.count, 2)
@ -998,7 +1000,8 @@ class InstanceTest(unittest.TestCase):
self.assertTrue(w1.toggle) self.assertTrue(w1.toggle)
self.assertEqual(w1.count, 3) self.assertEqual(w1.count, 3)
flip(w1) flip(w1)
w1.save(save_condition={'count__gte': w1.count}) self.assertRaises(OperationError,
w1.save, save_condition={'count__gte': w1.count})
w1.reload() w1.reload()
self.assertTrue(w1.toggle) self.assertTrue(w1.toggle)
self.assertEqual(w1.count, 3) self.assertEqual(w1.count, 3)