moellus - a rich and soft layer on Durus -------------------------------------------------------------------------------- Copyright (C) 2005 Mario Ruggier, All rights reserved Author: Mario Ruggier, mario@ruggier.org URL: http://ruggier.org/software/moellus/ License: GNU LGPL, http://www.gnu.org/copyleft/lesser.html -------------------------------------------------------------------------------- $Id: README.txt 134 2005-11-15 09:34:33Z mario $ -------------------------------------------------------------------------------- Moellus is a layer on top of the Durus Object Persistence System for Python, providing simple relational-like object model semantics for quick and easy development of an object model. Moellus is Durus-centric, in terms that it uses features specific to Durus, while at the same time being relational-friendly, in terms that objects are organized in dedicated containers. Moellus may therefore be useful for prototyping an object model, in a naturally object-oriented and pythonic way, while implying that the resulting object model might be mapped to a relational implementation, in a rather obvious way, should that ever be deemed to be necessary. With the minimal superimposition of a conceptually tabular organization on an object graph, moellus combines the advantages that are typical of object-oriented databases, such as natural references and transparent persistency. with some very convenient ones that are typical of relational databases, such as indices and querying capabilities. This without any additional layers, such as an object-relational mapper, that typically are needed to achieve the same thing. Moellus follows pretty much the Durus philosophy, that is to implement only what is needed for the kind of problems being addressed, that specifically are database applications where the quantity of data to be treated is not unlimited, are not write-intensive, and where the loaded data should be very "manipulable". Furthermore, there is no integrated type or referential integrity checking, as, besides the effort required to implement it, this rather expensive runtime overhead is in some cases better handled elsewhere and/or selectively. There is in fact no type declarations for attributes as yet. Another point that may be worth mentioning is that moellus does not attempt to hide the Durus db interface, and in general the implementation stays clear of all things that "belong" to durus, such as the Persistent.__new__ method. Requires - Python 2.3 - Durus 3.0 - Quixote 2.2 (for the accompanying small web application) Installation is standard distutils: $ cd $ sudo python setup.py install Main Features - A moellus database is a durus database that is organized such that all instances are either subclasses of moellus.database.PersistentContainer or of moellus.database.PersistentItem. The keys of the durus db root PersistentDict instance are the string classnames of subclasses of PersistentContainer. And each container instance contains only instances of a subclass of PersistentItem. - Item values are accessed via properties, that for the large part are automatically generated from the information provided by the moellus magic class attributes (those starting with "__m_"). If a custom implementation is provided for a property, then it is used. The automatic "make up" of classes is performed when a model is imported, via the call to moellus.database.makeup_m_classes(model_module) at the end of the model module itself. - Attributes of PersistentItems may be either simple (attrs) or a durus ComputedAttribute (cattrs). Furthermore, simple attrs may be also declared as an enum (enums). - PersistentItems may provide a special keybinding tuple, containing an ordered list of attribute names that uniquely identify each item -- thus a mutable compound primary key. Attributes in the item's keybinding must be defined when an item is added to the container, but are mutable at any time (as long as uniqueness is respected). Attributes used as keybindings may be of any type, i.e. attr, enum attr, or cattr. The corresponding index (see below) is updated automatically by the container. - The invalidating of cattrs is handled automatically, when a source attr of a cattr changes value. This also works for cattrs that derive their values from other cattrs. - There are a few predefined cattr types, that may therefore be used simply by declaring them as such. These include: - inverse for 1:1 relationship - inverse for 1:* relationship - PersistentItem classes may inherit from other PersistentItem classes (or any other classes), with proper automatic handling of moellus magic attributes. - PersistentContainers provide methods to add, get, del items, as well as to manage indices -- of which two are defined by default, one is based on the automatically managed "id" attr, and the other is based on the keybindings tuple (of attr names) that is defined by the class for the item. - In addition to the indices provided by default, PersistentContainers allow for the addition of custom indices as needed. An index should be thought of as a "mutable compound primary key" for the items in the container. - A moellus database can be browsed (very simplistically) via a quixote web application. - A few miscellaneous utilities are provided, to help with managing model changes, data migration, etc. Notably: - utils.clone_db() - utils.rebuild_indices_db() Class essentials: Database, PersistentContainer, PersistentItem In addition to PersistentContainer and PersistentItem, there is also a simple Database class that is essentially a wrapper over a Durus database connection. For more information see the source for the demo model, as well as the comments in the source for moellus/database.py. There is also an optional ConnectionCache singleton class provided, for the convenience of managing durus connections. For usage see the sources for the demo and the module itself. The class attributes starting with "__m_" are moellus magic attributes, that provide information allowing to automate numerous tasks. Database connection root get_container(cls_name) set_container(cls) setdefault_container(cls, minimum_degree=16) PersistentContainer __m_item_classname__ = 'PersistentItem' item_cls = None # set dynamically when model is imported index_keys index_attrs # derived property allowed_item_attr_names # derived property add_item(item, ignore_if_exists=0) del_item(item) get_item(item_key, index='id') get_items() gikb(item_keybinding) # get item by its keybinding get_item_key(item, index_key) get_index(index_key) has_key(item_key, index_key) add_index(index_key) rebuild_index(index_key) PersistentItem __m_container_classname__ = 'PersistentContainer' __m_attrs__ = {} # attr name: default value __m_cattrs__ = {} # cattr name: dict of cattr name/values __m_keybindings__ = () # attr names, value tuple must be unique __m_enums__ = {} # attr name: list of values id # automatically set on add container # automatically set on add Demo The demo does the following: - Defines a rather simple model, providing a sample of most of the features. The file HRModel.pdf contains the UML class diagram (approximately) for the model. The file hr_model.py contains the moellus implementation of the model. - Provides some sample data, to instantiate a database for this model, that is done by running: $ cd /demo $ python hr_sampledata.py This will generate the durus db file: ./data/hr_db.durus. - Provides a small quixote web application to browse the database. To run it (after having generated the db file, from previous step) do: $ python run_server.py For Future Consideration - Add type information, and incorporate a non-intrusive mechanism to do type and referential integrity checking. - Evolve the moellus db web application, to allow in particular manipulation of items. - Sort orderings (non-unique indices). - A "where" option, for convenient selecting of items in a container. - Segment db, with each segment being defined by a schema. - Consider supporting arbitrary objects (not part of a moellus schema), to live nicely alongside moellus Container and Item objects, e.g. be taken into account when cloning the db. - Give PersistentContainer the container interface (need: __len__, __setitem__, __getitem__, __delitem__): http://docs.python.org/ref/sequence-types.html -------------------------------------------------------------------------------- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details: http://www.gnu.org/copyleft/lesser.html A copy of the GNU Lesser General Public License (version 2.1) is included in the file COPYING. --------------------------------------------------------------------------------