[z3-checkins] r6871 - in z3/sqlos/trunk: event transaction
dreamcatcher at codespeak.net
dreamcatcher at codespeak.net
Fri Oct 8 16:56:48 MEST 2004
Author: dreamcatcher
Date: Fri Oct 8 16:56:47 2004
New Revision: 6871
Modified:
z3/sqlos/trunk/event/configure.zcml
z3/sqlos/trunk/event/subscriber.py
z3/sqlos/trunk/transaction/__init__.py
Log:
- Expire the object and re-sync from database when:
- The transaction is commited
- The transaction is aborted
- Setup the events on the test so that we can test they have been called
- Use an event from commit() and abort() instead of calling the methods directly
- Create an event for expiring an sqlobject and register a subscriber for it
Modified: z3/sqlos/trunk/event/configure.zcml
==============================================================================
--- z3/sqlos/trunk/event/configure.zcml (original)
+++ z3/sqlos/trunk/event/configure.zcml Fri Oct 8 16:56:47 2004
@@ -10,4 +10,9 @@
for="zope.app.event.interfaces.IObjectCreatedEvent"
/>
+ <subscriber
+ factory=".subscriber.sqlobjectExpiredSubscriber"
+ for="sqlos.event.interfaces.IObjectExpiredEvent"
+ />
+
</configure>
\ No newline at end of file
Modified: z3/sqlos/trunk/event/subscriber.py
==============================================================================
--- z3/sqlos/trunk/event/subscriber.py (original)
+++ z3/sqlos/trunk/event/subscriber.py Fri Oct 8 16:56:47 2004
@@ -11,6 +11,7 @@
"""
from sqlos.interfaces import ISQLObject
+from sqlos.event.interfaces import expired
def sqlobjectModifiedSubscriber(event):
obj = event.object
@@ -22,8 +23,20 @@
# lose the new values.
obj.syncUpdate()
+ expired(obj)
+
+sqlobjectCreatedSubscriber = sqlobjectModifiedSubscriber
+
+def sqlobjectExpiredSubscriber(event):
+ obj = event.object
+
+ if not ISQLObject.providedBy(obj): return
+
from sqlos.connection import connCache
for connection in connCache.values():
connection.cache.expire(obj.id, obj.__class__)
-sqlobjectCreatedSubscriber = sqlobjectModifiedSubscriber
+ # Expire object values and re-sync from database. The transaction
+ # has either been aborted or committed.
+ obj.expire()
+ obj.sync()
Modified: z3/sqlos/trunk/transaction/__init__.py
==============================================================================
--- z3/sqlos/trunk/transaction/__init__.py (original)
+++ z3/sqlos/trunk/transaction/__init__.py Fri Oct 8 16:56:47 2004
@@ -18,23 +18,56 @@
from transaction.interfaces import IDataManager, IRollback
from transaction.util import NoSavepointSupportRollback
from zope.interface import implements
+from zope.app.event.objectevent import modified
from sqlos.interfaces import ISQLObject
+from sqlos.event.interfaces import expired
class SQLObjectTransactionManager:
"""
- This is a very simple Data Manager that just
- takes registrations of ``ISQLObject`` objects and
- calls their ``sync()`` method when needed.
+ This is a very simple Data Manager that just takes registrations
+ of ``ISQLObject`` objects and calls their ``sync()`` method when
+ needed.
- Let's see how it works:
+ In addition to that, when the transaction is aborted, all modified
+ objects will be expired.
+
+ Let's see how it works.
+
+ First of all, setup the environment:
+
+ >>> from zope.app.tests.placelesssetup import setUp, tearDown
+ >>> setUp()
+
+ First, register the subscribers:
+
+ >>> from zope.app.tests import ztapi
+ >>> from zope.app.event.interfaces import IObjectModifiedEvent
+ >>> from zope.app.event.interfaces import IObjectCreatedEvent
+ >>> from sqlos.event.interfaces import IObjectExpiredEvent
+ >>> from sqlos.event.subscriber import sqlobjectModifiedSubscriber
+ >>> from sqlos.event.subscriber import sqlobjectCreatedSubscriber
+ >>> from sqlos.event.subscriber import sqlobjectExpiredSubscriber
+
+ >>> ztapi.handle([IObjectExpiredEvent], sqlobjectExpiredSubscriber)
+ >>> ztapi.handle([IObjectCreatedEvent], sqlobjectCreatedSubscriber)
+ >>> ztapi.handle([IObjectModifiedEvent], sqlobjectModifiedSubscriber)
+
+ Then, create a connection:
>>> from sqlobject.dbconnection import connectionForURI
>>> from sqlos.tests.sampleperson import SamplePerson
>>> from sqlos.adapter import SQLiteAdapter
>>> connection = connectionForURI('sqlite:///tmp/sqlite.db')
>>> adapter = SQLiteAdapter(connection.makeConnection())
+
+ Stuff the connection into the test class and initialize the table
+ if it doesn't exists yet:
+
>>> SamplePerson._connection = adapter
>>> SamplePerson.createTable(ifNotExists=True)
+
+ Now create a SamplePerson for testing:
+
>>> person = SamplePerson(fullname='Sidnei', username='sidnei',
... password='123')
>>> person.id
@@ -48,14 +81,22 @@
Create a temp method to ease testing:
- >>> oldsync = SamplePerson.sync
- >>> def sync(self):
+ >>> oldsync = SamplePerson.syncUpdate
+ >>> def syncUpdate(self):
... self._sync_called = True
... oldsync(self)
...
- >>> SamplePerson.sync = sync
+ >>> SamplePerson.syncUpdate = syncUpdate
>>> SamplePerson._sync_called = False
+ >>> oldexpire = SamplePerson.expire
+ >>> def expire(self):
+ ... self._expire_called = True
+ ... oldexpire(self)
+ ...
+ >>> SamplePerson.expire = expire
+ >>> SamplePerson._expire_called = False
+
Now, we check the DataManager state:
>>> person.dirty
@@ -84,24 +125,29 @@
...
TypeError: Already prepared
- Check that sync() hasn't been called yet:
+ Check that syncUpdate() hasn't been called yet:
>>> person._sync_called
False
+ >>> person._expire_called
+ False
- Commit, and make sure sync has been called:
+ Commit, and make sure syncUpdate and expire have been called:
>>> dm.commit(t1)
>>> dm.state, dm.delta
(0, 0)
>>> person._sync_called
True
+ >>> person._expire_called
+ True
>>> person.dirty
False
Now, we do everything again to test abort():
>>> person._sync_called = False
+ >>> person._expire_called = False
>>> person.set(fullname='Alan Runyan')
>>> person.dirty
True
@@ -115,16 +161,29 @@
>>> dm.state, dm.delta
(0, 0)
- SQLObject doesn't have a reset() method (yet), so
- the object is still dirty:
+ Make sure syncUpdate and expire have been called:
- >>> person.dirty
+ >>> person._sync_called
+ True
+ >>> person._expire_called
True
+ But the object is not dirty nor expired, because sync() has been
+ called to refetch the values from the database:
+
+ >>> person.dirty, person._expired
+ (False, False)
+
And then cleanup the monkeypatched method:
- >>> SamplePerson.sync = oldsync
+ >>> SamplePerson.syncUpdate = oldsync
>>> del SamplePerson._sync_called
+ >>> SamplePerson.expire = oldexpire
+ >>> del SamplePerson._expire_called
+
+ And finally call tearDown to cleanup the environment:
+
+ >>> tearDown()
"""
implements(IDataManager)
@@ -158,6 +217,8 @@
self.state -= self.delta
self.prepared = False
self.delta = 0
+ for obj in self.objects:
+ expired(obj)
self.objects = []
def commit(self, txn):
@@ -169,7 +230,7 @@
self.transaction = None
self.prepared = False
for obj in self.objects:
- obj.sync()
+ modified(obj)
self.objects = []
def register(self, obj):
More information about the z3-checkins
mailing list