[Persistence-sig] 'cucumber'

Titus Brown titus@caltech.edu
Sat, 17 Aug 2002 17:03:11 -0700


Hi everyone,

I thought I'd toss my own little package into the fray.  I've written
a fairly simple O/R mapping system named 'cucumber' that sits on top of
PostgreSQL.  By making use of PG's inheritance hierarchies, cucumber
class inheritance relations can be mapped directly into PostgreSQL
in a very simple and transparent way.

Currently there is a Python implementation, but I hope to have Perl and
Java interfaces soon; because all of the data is stored in the database,
and because the class files are quite sparing, it's entirely possible to
make cross-language data retrieval work.

cucumber is still quite young, but it's been used in three separate
projects (all mine, of course) and it seems to work quite well.  I'm
continuing work on it because it satisfies a couple of needs:

* cross-language access is potentially quite useful;
* access to a cucumber database can be done through straight SQL, without
	any Python/Perl/Java knowledge; you only need to be careful when
	creating tables;
* it's quite lightweight and easy to extend.

I don't regard it as mature -- I've labeled the current CVS version as
0.1.1, to give you an idea -- but I think it may contrast interestingly
with other approaches.

Some of the drawbacks of the package's immaturity and my own lack of
intelligence are:

* I haven't yet figured out how to get rid of SQL when building lists of
	objects (done via a "Catalog" class, which takes SQL WHERE clauses);
* the exception/error-reporting hierarchy is, umm, "not well developed";
* documentation is, of course, non-existent.

All in all, though, it works and works well for a quick hack of under
1000 lines of Python that most Python hackers could understand.

cucumber is checked into CVS at SourceForge, and I'm happy to 

To show you the basic flavor of things, you first create your various tables
in straight SQL:

--- example.sql

CREATE TABLE classes (
       id	     INTEGER PRIMARY KEY,
       name	     TEXT,
       description   TEXT
);

CREATE SEQUENCE object_unique_id;

INSERT INTO classes VALUES (1, 'example.BaseObject', 'base example object');
INSERT INTO classes VALUES (2, 'example.Fruit', 'fruit object.');

CREATE TABLE base_objects (
       id	  INTEGER PRIMARY KEY DEFAULT NEXTVAL('object_unique_id'),
       class_id	  INTEGER REFERENCES classes DEFAULT 1
);

CREATE TABLE fruits (
       class_id	  INTEGER REFERENCES classes DEFAULT 2,
       name       TEXT
) INHERITS (base_objects);

---

and then write a class file:

--- example/Fruit.py

from cucumber import Object

class Fruit(Object):
    table = 'fruits'

    mymembers = ('name',)
    myrefmembers = ()
    myobjmembers = {}

---

and finally, you use it:

-- run-example
#! /usr/bin/env python

import sys

# import the object manager
from example.ExampleManager import ExampleManager

# import a class to use
from example.Fruit import Fruit

# create an instance around the database 'cuc-example'
manager = ExampleManager('cuc-example')

#
# create a new Fruit
#

orange = manager.create(Fruit, name='orange')

orange_id = orange.id
manager.commit()                        # save it into the database

#
# load it back in from the id.
#

orange2 = manager.load(orange_id)
print orange2.name

--

Note that the object manager (here 'ExampleManager') is descended from
cucumber.ObjectManager.

Also, transactions etc. are managed through PostgreSQL and are subject to
PostgreSQL's transaction mechanisms -- no intelligence is used on the
part of the program.

And finally, no object caching is yet done, although I'm sure someone more
expert than me could do a good quick job of it.

cheers,
--titus