
Object Cache:
=============
On request for a given object ID, looks to see if the data required is
loaded. If so, operates directly.

If not, requests OQL module to create a 'load instance of this class and the
appropriate key' query. only loads fields in the requested class, not
parents/children classes. sends query to objectstore. results get stored in
the cache, and used.

If the specific class is a sub/superclass, the key needs to watched, in case
there are complex changes. (that's a TODO anyway)


Object Store
============
Executes queries. reads are placed into a table defined by GEAS, and the
object store API has methods to read this data.


OQL
===

Creates queries that the object store can execute. Currently implemented as
SQL, this will probably be changed to another more general format later on.
Only the objctstore is allowed to interpret these queries. also includes an
API for reading certain aspects of the query. combined with the objectstore
API, users of this system can perform any arbitrary query.

(note: actual query execution should be expanded to include object cache
data as well. this will really require a more general query data structure,
and for GEAS to manage queries appropriately. This is another TODO)





Old:
--------------------------------------------------------------------------------
Object Cache
============
Stores the current view of a set of objects. Can flush objects to the
database at arbitrary times. If a read request does not find data, it calls
the OQL code to load the specific data required.

The client API will ensure an object is in the cache by calling a method in
the cache code that loads the object if necessary, and locks it in the cache.
The object must be unlocked by the code that locked it. The lock method will
use the OQL code to generate a 'load object' request, that the object store
will use to load the object. accessing fields in an object that should
exist, but aren't in the database, can be handled by loading the field on
demand. note that 'null' fields must be recorded in the cache, and these are
different to empty fields. (eg: a null string field and a string field with
a 0 length ("") are different.)

(Effectively, 'locking' an object means that the objects existance is
confirmed. it should be rare that a recently locked object is quickly
flushed out of RAM anyway, as locking it will bump it to the top of the most
recently used objects list. Still, the lock will enforce this rule, while
still allowing objects to be loaded a part at a time.)

The yet to be written data monitor will be called each time an object is
accessed in any way. It can pass this on to log systems, try to predict what
objects should be pre loaded, and so on.


Client API
==========
On an incoming request, this verifies the existance of the object in the
cache, possibly waiting until it is loaded from the database, and the cache
must lock the object in. Once the object is verified, the code to process
the request is allowed to be called. (Security code can interrupt at this
point, returning appropriate exceptions.)

The main code will use the cache for reading and writing data, and the OQL
module for processing queries (such as the contents of a list field.) The
method handling module will handle method calls in an object.

When the method completes, the object must be unlocked in the cache. (Note:
the ServantLocator code can handle this.)


Object Store
============

Executes queries created by the OQL code. Returns result data which is a
standardised form for all supported databases. This data will be a table,
with a structure that reflects the query generated, or a success/failure
result for queries other than 'select'.

Code needs to know the fields that were requested in the query - however,
the querydata created by OQL code should be able to store this, so the code
can then go:    (rough pseudo python code)

   for r in all_rows:
      for f in r.fields:
          cache.insert( q.class , f.name , f.value );


