Skip to content

Commit 25c2982

Browse files
committed
change session save api (foundation) to detect before_save changes, and don't break on inserts. tests provided
1 parent 727a3b8 commit 25c2982

4 files changed

Lines changed: 74 additions & 16 deletions

File tree

ming/odm/mapper.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from copy import copy, deepcopy
44

55
from ming.base import Object, NoDefault
6-
from ming.utils import wordwrap, doc_to_set
6+
from ming.utils import wordwrap
77

88
from .base import ObjectState, state, _with_hooks
99
from .property import FieldProperty
@@ -84,15 +84,8 @@ def insert(self, obj, state, session, **kwargs):
8484

8585
@_with_hooks('update')
8686
def update(self, obj, state, session, **kwargs):
87-
fields = state.options.get('fields', None)
88-
if fields is None:
89-
# here we do a symmetric difference to see what fields did change
90-
fields = tuple(set((k for k, v in
91-
doc_to_set(state.original_document)
92-
^ doc_to_set(state.document))))
93-
9487
doc = self.collection(state.document, skip_from_bson=True)
95-
ret = session.impl.save(doc, *fields, validate=False)
88+
ret = session.impl.save(doc, validate=False, state=state)
9689
state.status = state.clean
9790
return ret
9891

ming/session.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import six
1010

1111
from .base import Cursor, Object
12-
from .utils import fixup_index, fix_write_concern
12+
from .utils import fixup_index, fix_write_concern, doc_to_set
1313
from . import exc
1414

1515
log = logging.getLogger(__name__)
@@ -139,7 +139,8 @@ def find_and_modify(self, cls, query=None, sort=None, new=False, **kw):
139139

140140
def _prep_save(self, doc, validate):
141141
hook = doc.m.before_save
142-
if hook: hook(doc)
142+
if hook:
143+
hook(doc)
143144
if validate:
144145
if doc.m.schema is None:
145146
data = dict(doc)
@@ -151,9 +152,15 @@ def _prep_save(self, doc, validate):
151152
return data
152153

153154
@annotate_doc_failure
154-
def save(self, doc, *args, **kwargs):
155+
def save(self, doc, state=None, **kwargs):
156+
# args was meant to be the list of changed fields
157+
# but actually we ended up checking the differences here
155158
data = self._prep_save(doc, kwargs.pop('validate', True))
156-
if args:
159+
if state is not None and state.original_document:
160+
if state is not None:
161+
args = tuple(set((k for k, v in
162+
doc_to_set(state.original_document)
163+
^ doc_to_set(data))))
157164
values = dict((arg, data[arg]) for arg in args)
158165
result = self._impl(doc).update(
159166
dict(_id=doc._id), {'$set': values}, **fix_write_concern(kwargs))

ming/tests/odm/test_declarative.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import sys
22
from collections import defaultdict
33
from unittest import TestCase, SkipTest
4+
from unittest.mock import MagicMock
45

56
from ming import schema as S
67
from ming import create_datastore
@@ -811,3 +812,60 @@ def test_hook_base(self):
811812
[
812813
{'_id': doc._id, 'a': doc.a}
813814
])
815+
816+
817+
class TestReplacingSession(TestCase):
818+
819+
def setUp(self):
820+
Mapper._mapper_by_classname.clear()
821+
self.datastore = create_datastore('mim:///test_db')
822+
self.session = ODMSession(bind=self.datastore)
823+
class Basic(MappedClass):
824+
class __mongometa__:
825+
name = 'hook'
826+
session = self.session
827+
_id = FieldProperty(S.ObjectId)
828+
a = FieldProperty(int)
829+
Mapper.compile_all()
830+
self.Basic = Basic
831+
self.session.remove(self.Basic)
832+
833+
def test_hook_base(self):
834+
assert id(self.Basic.query.session) == id(self.session)
835+
session2 = MagicMock()
836+
new_session = ODMSession(bind=session2)
837+
Mapper.replace_session(new_session)
838+
assert id(self.Basic.query.session) == id(new_session)
839+
assert id(self.session) != id(new_session)
840+
841+
class TestBeforeSave(TestCase):
842+
843+
def setUp(self):
844+
Mapper._mapper_by_classname.clear()
845+
self.datastore = create_datastore('mim:///test_db')
846+
self.session = ODMSession(bind=self.datastore)
847+
class Basic(MappedClass):
848+
class __mongometa__:
849+
name = 'hook'
850+
session = self.session
851+
def before_save(instance):
852+
instance.a = 9
853+
854+
_id = FieldProperty(S.ObjectId)
855+
a = FieldProperty(int)
856+
Mapper.compile_all()
857+
self.Basic = Basic
858+
self.session.remove(self.Basic)
859+
860+
def test_hook_base(self):
861+
doc = self.Basic()
862+
doc.a = 5
863+
self.session.flush() # first insert
864+
self.session.close()
865+
doc = self.Basic.query.get(doc._id)
866+
assert doc.a == 9, doc.a
867+
doc.a = 6
868+
self.session.flush() # then save
869+
self.session.close()
870+
doc = self.Basic.query.get(doc._id)
871+
assert doc.a == 9, doc.a

ming/tests/test_session.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ def test_base_session(self):
8181
doc = self.TestDocNoSchema({'_id':5, 'a':5})
8282
sess.save(doc)
8383
impl.save.assert_called_with(dict(_id=5, a=5))
84-
doc = self.TestDocNoSchema({'_id':5, 'a':5})
85-
sess.save(doc, 'a')
86-
impl.update.assert_called_with(dict(_id=5), {'$set':dict(a=5)})
84+
# doc = self.TestDocNoSchema({'_id':5, 'a':5})
85+
# sess.save(doc, 'a')
86+
# impl.update.assert_called_with(dict(_id=5), {'$set':dict(a=5)})
8787
doc = self.TestDocNoSchema({'_id':5, 'a':5})
8888
impl.insert.return_value = bson.ObjectId()
8989
sess.insert(doc)

0 commit comments

Comments
 (0)