[z3-checkins] r36434 - in z3/sqlos/trunk/src/sqlos: . container ftests interfaces testing
kobold at codespeak.net
kobold at codespeak.net
Wed Jan 10 20:31:38 CET 2007
Author: kobold
Date: Wed Jan 10 20:31:36 2007
New Revision: 36434
Added:
z3/sqlos/trunk/src/sqlos/ftests/joins.txt
Modified:
z3/sqlos/trunk/src/sqlos/configure.zcml
z3/sqlos/trunk/src/sqlos/container/standard.py
z3/sqlos/trunk/src/sqlos/ftesting.zcml
z3/sqlos/trunk/src/sqlos/ftests/adding.txt
z3/sqlos/trunk/src/sqlos/ftests/containers.txt
z3/sqlos/trunk/src/sqlos/ftests/localutilities.txt
z3/sqlos/trunk/src/sqlos/ftests/test_doctest.py
z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py
z3/sqlos/trunk/src/sqlos/interfaces/__init__.py
z3/sqlos/trunk/src/sqlos/interfaces/container.py
z3/sqlos/trunk/src/sqlos/testing/sampleperson.py
z3/sqlos/trunk/src/sqlos/zsqlobject.py
Log:
Implemented native joins between SQLOS objects.
Modified: z3/sqlos/trunk/src/sqlos/configure.zcml
==============================================================================
--- z3/sqlos/trunk/src/sqlos/configure.zcml (original)
+++ z3/sqlos/trunk/src/sqlos/configure.zcml Wed Jan 10 20:31:36 2007
@@ -4,33 +4,7 @@
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="sqlos">
- <!-- ISQLObjectContainer Views -->
-
- <class class=".container.SQLObjectContainer">
-
- <implements interface="zope.app.container.interfaces.IContentContainer" />
-
- <factory
- id="sqlos.SQLObjectContainer"
- title="SQLObject Container"
- description="A container for SQLObject instances" />
-
- <require
- permission="zope.View"
- interface="zope.app.container.interfaces.IReadContainer"
- />
-
- <require
- permission="zope.ManageContent"
- interface="zope.app.container.interfaces.IWriteContainer"
- />
-
- <require
- permission="zope.View"
- attributes="select"
- />
-
- </class>
+ <!-- Adapters -->
<adapter
provides="zope.app.container.interfaces.INameChooser"
@@ -45,8 +19,28 @@
permission="zope.Public"
factory=".container.SQLObjectMonoNameChooser"
/>
-
- <!-- Default view for containers. Should we really be specifying this??-->
+
+ <adapter
+ provides="zope.app.container.interfaces.INameChooser"
+ for="sqlos.interfaces.container.ISQLObjectJoinContainer"
+ permission="zope.Public"
+ factory=".container.SQLObjectMonoNameChooser"
+ />
+
+ <adapter
+ for="sqlos.interfaces.ISelectResults"
+ provides="sqlos.interfaces.container.ISQLObjectJoinContainer"
+ factory="sqlos.zsqlobject.SelectResultsContainer"
+ permission="zope.Public"
+ />
+
+ <adapter
+ for="sqlos.interfaces.ISQLSchema"
+ factory="sqlos.zsqlobject.SQLOSTraversable"
+ provides="zope.traversing.interfaces.ITraversable"
+ />
+
+ <!-- Default view for containers -->
<browser:defaultView
for="sqlos.interfaces.container.ISQLObjectContainer"
@@ -62,6 +56,31 @@
attribute="contents"
/>
+ <browser:defaultView
+ for="sqlos.interfaces.container.ISQLObjectJoinContainer"
+ name="contents.html"
+ />
+
+ <browser:page
+ name="contents.html"
+ menu="zmi_views" title="Contents"
+ for=".interfaces.container.ISQLObjectJoinContainer"
+ permission="zope.ManageContent"
+ class="zope.app.container.browser.contents.Contents"
+ attribute="contents"
+ />
+
+ <browser:page
+ name="contents.html"
+ menu="zmi_views" title="Contents"
+ for=".interfaces.ISQLObject"
+ permission="zope.ManageContent"
+ class="zope.app.container.browser.contents.Contents"
+ attribute="contents"
+ />
+
+ <!-- Database adapters -->
+
<class class=".adapter.MySQLAdapter">
<require
permission="zope.Public"
@@ -131,6 +150,8 @@
/>
</configure>
+ <!-- Subscribers for cache cleaning -->
+
<subscriber
for="zope.app.component.interfaces.ISite
zope.app.publication.interfaces.IBeforeTraverseEvent"
Modified: z3/sqlos/trunk/src/sqlos/container/standard.py
==============================================================================
--- z3/sqlos/trunk/src/sqlos/container/standard.py (original)
+++ z3/sqlos/trunk/src/sqlos/container/standard.py Wed Jan 10 20:31:36 2007
@@ -23,7 +23,7 @@
from zope.location.interfaces import ILocation
from zope.proxy import sameProxiedObjects
-from sqlos.interfaces import ISQLObject, IISQLObject
+from sqlos.interfaces import ISQLSchema, ISQLObject, IISQLObject
from sqlos.interfaces.container import ISQLObjectContainer
@@ -31,7 +31,7 @@
"""An implementation of zope.app.container.contained.contained
that doesn't generate events, for internal use.
"""
- if (parent is None):
+ if parent is None:
raise TypeError, 'Must provide a parent'
if not IContained.providedBy(obj):
@@ -40,16 +40,13 @@
else:
obj = ContainedProxy(obj)
- oldparent = obj.__parent__
- oldname = obj.__name__
+ obj.__name__ = unicode(name)
- if (oldparent is None) or not (oldparent is parent
- or sameProxiedObjects(oldparent, parent)):
+ if ISQLSchema.providedBy(obj):
+ obj.setParent(parent)
+ else:
obj.__parent__ = parent
- if oldname != name and name is not None:
- obj.__name__ = unicode(name)
-
return obj
@@ -165,7 +162,7 @@
KeyError is raised.
"""
try:
- return contained(self[name], parent=self, name=name)
+ return self[name]
except KeyError:
return default
Modified: z3/sqlos/trunk/src/sqlos/ftesting.zcml
==============================================================================
--- z3/sqlos/trunk/src/sqlos/ftesting.zcml (original)
+++ z3/sqlos/trunk/src/sqlos/ftesting.zcml Wed Jan 10 20:31:36 2007
@@ -12,7 +12,7 @@
You should only need to change the connectionName in order to
test against a different database that sqlite -->
- <sqlos:connectionName name='sqlite' />
+ <sqlos:connectionName name='pg2sql' />
<adapter
provides=".interfaces.IZopeSQLConnection"
@@ -89,6 +89,10 @@
permission="zope.View"
interface="sqlos.interfaces.ISQLObject"
/>
+ <require
+ permission="zope.View"
+ interface="zope.app.container.interfaces.IReadContainer"
+ />
</class>
<browser:addform
@@ -147,12 +151,17 @@
permission="zope.View"
interface="sqlos.interfaces.ISQLObject"
/>
+ <require
+ permission="zope.View"
+ interface="zope.app.container.interfaces.IReadContainer"
+ />
</class>
<browser:addform
schema="sqlos.testing.sampleperson.IDog"
content_factory="sqlos.testing.sampleperson.SampleDog"
- keyword_arguments="fullname owner"
+ fields="fullname"
+ keyword_arguments="fullname"
label="New Sample Dog"
name="AddDog.html"
permission="zope.ManageContent"
@@ -161,6 +170,7 @@
<browser:editform
schema="sqlos.testing.sampleperson.IDog"
name="edit.html"
+ fields="fullname"
menu="zmi_views"
label="Edit a Sample Dog"
permission="zope.ManageContent"
Modified: z3/sqlos/trunk/src/sqlos/ftests/adding.txt
==============================================================================
--- z3/sqlos/trunk/src/sqlos/ftests/adding.txt (original)
+++ z3/sqlos/trunk/src/sqlos/ftests/adding.txt Wed Jan 10 20:31:36 2007
@@ -139,4 +139,5 @@
False
CleanUp:
+
>>> sampleperson.dropTestingTables()
Modified: z3/sqlos/trunk/src/sqlos/ftests/containers.txt
==============================================================================
--- z3/sqlos/trunk/src/sqlos/ftests/containers.txt (original)
+++ z3/sqlos/trunk/src/sqlos/ftests/containers.txt Wed Jan 10 20:31:36 2007
@@ -124,11 +124,15 @@
Now we add sally's dog:
- >>> fido = sampleperson.SampleDog(fullname='Fido', owner='sally')
+ >>> fido = sampleperson.SampleDog(fullname='Fido', owner=sally)
>>> len(multicontainer)
2
>>> fido in [i for i in multicontainer.values()]
True
+ >>> fido in sally.dogs
+ True
+ >>> fido.owner is sally
+ True
CleanUp:
Added: z3/sqlos/trunk/src/sqlos/ftests/joins.txt
==============================================================================
--- (empty file)
+++ z3/sqlos/trunk/src/sqlos/ftests/joins.txt Wed Jan 10 20:31:36 2007
@@ -0,0 +1,127 @@
+=================
+Joined SQLObjects
+=================
+
+Test join relationships between SQLOS objects.
+
+First lets set up some tables in the database:
+
+ >>> from sqlos.testing import sampleperson
+ >>> sampleperson.createTestingTables()
+
+Then get a browser:
+
+ >>> from zope.testbrowser.testing import Browser
+ >>> browser = Browser()
+ >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+ >>> browser.handleErrors = False
+
+Go to the main interface and add a SQLObject MultiContainer
+
+ >>> browser.open('http://localhost/manage')
+ >>> 'sqlos.testing.SamplePerson' not in str(browser.contents)
+ True
+ >>> browser.getLink('SQLObject Multi Container').click()
+ >>> browser.getControl(name='new_value').value = 'multicontainer1'
+ >>> browser.getControl('Apply').click()
+
+Now add a Sample Person to the container:
+
+ >>> browser.getLink('multicontainer1').click()
+ >>> browser.getLink('SamplePerson').click()
+ >>> browser.getControl(name='field.fullname').value = 'Bob'
+ >>> browser.getControl(name='field.username').value = 'bob'
+ >>> browser.getControl(name='field.password').value = 'obo'
+ >>> browser.getControl('Add').click()
+
+Lets try editing bob:
+
+ >>> browser.getLink('sqlos.testing.SamplePerson.1').click()
+ >>> print browser.contents
+ <!DOC...
+ ...
+ ...Full Name...
+ ...
+ ...Bob...
+ ...
+ ...Username...
+ ...
+ ...bob...
+ ...
+ ...Password...
+ ...
+ ...obo...
+ ...
+ >>> browser.getControl(name='field.fullname').value = 'Bobby Bones'
+ >>> browser.getControl('Change').click()
+ >>> print browser.contents
+ <!DOC...
+ ...
+ ...Updated on...
+ ...
+ ...Full Name...
+ ...
+ ...Bobby Bones...
+ ...
+
+Now, let's create a new Dog:
+
+ >>> from sqlos.testing.sampleperson import SamplePerson, SampleDog
+ >>> bob = SamplePerson.get(1)
+ >>> dog = SampleDog(fullname='Fido', owner=bob)
+
+Verify the interfaces:
+
+ >>> from zope.interface.verify import verifyObject
+ >>> from zope.app.container.interfaces import IReadContainer
+ >>> from sqlos.interfaces.container import ISQLObjectJoinContainer
+ >>> verifyObject(IReadContainer, bob)
+ True
+ >>> verifyObject(ISQLObjectJoinContainer, bob['dogs'])
+ True
+
+Let's try to access to the dog going through the owner:
+
+ >>> browser.getLink('Contents').click()
+ >>> 'dogs' in browser.contents
+ True
+ >>> browser.getLink('dogs').click()
+ >>> '1/@@' in browser.contents
+ True
+ >>> browser.open('http://localhost/multicontainer1/sqlos.testing.SamplePerson.1/'
+ ... 'dogs/1')
+ >>> browser.getControl(name='field.fullname').value = 'Fido dog'
+ >>> browser.getControl('Change').click()
+ >>> print browser.contents
+ <!DOC...
+ ...
+ ...Updated on...
+ ...
+ ...Full Name...
+ ...
+ ...Fido dog...
+ ...
+
+Let's try to access to the person going through the dog:
+
+ >>> browser.getLink('multicontainer1').click()
+ >>> browser.getLink('sqlos.testing.SampleDog.1').click()
+ >>> browser.getLink('Contents').click()
+ >>> 'owner' in browser.contents
+ True
+ >>> browser.getLink('owner').click()
+ >>> browser.getControl(name='field.fullname').value = 'Bob the top'
+ >>> browser.getControl('Change').click()
+ >>> print browser.contents
+ <!DOC...
+ ...
+ ...Updated on...
+ ...
+ ...Full Name...
+ ...
+ ...Bob the top...
+ ...
+
+CleanUp:
+
+ >>> sampleperson.dropTestingTables()
Modified: z3/sqlos/trunk/src/sqlos/ftests/localutilities.txt
==============================================================================
--- z3/sqlos/trunk/src/sqlos/ftests/localutilities.txt (original)
+++ z3/sqlos/trunk/src/sqlos/ftests/localutilities.txt Wed Jan 10 20:31:36 2007
@@ -61,7 +61,7 @@
... '''create table sample_dog (
... id integer primary key,
... fullname varchar(50) not null,
- ... owner varchar(20) not null)''')
+ ... owner_id int not null)''')
>>> c = cursor.execute(
... '''create table sample_isolated_person (
... id integer primary key,
Modified: z3/sqlos/trunk/src/sqlos/ftests/test_doctest.py
==============================================================================
--- z3/sqlos/trunk/src/sqlos/ftests/test_doctest.py (original)
+++ z3/sqlos/trunk/src/sqlos/ftests/test_doctest.py Wed Jan 10 20:31:36 2007
@@ -25,5 +25,6 @@
'containers.txt',
'localutilities.txt',
'isolated_containers.txt',
- 'mono_containers.txt']
+ 'mono_containers.txt',
+ 'joins.txt']
return FunctionalDocFileSuite(*filelist)
Modified: z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py
==============================================================================
--- z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py (original)
+++ z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py Wed Jan 10 20:31:36 2007
@@ -20,7 +20,7 @@
from zope.rdb.interfaces import IZopeDatabaseAdapter
from sqlos.interfaces import IConnectionName
-from sqlos.testing.sampleperson import SamplePerson
+from sqlos.testing.sampleperson import SamplePerson, SampleDog
__metaclass__ = type
@@ -29,6 +29,7 @@
def setUp(self):
super(TestTransaction, self).setUp()
SamplePerson.createTable(ifNotExists=True)
+ SampleDog.createTable(ifNotExists=True)
person = SamplePerson(fullname='Sidnei da Silva',
username='sidnei',
password='test')
Modified: z3/sqlos/trunk/src/sqlos/interfaces/__init__.py
==============================================================================
--- z3/sqlos/trunk/src/sqlos/interfaces/__init__.py (original)
+++ z3/sqlos/trunk/src/sqlos/interfaces/__init__.py Wed Jan 10 20:31:36 2007
@@ -14,7 +14,7 @@
from zope.interface import classImplements
from zope.security.checker import NamesChecker, NoProxy, defineChecker
from zope.schema.vocabulary import SimpleVocabulary
-from zope.schema import Choice, List
+from zope.schema import Choice, List, TextLine
from zope.annotation.interfaces import IAttributeAnnotatable
from zope.app.container.interfaces import IContained
from sqlobject import NoDefault
@@ -33,10 +33,13 @@
)
-class ISQLSchema(Interface):
+class ISQLSchema(IContained):
"""Base interface for SQLObject-based objects"""
- id = Attribute('Id')
+ id = Attribute(u'Id')
+
+ def setParent(parent):
+ """Set the object's parent"""
class IDBConnection(Interface):
@@ -242,7 +245,9 @@
"""
-class ISQLObject(IContained):
+class ISQLObject(Interface):
+
+ sqlmeta = Attribute(u'Subclass sqlmeta for SQLObject objects')
def set(**kw):
"""Used to update multiple values at once, potentially with one SQL
@@ -303,6 +308,63 @@
def __len__():
"""List emulation"""
+ def clone(**newOps):
+ """"""
+
+ def orderBy(orderBy):
+ """"""
+
+ def connection(conn):
+ """"""
+
+ def limit(limit):
+ """"""
+
+ def lazyColumns(value):
+ """"""
+
+ def reversed():
+ """"""
+
+ def distinct():
+ """"""
+
+ def newClause(new_clause):
+ """"""
+
+ def filter(filter_clause):
+ """"""
+
+ def __getitem__(value):
+ """"""
+
+ def lazyIter():
+ """"""
+
+ def accumulate(*expressions):
+ """"""
+
+ def count():
+ """"""
+
+ def accumulateMany(*attributes):
+ """"""
+
+ def accumulateOne(func_name, attribute):
+ """"""
+
+ def sum(attribute):
+ """"""
+
+ def min(attribute):
+ """"""
+
+ def avg(attribute):
+ """"""
+
+ def max(attribute):
+ """"""
+
class IIterator(Interface):
Modified: z3/sqlos/trunk/src/sqlos/interfaces/container.py
==============================================================================
--- z3/sqlos/trunk/src/sqlos/interfaces/container.py (original)
+++ z3/sqlos/trunk/src/sqlos/interfaces/container.py Wed Jan 10 20:31:36 2007
@@ -11,19 +11,17 @@
"""
from zope.interface import Attribute
+from zope.interface.common.mapping import IEnumerableMapping
+
from zope.deprecation import deprecated
from zope.app.container.constraints import ItemTypePrecondition
from zope.annotation.interfaces import IAttributeAnnotatable
-from zope.app.container.interfaces import IContainerNamesContainer
-from zope.app.container.interfaces import IReadContainer, IContainer
-
-
-class ISQLObjectReadContainer(IReadContainer, IAttributeAnnotatable):
- """Read interface for SQLObject containers"""
+from zope.app.container.interfaces import IContainerNamesContainer, IReadContainer, \
+ IContainer, IContained
-class ISQLObjectContainer(IContainer, IContainerNamesContainer, IAttributeAnnotatable):
+class ISQLObjectContainer(IContainerNamesContainer, IAttributeAnnotatable):
"""A SQLObject container"""
def __setitem__(name, obj):
@@ -45,6 +43,10 @@
"""A mono-type SQLObject container"""
+class ISQLObjectJoinContainer(IContainerNamesContainer, IEnumerableMapping, IContained):
+ """A SQLObject container for joins"""
+
+
IIsolatedSQLContainer = ISQLObjectIsolatedContainer
deprecated('IIsolatedSQLContainer', 'sqlos.interfaces.container.IIsolatedSQLContainer '
'is deprecated and will go away in next release; use sqlos.interfaces.container.'
Modified: z3/sqlos/trunk/src/sqlos/testing/sampleperson.py
==============================================================================
--- z3/sqlos/trunk/src/sqlos/testing/sampleperson.py (original)
+++ z3/sqlos/trunk/src/sqlos/testing/sampleperson.py Wed Jan 10 20:31:36 2007
@@ -13,7 +13,7 @@
from sqlobject import *
import transaction
-from zope.interface import implements, classProvides, Interface
+from zope.interface import implements, classProvides, Interface, Attribute
from zope.schema import TextLine, Datetime
from zope.app.container import constraints
from zope.app.container.interfaces import IContained
@@ -68,6 +68,8 @@
required=True,
)
+ dogs = Attribute(u'List of dogs')
+
class IPersonContainer(ISQLObjectContainer):
@@ -97,6 +99,7 @@
fullname = StringCol(length=50, notNull=1)
username = StringCol(length=20, notNull=1)
password = StringCol(length=20, notNull=1)
+ dogs = SQLMultipleJoin('SampleDog', joinColumn='owner_id')
class SampleIsolatedPerson(SQLOS):
@@ -167,7 +170,7 @@
implements(IDog)
fullname = StringCol(length=50, notNull=1)
- owner = StringCol(length=20, notNull=1)
+ owner = ForeignKey('SamplePerson', notNull=1, cascade=True)
class IMultiContainer(IPersonContainer):
Modified: z3/sqlos/trunk/src/sqlos/zsqlobject.py
==============================================================================
--- z3/sqlos/trunk/src/sqlos/zsqlobject.py (original)
+++ z3/sqlos/trunk/src/sqlos/zsqlobject.py Wed Jan 10 20:31:36 2007
@@ -10,15 +10,25 @@
$Id: __init__.py 5216 2004-06-21 18:33:07Z dreamcatcher $
"""
+import sqlobject
+
from zope.interface import implements
from sqlobject.main import SQLObject
-from sqlobject import StringCol
+
from zope.app.container.contained import Contained
+from zope.app.container.interfaces import IReadContainer
+from zope.component import adapts
+from zope.security.proxy import removeSecurityProxy
+from zope.traversing.interfaces import ITraversable
+from zope.traversing.adapters import _marker
from sqlos.connection import ConnectionDescriptor
-from sqlos.interfaces import ISQLObject
+from sqlos.container import contained
+from sqlos.interfaces import ISQLObject, ISelectResults
+from sqlos.interfaces.container import ISQLObjectJoinContainer
from sqlos._transaction import dirty_object_registry
+
def syncUpdateAll():
"""Calls syncUpdate on all dirty SQLOS objects, sending all SQL to the DB.
@@ -46,6 +56,9 @@
>>> from zope.interface.verify import verifyObject
>>> verifyObject(ISQLObject, s)
True
+ >>> verifyObject(IReadContainer, s)
+ True
+
And finally call tearDown and cleanup:
@@ -53,9 +66,10 @@
"""
- implements(ISQLObject)
+ implements(ISQLObject, IReadContainer)
_connection = ConnectionDescriptor()
+ _containers = None
class sqlmeta:
lazyUpdate = True
@@ -69,19 +83,11 @@
dirty = property(_get_dirty, _set_dirty)
def get(self, id, connection=None, selectResults=None):
- # While interacting with zope, we may end up having
- # objects in the cache that have a __parent__ set.
- # This may be confusing when expect to get a object
- # which has no __parent__ and thats not what you get.
try:
- val = super(SQLOS, self).get(id, connection=connection,
+ return super(SQLOS, self).get(id, connection=connection,
selectResults=selectResults)
except ValueError:
raise AttributeError, id
- if getattr(val, '__parent__', None) is not None:
- val.__parent__ = None
- val.__name__ = None
- return val
get = classmethod(get)
def __repr__(self):
@@ -91,3 +97,162 @@
if connection is not None:
self._connection = connection
setConnection = classmethod(setConnection)
+
+ def setParent(self, parent):
+ self.__parent__ = parent
+
+ def __getitem__(self, name):
+ """See zope.app.container.interfaces.IReadContainer"""
+ if self._containers is None:
+ self._containers = {}
+ elif name in self._containers:
+ return self._containers[name]
+
+ obj = None
+ sqlmeta = self.sqlmeta
+ for column in sqlmeta.columns:
+ if column.endswith('ID') and \
+ sqlmeta.columns[column].foreignName == name and \
+ isinstance(sqlmeta.columns[column], sqlobject.SOForeignKey):
+ obj = contained(getattr(self, sqlmeta.columns[column].foreignName),
+ parent=self, name=name)
+
+ if obj is not None:
+ self._containers[name] = obj
+ return obj
+
+ for j in sqlmeta.joins:
+ if j.joinDef.name == name:
+ obj = getattr(self, name)
+ if ISelectResults.providedBy(obj):
+ obj = contained(ISQLObjectJoinContainer(obj), parent=self, name=name)
+ elif not ISQLObject.providedBy(obj):
+ obj = None
+
+ if obj is not None:
+ self._containers[name] = obj
+ return obj
+
+ raise KeyError, name
+
+ def __contains__(self, name):
+ """See zope.app.container.interfaces.IReadContainer"""
+ return name in self.values()
+
+ def __iter__(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ for i in self.keys():
+ yield i
+
+ def __len__(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ return len(tuple(self.keys()))
+
+ def keys(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ sqlmeta = self.sqlmeta
+ for column in sqlmeta.columns:
+ if column.endswith('ID') and \
+ isinstance(sqlmeta.columns[column], sqlobject.SOForeignKey):
+ yield sqlmeta.columns[column].foreignName
+ for join in sqlmeta.joins:
+ yield join.joinDef.name
+
+ def items(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ for key in self.keys():
+ yield (key, self[key])
+
+ def values(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ for key in self.keys():
+ yield self[key]
+
+
+class SQLOSTraversable(object):
+ """Traverses objects via item lookup and attribute"""
+
+ implements(ITraversable)
+
+ def __init__(self, subject):
+ self._subject = subject
+
+ def traverse(self, name, furtherPath):
+ subject = self._subject
+ __traceback_info__ = (subject, name, furtherPath)
+ if hasattr(subject, '__getitem__'):
+ try:
+ return subject[name]
+ except KeyError:
+ pass
+ attr = getattr(subject, name, _marker)
+ if attr is not _marker:
+ return attr
+ raise TraversalError(subject, name)
+
+
+class SelectResultsContainer:
+ """Adapter for SelectResults objects"""
+
+ adapts(ISelectResults)
+
+ implements(ISQLObjectJoinContainer)
+
+ def __init__(self, context):
+ self.context = context
+ self.base_class = None
+
+ def __len__(self):
+ return int(self.context.count())
+
+ def __getitem__(self, name):
+ if not self.base_class:
+ sqlmeta = removeSecurityProxy(self.__parent__.sqlmeta)
+ join = filter(lambda x: x.joinDef.name == self.__name__, sqlmeta.joins)[0]
+ self.base_class = join.otherClass
+ try:
+ result = list(self.context.filter(
+ self.base_class.q.id == self.base_class.sqlmeta.idType(name)))
+ if result:
+ return contained(result[0], name=unicode(name), parent=self)
+ except ValueError:
+ pass
+ raise KeyError, name
+
+ def __iter__(self):
+ for j in self.context:
+ yield unicode(j.id)
+
+ def keys(self):
+ return [unicode(j.id) for j in self.context]
+
+ def items(self):
+ for j in self.context:
+ yield unicode(j.id), contained(j, name=unicode(j.id), parent=self)
+
+ def values(self):
+ for j in self.context:
+ yield contained(j, name=unicode(j.id), parent=self)
+
+ def __nonzero__(self):
+ return len(self)
+
+ def get(self, name, default=None):
+ try:
+ return self[name]
+ except KeyError:
+ return default
+
+ def __contains__(self, object):
+ return object in list(self.items())
+
+ def __delitem__(self, name):
+ """Delete the named object from the container.
+
+ Raises a KeyError if the object is not found.
+ """
+ obj = self[name]
+ obj.destroySelf()
+
+ def __setitem__(self, name, content):
+ return name
More information about the z3-checkins
mailing list