Some improvements on relation registry stuff
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1089 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
84dd0ce76a
commit
a5cb31fa47
4 changed files with 92 additions and 23 deletions
|
@ -87,11 +87,15 @@ reference these objects via IntIds later; the __parent__ and __name__
|
||||||
attributes are also needed later when we send an IObjectRemovedEvent event):
|
attributes are also needed later when we send an IObjectRemovedEvent event):
|
||||||
|
|
||||||
>>> from persistent import Persistent
|
>>> from persistent import Persistent
|
||||||
|
>>> from zope.interface import implements
|
||||||
|
>>> from cybertools.relation.interfaces import IRelatable
|
||||||
|
|
||||||
>>> class Person(Persistent):
|
>>> class Person(Persistent):
|
||||||
... __name__ = __parent__ = None
|
... __name__ = __parent__ = None
|
||||||
|
... implements(IRelatable)
|
||||||
|
|
||||||
>>> class City(Persistent):
|
>>> class City(Persistent):
|
||||||
... pass
|
... implements(IRelatable)
|
||||||
|
|
||||||
>>> clark = Person()
|
>>> clark = Person()
|
||||||
>>> kirk = Person()
|
>>> kirk = Person()
|
||||||
|
@ -138,6 +142,12 @@ relations, first and second:
|
||||||
>>> len(nyRels)
|
>>> len(nyRels)
|
||||||
2
|
2
|
||||||
|
|
||||||
|
We can also query the registry using an example relation:
|
||||||
|
|
||||||
|
>>> clarkRels = relations.query(example=LivesIn(clark, None))
|
||||||
|
>>> len(clarkRels)
|
||||||
|
1
|
||||||
|
|
||||||
It is also possible to remove a relation from the relation registry:
|
It is also possible to remove a relation from the relation registry:
|
||||||
|
|
||||||
>>> relations.unregister(
|
>>> relations.unregister(
|
||||||
|
@ -254,6 +264,12 @@ if we want to access relations by array index:
|
||||||
>>> len(nyRels)
|
>>> len(nyRels)
|
||||||
2
|
2
|
||||||
|
|
||||||
|
We can also query the registry using an example relation:
|
||||||
|
|
||||||
|
>>> clarkRels = relations.query(example=LivesIn(clark, None))
|
||||||
|
>>> len(clarkRels)
|
||||||
|
1
|
||||||
|
|
||||||
>>> relations.unregister(
|
>>> relations.unregister(
|
||||||
... list(relations.query(first=audrey, second=newyork))[0]
|
... list(relations.query(first=audrey, second=newyork))[0]
|
||||||
... )
|
... )
|
||||||
|
@ -355,10 +371,12 @@ creating a special relation class that uses named predicates.
|
||||||
>>> class PredicateRelation(DyadicRelation):
|
>>> class PredicateRelation(DyadicRelation):
|
||||||
... def __init__(self, predicate, first, second):
|
... def __init__(self, predicate, first, second):
|
||||||
... self.predicate = predicate
|
... self.predicate = predicate
|
||||||
|
... predicate.forClass = self.__class__
|
||||||
... self.first = first
|
... self.first = first
|
||||||
... self.second = second
|
... self.second = second
|
||||||
... def getPredicateName(self):
|
... def getPredicateName(self):
|
||||||
... return self.predicate.getPredicateName()
|
... baseName = super(PredicateRelation, self).getPredicateName()
|
||||||
|
... return '.'.join((baseName, self.predicate.name))
|
||||||
|
|
||||||
We also need a class for the predicate objects that will be used for
|
We also need a class for the predicate objects that will be used for
|
||||||
the constructor of the NamedPredicateRelation class:
|
the constructor of the NamedPredicateRelation class:
|
||||||
|
@ -370,7 +388,10 @@ the constructor of the NamedPredicateRelation class:
|
||||||
... implements(IPredicate)
|
... implements(IPredicate)
|
||||||
... def __init__(self, name):
|
... def __init__(self, name):
|
||||||
... self.name = name
|
... self.name = name
|
||||||
|
... self.forClass = None
|
||||||
... def getPredicateName(self):
|
... def getPredicateName(self):
|
||||||
|
... if self.forClass is not None:
|
||||||
|
... return self.forClass(self, None, None).getPredicateName()
|
||||||
... return self.name
|
... return self.name
|
||||||
|
|
||||||
We can now create a predicate with the name '_lives in_' (that may replace
|
We can now create a predicate with the name '_lives in_' (that may replace
|
||||||
|
|
|
@ -29,6 +29,7 @@ from persistent import Persistent
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from interfaces import IPredicate
|
from interfaces import IPredicate
|
||||||
from interfaces import IRelation, IDyadicRelation, ITriadicRelation
|
from interfaces import IRelation, IDyadicRelation, ITriadicRelation
|
||||||
|
from interfaces import IRelatable
|
||||||
|
|
||||||
class Relation(Persistent):
|
class Relation(Persistent):
|
||||||
|
|
||||||
|
@ -40,6 +41,12 @@ class Relation(Persistent):
|
||||||
|
|
||||||
def validate(self, registry=None):
|
def validate(self, registry=None):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def checkRelatable(self, *objects):
|
||||||
|
for obj in objects:
|
||||||
|
if obj is not None and not IRelatable.providedBy(obj):
|
||||||
|
raise(ValueError, 'Objects to be used in relations '
|
||||||
|
'must provide the IRelatable interface.')
|
||||||
|
|
||||||
|
|
||||||
class DyadicRelation(Relation):
|
class DyadicRelation(Relation):
|
||||||
|
@ -49,6 +56,7 @@ class DyadicRelation(Relation):
|
||||||
def __init__(self, first, second):
|
def __init__(self, first, second):
|
||||||
self.first = first
|
self.first = first
|
||||||
self.second = second
|
self.second = second
|
||||||
|
self.checkRelatable(first, second)
|
||||||
|
|
||||||
|
|
||||||
class TriadicRelation(Relation):
|
class TriadicRelation(Relation):
|
||||||
|
@ -59,4 +67,5 @@ class TriadicRelation(Relation):
|
||||||
self.first = first
|
self.first = first
|
||||||
self.second = second
|
self.second = second
|
||||||
self.third = third
|
self.third = third
|
||||||
|
self.checkRelatable(first, second, third)
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,23 @@ class ITriadicRelation(IDyadicRelation):
|
||||||
third = Attribute('Third object that belongs to the relation.')
|
third = Attribute('Third object that belongs to the relation.')
|
||||||
|
|
||||||
|
|
||||||
|
# this is just a conceptual try - thinking about storing
|
||||||
|
# relations as attributes...
|
||||||
|
class IAttributeRelation(IDyadicRelation):
|
||||||
|
""" A type of relation that will be stored in attributes of the
|
||||||
|
objects that take part in the relation. You have to use a
|
||||||
|
relation registry that provides IAttributeRelationRegistry
|
||||||
|
for registering/managing relations of this type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
attributeNameFirst = Attribute('Name of the attribute in which the '
|
||||||
|
'relation will be stored on the `first` object. '
|
||||||
|
'Typically a class attribute.')
|
||||||
|
attributeNameSecond = Attribute('Name of the attribute in which the '
|
||||||
|
'relation will be stored on the `second` object.'
|
||||||
|
'Typically a class attribute.')
|
||||||
|
|
||||||
|
|
||||||
class IPredicate(Interface):
|
class IPredicate(Interface):
|
||||||
""" A predicate signifies a relationship. This may be implemented
|
""" A predicate signifies a relationship. This may be implemented
|
||||||
directly as a relation class, or the relation object may
|
directly as a relation class, or the relation object may
|
||||||
|
@ -90,6 +107,15 @@ class IRelationInvalidatedEvent(IObjectEvent):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# marker interfaces
|
||||||
|
|
||||||
|
class IRelatable(Interface):
|
||||||
|
""" Marker interface for objects that may have relations associated
|
||||||
|
with them. Should be checked by IRelationRegistry.register()
|
||||||
|
and event handlers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
# relation registry interfaces
|
# relation registry interfaces
|
||||||
|
|
||||||
class IRelationRegistryUpdate(Interface):
|
class IRelationRegistryUpdate(Interface):
|
||||||
|
@ -105,15 +131,12 @@ class IRelationRegistryUpdate(Interface):
|
||||||
""" Remove the relation given from this registry.
|
""" Remove the relation given from this registry.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#BBB
|
|
||||||
#IRelationsRegistryUpdate = IRelationRegistryUpdate
|
|
||||||
|
|
||||||
|
|
||||||
class IRelationRegistryQuery(Interface):
|
class IRelationRegistryQuery(Interface):
|
||||||
""" Interface for querying a relation registry.
|
""" Interface for querying a relation registry.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def query(relation=None, **kw):
|
def query(example=None, **kw):
|
||||||
""" Return a sequence of relations that fulfill the criteria given.
|
""" Return a sequence of relations that fulfill the criteria given.
|
||||||
|
|
||||||
You may provide a relation object as an example that specifies the
|
You may provide a relation object as an example that specifies the
|
||||||
|
@ -125,8 +148,6 @@ class IRelationRegistryQuery(Interface):
|
||||||
rr.queryRelations(first=someObject, second=anotherObject,
|
rr.queryRelations(first=someObject, second=anotherObject,
|
||||||
relationship=SomeRelationClass)
|
relationship=SomeRelationClass)
|
||||||
"""
|
"""
|
||||||
#BBB
|
|
||||||
#IRelationsRegistryQuery = IRelationRegistryQuery
|
|
||||||
|
|
||||||
|
|
||||||
class IRelationRegistry(IRelationRegistryUpdate, IRelationRegistryQuery):
|
class IRelationRegistry(IRelationRegistryUpdate, IRelationRegistryQuery):
|
||||||
|
@ -134,6 +155,4 @@ class IRelationRegistry(IRelationRegistryUpdate, IRelationRegistryQuery):
|
||||||
implemented as a local utility .
|
implemented as a local utility .
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#BBB
|
|
||||||
#IRelationsRegistry = IRelationRegistry
|
|
||||||
|
|
||||||
|
|
|
@ -57,23 +57,27 @@ class DummyRelationRegistry(object):
|
||||||
|
|
||||||
def query(self, example=None, **kw):
|
def query(self, example=None, **kw):
|
||||||
result = []
|
result = []
|
||||||
|
criteria = {}
|
||||||
|
if example is not None:
|
||||||
|
for attr in ('first', 'second', 'third',):
|
||||||
|
value = getattr(example, attr, None)
|
||||||
|
if value is not None:
|
||||||
|
criteria[attr] = value
|
||||||
|
criteria['relationship'] = example
|
||||||
|
criteria.update(kw)
|
||||||
for r in self.relations:
|
for r in self.relations:
|
||||||
hit = True
|
hit = True
|
||||||
for k in kw:
|
for k in criteria:
|
||||||
#if ((k == 'relationship' and r.__class__ != kw[k])
|
|
||||||
if ((k == 'relationship'
|
if ((k == 'relationship'
|
||||||
and r.getPredicateName() != kw[k].getPredicateName())
|
and r.getPredicateName() != criteria[k].getPredicateName())
|
||||||
or (k != 'relationship'
|
or (k != 'relationship'
|
||||||
and (not hasattr(r, k) or getattr(r, k) != kw[k]))):
|
and (not hasattr(r, k) or getattr(r, k) != criteria[k]))):
|
||||||
hit = False
|
hit = False
|
||||||
break
|
break
|
||||||
if hit:
|
if hit:
|
||||||
result.append(r)
|
result.append(r)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
#BBB
|
|
||||||
#DummyRelationsRegistry = DummyRelationRegistry
|
|
||||||
|
|
||||||
|
|
||||||
class RelationRegistry(Catalog):
|
class RelationRegistry(Catalog):
|
||||||
""" Local utility for registering (cataloguing) and searching relations.
|
""" Local utility for registering (cataloguing) and searching relations.
|
||||||
|
@ -97,14 +101,26 @@ class RelationRegistry(Catalog):
|
||||||
notify(RelationInvalidatedEvent(relation))
|
notify(RelationInvalidatedEvent(relation))
|
||||||
|
|
||||||
def query(self, example=None, **kw):
|
def query(self, example=None, **kw):
|
||||||
|
intIds = zapi.getUtility(IIntIds)
|
||||||
|
criteria = {}
|
||||||
|
if example is not None:
|
||||||
|
for attr in ('first', 'second', 'third',):
|
||||||
|
value = getattr(example, attr, None)
|
||||||
|
if value is not None:
|
||||||
|
criteria[attr] = intIds.getId(value)
|
||||||
|
pn = example.getPredicateName()
|
||||||
|
if pn:
|
||||||
|
criteria['relationship'] = pn
|
||||||
for k in kw:
|
for k in kw:
|
||||||
|
# overwrite example fields with explicit values
|
||||||
if k == 'relationship':
|
if k == 'relationship':
|
||||||
quString = kw[k].getPredicateName()
|
criteria[k] = kw[k].getPredicateName()
|
||||||
else:
|
else:
|
||||||
quString = zapi.getUtility(IIntIds).getId(kw[k])
|
criteria[k] = intIds.getId(kw[k])
|
||||||
|
for k in criteria:
|
||||||
# set min, max
|
# set min, max
|
||||||
kw[k] = (quString, quString)
|
criteria[k] = (criteria[k], criteria[k])
|
||||||
return self.searchResults(**kw)
|
return self.searchResults(**criteria)
|
||||||
|
|
||||||
#BBB
|
#BBB
|
||||||
#RelationsRegistry = RelationRegistry
|
#RelationsRegistry = RelationRegistry
|
||||||
|
@ -207,9 +223,13 @@ def invalidateRelations(context, event):
|
||||||
""" Handles IObjectRemoved event: unregisters
|
""" Handles IObjectRemoved event: unregisters
|
||||||
all relations the object to be removed is involved in.
|
all relations the object to be removed is involved in.
|
||||||
"""
|
"""
|
||||||
|
# TODO: check marker interface of object:
|
||||||
|
# if not IRelatable.providedBy(event.object):
|
||||||
|
# return
|
||||||
relations = []
|
relations = []
|
||||||
registry = zapi.queryUtility(IRelationRegistry)
|
#registry = zapi.queryUtility(IRelationRegistry)
|
||||||
if registry is not None:
|
registries = zapi.getAllUtilitiesRegisteredFor(IRelationRegistry)
|
||||||
|
for registry in registries:
|
||||||
for attr in ('first', 'second', 'third'):
|
for attr in ('first', 'second', 'third'):
|
||||||
relations = registry.query(**{attr: context})
|
relations = registry.query(**{attr: context})
|
||||||
for relation in relations:
|
for relation in relations:
|
||||||
|
|
Loading…
Add table
Reference in a new issue