Skip to content
This repository has been archived by the owner on May 13, 2020. It is now read-only.

Commit

Permalink
Fix transaction.abort() behaviour for complex objects
Browse files Browse the repository at this point in the history
_py_type information is not lost after transaction abort().
  • Loading branch information
kedder committed Jun 13, 2013
1 parent 86e00db commit 2dcc019
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ CHANGES
0.8.4 (unreleased)
------------------

- Nothing changed yet.
- Fix transaction.abort() behaviour for complex objects. _py_type information
is not lost after transaction abort().


0.8.3 (2013-04-09)
Expand Down
3 changes: 2 additions & 1 deletion src/mongopersist/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
##############################################################################
"""Object Serialization for Mongo/BSON"""
from __future__ import absolute_import
import copy
import copy_reg

import bson.dbref
Expand Down Expand Up @@ -517,7 +518,7 @@ def set_ghost_state(self, obj, doc=None):
if doc is None:
raise ImportError(obj._p_oid)
# Create a copy of the doc, so that we can modify it.
state_doc = doc.copy()
state_doc = copy.deepcopy(doc)
# Remove unwanted attributes.
state_doc.pop('_id')
state_doc.pop('_py_persistent_type', None)
Expand Down
60 changes: 60 additions & 0 deletions src/mongopersist/tests/test_datamanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ def __init__(self, name=None):
class Bar(persistent.Persistent):
_p_mongo_sub_object = True

class FooItem(object):
def __init__(self):
self.bar = 6

class ComplexFoo(persistent.Persistent):
def __init__(self):
self.item = FooItem()
self.name = 'complex'

def doctest_Root():
r"""Root: General Test
Expand Down Expand Up @@ -742,6 +751,48 @@ def doctest_MongoDataManager_abort_conflict_detection():
{u'_id': ObjectId('4e7ddf12e138237403000000'), u'_py_serial': 2,
u'name': u'Eins'}
"""
def doctest_MongoDataManager_abort_subobjects():
r"""MongoDataManager: abort(): Correct restoring of complex objects
Object, that contain subobjects should be restored to the state, exactly
matching one before initial loading.
1. Create a single record and make sure it is stored in db
>>> dm.reset()
>>> foo1_ref = dm.insert(ComplexFoo())
>>> dm.reset()
>>> coll = dm._get_collection_from_object(ComplexFoo())
>>> tuple(coll.find({}))
({u'item': {u'bar': 6,
u'_py_type': u'mongopersist.tests.test_datamanager.FooItem'},
u'_id': ObjectId('51b9987786a4bd2bfa5ad62c'),
u'name': u'complex'},)
2. Modify the item and flush it to database
>>> foo1 = dm.load(foo1_ref)
>>> foo1.name = 'modified'
>>> dm.flush()
>>> tuple(coll.find({}))
({u'item': {u'bar': 6,
u'_py_type': u'mongopersist.tests.test_datamanager.FooItem'},
u'_id': ObjectId('51b9987786a4bd2bfa5ad62c'),
u'name': u'modified'},)
3. Abort the current transaction and expect original state is restored
>>> dm.abort(transaction.get())
>>> tuple(coll.find({}))
({u'item': {u'bar': 6,
u'_py_type': u'mongopersist.tests.test_datamanager.FooItem'},
u'_id': ObjectId('51b9987786a4bd2bfa5ad62c'),
u'name': u'complex'},)
"""

def doctest_MongoDataManager_tpc_begin():
Expand Down Expand Up @@ -793,11 +844,20 @@ def doctest_MongoDataManager_tpc_finish():
>>> dm.reset()
>>> foo3 = dm.load(foo._p_oid)
>>> foo3.name = 'changed'
>>> dm._registered_objects = [foo3.bar, foo3]
>>> dm.tpc_finish(transaction.get())
>>> foo3._p_serial
'\x00\x00\x00\x00\x00\x00\x00\x04'
When there is no change in the objects, serial is not incremented
>>> dm.reset()
>>> foo4 = dm.load(foo._p_oid)
>>> dm._registered_objects = [foo4.bar, foo4]
>>> dm.tpc_finish(transaction.get())
>>> foo3._p_serial
'\x00\x00\x00\x00\x00\x00\x00\x04'
"""

def doctest_MongoDataManager_tpc_abort():
Expand Down

0 comments on commit 2dcc019

Please sign in to comment.