[Checkins] SVN: z3c.zalchemy/trunk/src/z3c/zalchemy/ Simple container implementation which contains all objects of a given SQLAlchemy class

Jürgen Kartnaller juergen at kartnaller.at
Thu Jun 29 04:45:56 EDT 2006


Log message for revision 68902:
  Simple container implementation which contains all objects of a given SQLAlchemy class

Changed:
  U   z3c.zalchemy/trunk/src/z3c/zalchemy/container.py
  A   z3c.zalchemy/trunk/src/z3c/zalchemy/container.txt
  A   z3c.zalchemy/trunk/src/z3c/zalchemy/tests/test_container.py

-=-
Modified: z3c.zalchemy/trunk/src/z3c/zalchemy/container.py
===================================================================
--- z3c.zalchemy/trunk/src/z3c/zalchemy/container.py	2006-06-28 23:22:15 UTC (rev 68901)
+++ z3c.zalchemy/trunk/src/z3c/zalchemy/container.py	2006-06-29 08:45:54 UTC (rev 68902)
@@ -62,7 +62,6 @@
 class SQLAlchemyNameChooser(NameChooser):
 
     def checkName(self, name, container):
-
         if isinstance(name, str):
             name = unicode(name)
         elif not isinstance(name, unicode):
@@ -70,23 +69,15 @@
 
         unproxied = removeSecurityProxy(container)
         if not name.startswith(unproxied._class.__name__+'.'):
-            raise UserError(
-                _("Invalid name for SQLAlchemy object")
-                )
-        try:
-            id = int(name.split('.')[-1])
-        except:
-            raise UserError(
-                _("Invalid id for SQLAlchemy object")
-                )
-
+            raise UserError("Invalid name for SQLAlchemy object")
         return True
 
     def chooseName(self, name, obj):
-        # commit the object to make sure it contains an id
+        # flush the object to make sure it contains an id
         session = z3c.zalchemy.getSession()
-        session.flush(obj)
-        return '%s.%i'%(obj.__class__.__name__, obj.id)
+        session.save(obj)
+        session.flush([obj])
+        return self.context._toStringIdentifier(obj)
 
 
 class SQLAlchemyContainer(Persistent, Contained):
@@ -115,19 +106,16 @@
         return iter(self.keys())
 
     def items(self):
-        for obj in self._class.mapper.select():
-            name = '%s.%i'%(self._class.__name__, obj.id)
+        session = z3c.zalchemy.getSession()
+        query = session.query(self._class)
+        for obj in query.select():
+            name = self._toStringIdentifier(obj)
             yield (name, contained(obj, self, name) )
 
     def __getitem__(self, name):
         if not isinstance(name, basestring):
             raise KeyError, "%s is not a string" % name
-        vals = name.split('.')
-        try:
-            id=int(vals[-1])
-        except ValueError:
-            return None
-        obj = self._class.mapper.selectfirst(self._class.c.id==id)
+        obj = self._fromStringIdentifier(name)
         if obj is None:
             raise KeyError, name
         return contained(obj, self, name)
@@ -144,7 +132,7 @@
     def __len__(self):
         try:
             session = z3c.zalchemy.getSession()
-            query = session.query(class_)
+            query = session.query(self._class)
             return query.count()
         except sqlalchemy.exceptions.SQLError:
             # we don't want an exception in case of database problems
@@ -158,5 +146,21 @@
 
     def __setitem__(self, name, item):
         session = z3c.zalchemy.getSession()
-        session.flush(item)
+        session.save(item)
+        session.flush([item])
 
+    def _toStringIdentifier(self, obj):
+        session = z3c.zalchemy.getSession()
+        mapper = session.mapper(obj.__class__)
+        instance_key = mapper.instance_key(obj)
+        ident = str(instance_key[1])
+        return '%s.%s'%(instance_key[0].__name__, ident)
+
+    def _fromStringIdentifier(self, name):
+        dotpos = name.find('.')
+        if dotpos<0:
+            return None
+        exec 'keys='+name[dotpos+1:]
+        session = z3c.zalchemy.getSession()
+        return session.query(self._class).get([str(key) for key in keys])
+

