[Checkins] SVN: megrok.rdb/trunk/src/megrok/rdb/ Add (incomplete) support for QueryContainer, a container driven by

Martijn Faassen faassen at infrae.com
Wed Aug 20 13:42:49 EDT 2008


Log message for revision 90035:
  Add (incomplete) support for QueryContainer, a container driven by
  a custom query.
  

Changed:
  U   megrok.rdb/trunk/src/megrok/rdb/README.txt
  U   megrok.rdb/trunk/src/megrok/rdb/__init__.py
  U   megrok.rdb/trunk/src/megrok/rdb/components.py

-=-
Modified: megrok.rdb/trunk/src/megrok/rdb/README.txt
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/README.txt	2008-08-20 17:13:59 UTC (rev 90034)
+++ megrok.rdb/trunk/src/megrok/rdb/README.txt	2008-08-20 17:42:48 UTC (rev 90035)
@@ -266,3 +266,64 @@
   Quantum Mechanics Quantum Mechanics Physics
   Relativity Relativity Physics
 
+Custom query container
+----------------------
+
+Sometimes we want to expose objects as a (read-only) container based
+on a query, not a relation. This is useful when constructing an
+application and you need a "starting point", a root object that
+launches into SQLAlchemy-mapped object that itself is not directly
+managed by SQLAlchemy.
+
+We can construct such a special container by subclassing from ``rdb.QueryContainer`` and implementing
+the special ``query`` method::
+
+  >>> class MyQueryContainer(rdb.QueryContainer):
+  ...   def query(self):
+  ...      return session.query(Department)
+  >>> qc = MyQueryContainer()
+
+Let's try some common read-only container operations, such as
+``__getitem__``1::
+
+  >>> qc[1].name
+  u'Philosophy'
+  >>> qc[2].name
+  'Physics'
+
+XXX Why the unicode difference?
+
+``__getitem__`` with a ``KeyError``::
+
+  >>> qc[3]
+  Traceback (most recent call last):
+    ...
+  KeyError: 3
+
+``get``::
+
+  >>> qc.get(1).name
+  u'Philosophy'
+  >>> qc.get(3) is None
+  True
+  >>> qc.get(3, 'foo')
+  'foo'
+
+``__contains__``::
+
+  >>> 1 in qc
+  True
+  >>> 3 in qc
+  False
+
+``has_key``::
+
+  >>> qc.has_key(1)
+  True
+  >>> qc.has_key(3)
+  False
+
+``len``::
+
+  >>> len(qc)
+  2

Modified: megrok.rdb/trunk/src/megrok/rdb/__init__.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/__init__.py	2008-08-20 17:13:59 UTC (rev 90034)
+++ megrok.rdb/trunk/src/megrok/rdb/__init__.py	2008-08-20 17:42:48 UTC (rev 90035)
@@ -1,4 +1,4 @@
-from megrok.rdb.components import Model, Container
+from megrok.rdb.components import Model, Container, QueryContainer
 from megrok.rdb.schema import Fields
 from megrok.rdb.directive import key, metadata, tablename, reflected
 from megrok.rdb.setup import setupDatabase

Modified: megrok.rdb/trunk/src/megrok/rdb/components.py
===================================================================
--- megrok.rdb/trunk/src/megrok/rdb/components.py	2008-08-20 17:13:59 UTC (rev 90034)
+++ megrok.rdb/trunk/src/megrok/rdb/components.py	2008-08-20 17:42:48 UTC (rev 90035)
@@ -1,6 +1,7 @@
 from sqlalchemy.orm.collections import MappedCollection, collection
 
 from zope.interface import implements
+from zope.location.interfaces import ILocation
 
 from grokcore.component import Context
 from grok.interfaces import IContainer
@@ -26,7 +27,7 @@
             "don't know how to do keying with composite primary keys")
 
 class Container(MappedCollection):
-    implements(IContainer)
+    implements(IContainer, ILocation)
 
     def __init__(self, *args, **kw):
         rdb_key = directive.key.bind().get(self)
@@ -73,3 +74,55 @@
             session.flush()
             key = self.keyfunc(value)
         self.__setitem__(key, value, _sa_initiator)
+
+class QueryContainer(object):
+    """A read-only Container backed by set of SQLAlchemy queries.
+
+    This container is often used as the "root" object for an application.
+    """
+    # XXX should really only implement IReadContainer, but this requires
+    # a bit of refactoring in Grok
+    implements(IContainer, ILocation)
+
+    def query(self):
+        raise NotImplementedError
+
+    def __getitem__(self, key):
+        result = self.query().get(key)
+        if result is None:
+            raise KeyError(key)
+        result.__parent__ = self
+        result.__name__ = key
+        return result
+    
+    def get(self, key, default=None):
+        try:
+            return self[key]
+        except KeyError:
+            return default
+    
+    def __contains__(self, key):
+        try:
+            self[key]
+            return True
+        except KeyError:
+            return False
+
+    def has_key(self, key):
+        return key in self
+
+    def keys(self):
+        raise NotImplementedError
+
+    def __iter__(self):
+        raise NotImplementedError
+    
+    def values(self):
+        raise NotImplementedError
+
+    def items(self):
+        raise NotImplementedError
+
+    def __len__(self):
+        return self.query().count()
+    



More information about the Checkins mailing list