[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