Added: z3c.zalchemy/trunk/src/z3c/zalchemy/container.txt
===================================================================
--- z3c.zalchemy/trunk/src/z3c/zalchemy/container.txt	2006-06-28 23:22:15 UTC (rev 68901)
+++ z3c.zalchemy/trunk/src/z3c/zalchemy/container.txt	2006-06-29 08:45:54 UTC (rev 68902)
@@ -0,0 +1,114 @@
+zalchemy container
+==================
+
+   >>> import z3c.zalchemy
+   >>> from z3c.zalchemy.tests.test_container import SQLTestSingle, SQLTestMulti
+   >>> from z3c.zalchemy.container import SQLAlchemyContainer
+
+   >>> session = z3c.zalchemy.getSession
+
+We create a container :
+
+   >>> c = SQLAlchemyContainer()
+
+And assign a class to the container.
+The class must be mapped to a table.
+
+   >>> c.className = 'z3c.zalchemy.tests.test_container.SQLTestSingle'
+
+
+WriteContainer
+--------------
+
+It is important to note that the name used to assign an item to a container
+is not used. The container is only saving the item in the session and then
+flushing it to the database.
+
+   >>> c[''] = SQLTestSingle()
+
+The above line has the same effect than this :
+
+   >>> t = SQLTestSingle()
+   >>> session().save(t)
+   >>> session().flush([t])
+
+Clean up for the next test :
+
+   >>> import transaction
+   >>> transaction.abort()
+
+ReadContainer
+-------------
+
+We can ask for the length :
+
+   >>> len(c)
+   0
+
+   >>> session().save(SQLTestSingle())
+   >>> session().flush()
+
+We can iterate over the keys :
+
+   >>> [key for key in c.keys()]
+   ['SQLTestSingle.(1,)']
+
+We can iterate over the items :
+
+   >>> [item.id for key, item in c.items()]
+   [1]
+
+We can iterate over the values :
+
+   >>> [item.id for item in c.values()]
+   [1]
+
+   >>> session().save(SQLTestSingle())
+   >>> session().flush()
+   >>> len(c)
+   2
+   >>> [key for key in c.keys()]
+   ['SQLTestSingle.(1,)', 'SQLTestSingle.(2,)']
+
+We can access specific object by key :
+
+   >>> c['SQLTestSingle.(1,)'].id
+   1
+   >>> c['SQLTestSingle.(2,)'].id
+   2
+
+Using compound primary keys
+---------------------------
+
+   >>> c = SQLAlchemyContainer()
+   >>> c.className = 'z3c.zalchemy.tests.test_container.SQLTestMulti'
+
+   >>> len(c)
+   0
+
+   >>> session().save(SQLTestMulti(1, 'a'))
+   >>> session().flush()
+   >>> len(c)
+   1
+   >>> [key for key in c.keys()]
+   ["SQLTestMulti.(1, 'a')"]
+   >>> c["SQLTestMulti.(1, 'a')"].id2
+   'a'
+
+NameChooser
+===========
+
+   >>> from z3c.zalchemy.container import SQLAlchemyNameChooser
+   >>> nc = SQLAlchemyNameChooser(c)
+
+   >>> nc.checkName("SQLTestMulti.(1, 'b')", c)
+   True
+   >>> nc.checkName("SQLTestSingle.(1, 'a')", c)
+   Traceback (most recent call last):
+   ...
+   UserError: Invalid name for SQLAlchemy object
+
+   >>> t = SQLTestMulti(1, 'b')
+   >>> nc.chooseName('unused', t)
+   "SQLTestMulti.(1, 'b')"
+


Property changes on: z3c.zalchemy/trunk/src/z3c/zalchemy/container.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.zalchemy/trunk/src/z3c/zalchemy/tests/test_container.py
===================================================================
--- z3c.zalchemy/trunk/src/z3c/zalchemy/tests/test_container.py	2006-06-28 23:22:15 UTC (rev 68901)
+++ z3c.zalchemy/trunk/src/z3c/zalchemy/tests/test_container.py	2006-06-29 08:45:54 UTC (rev 68902)
@@ -0,0 +1,74 @@
+##############################################################################
+#
+# Copyright (c) 2006 ROBOTECH Logistiksysteme GmbH and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import unittest
+import doctest
+from zope.app.testing import setup
+from zope.testing.doctestunit import DocFileSuite
+from zope.app.testing.placelesssetup import PlacelessSetup
+
+import sqlalchemy
+import z3c.zalchemy
+
+
+singlePrimaryKeyTable = sqlalchemy.Table(
+        'singlePrimaryKeyTable',
+        z3c.zalchemy.metadata,
+        sqlalchemy.Column('id', sqlalchemy.Integer, primary_key = True),
+        sqlalchemy.Column('x', sqlalchemy.Integer),
+        )
+
+class SQLTestSingle(object):
+    pass
+
+sqlalchemy.mapper(SQLTestSingle, singlePrimaryKeyTable)
+
+
+multiPrimaryKeyTable = sqlalchemy.Table(
+        'multiPrimaryKeyTable',
+        z3c.zalchemy.metadata,
+        sqlalchemy.Column('id1', sqlalchemy.Integer, primary_key = True),
+        sqlalchemy.Column('id2', sqlalchemy.String,  primary_key = True),
+        sqlalchemy.Column('x', sqlalchemy.Integer),
+        )
+
+class SQLTestMulti(object):
+    def __init__(self, id1, id2):
+        self.id1 = id1
+        self.id2 = id2
+
+sqlalchemy.mapper(SQLTestMulti, multiPrimaryKeyTable)
+
+
+def setUp(test):
+    setup.placefulSetUp()
+    z3c.zalchemy.testing.placefulSetUp(test)
+    z3c.zalchemy.createTable('singlePrimaryKeyTable')
+    z3c.zalchemy.createTable('multiPrimaryKeyTable')
+
+def tearDown(test):
+    z3c.zalchemy.testing.placefulTearDown(test)
+    setup.placefulTearDown()
+
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('../container.txt',
+                     setUp=setUp, tearDown=tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+


Property changes on: z3c.zalchemy/trunk/src/z3c/zalchemy/tests/test_container.py
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list