Yet Another Relations (Reference) Engine...
===========================================

  ($Id$)

There are quite a few solutions out there in the Zope world that allow to
manage relations or references bewtween objects. So I have been working
with the reference engine provided by Archetypes (as part of Plone) for
nearly two years now; and I also had a look at some proposals
on zope.org and implementations that are available in the Zope 3 packages from
SchoolTool and CPSSkins.

I have to confess that I was not really happy with any of these proposals
or solutions - a feeling that we may discuss in more detail, the main
point being just that I wanted to have something simple that is nevertheless
flexible enough to accomodate to various needs...

So I came up with the following (mainly combining concepts by Jean-Marc
Orliaguet and implementation ideas from Archetypes 1.3):

Basic API
---------

A relation is an object providing the IRelation interface. This has got
two attributes ('first', 'second') for a dyadic relation) or three ('first',
'second', 'third') for a triadic relation. (You may ignore triadic relations if
you don't think you need them.)

If I now create corresponding classes (DyadicRelation, TriadicRelation) I
can store the objects taking part in a relation directly in these
attributes of my relation objects. (Note that the objects taking part in
a relation are not touched at all.) In fact I create a class for each kind
of relation (each relationship or predicate or whatever you like to call it)
I want to use.

So the question arises what to do with the relation objects? The point here
is not so much where to store them but how to make sure that we can find
them. So we need a registry for relations - interface IRelationRegistry.

This has three methods:

- register(relation)
- unregister(relation)
- query(**kw)

The keyword arguments to the query() method may be:

- relationship=... - a relation class (we can also work with named predicates,
                     see below)
- first=... - an object
- second=... - an object
- third=... - an object

One can combine those arguments at will to search for all relations of the
relation class specified (if given) with the given values for the attributes.
The list may be extended if you use relation classes with additionsl
attributes you want to search for.

(For details have a look at the file README.txt)

Default Implementation
----------------------

You see that this looks very much like a catalog search - so why not implement
the relation registry as a subclass of Catalog (see zope.app.catalog).

OK, so the RelationRegistry class is derived from Catalog, and of course it is
a local utility. The indexes are just FieldIndex objects, using an adapter
to provide unique ids for the objects involved via the IntIds
utility; the same is done for providing an id for the relation objects
themselves. The relationship is mapped to the full module path + class name of
the relation class.

An interesting consequence of this is that the relation objects are not
expllicitly stored somewhere, the only reference to them is via the IntIds
utility. You may of course store them in some container or even make them
first class content objects if you want.

The whole stuff is flexible enough to be extended as needed, e.g. with special
registry classes used via named utilities (or even specialized registry
interfaces), additional attributes on relations (easily indexable in the
registry); it could be wrapped in a richer and more application-oriented
API, etc.

It is also possible to use named predicates (with URIs or strings like
'_ is child of _') instead of different relation classes to represent
relationships (this is shown by an example at the end of the README.txt).

