[TransWarp] SkinScript-to-Jars phrasebook, deleting objects, and
Phillip J. Eby
pje at telecommunity.com
Sun Jun 30 16:10:46 EDT 2002
Most SkinScript declarations can be rewritten as Python code inside one of
the methods of AbstractJar. The main difference in execution model between
ZPatterns and PEAK for attribute storage is that ZPatterns allows
attributes to be computed on-demand, while PEAK (actually ZODB) requires
that all an object's attributes be computed at once. It's just that
attributes which are other persistent objects can be "ghosts", whose class
is known but whose state/contents may not be.
So translating from SkinScript to PEAK persistence using Jars will be done
by combining all SkinScript declarations into Python code in jar methods
according to the following chart:
Abstract method ZPatterns/SkinScript Equivalent
load() WITH ... COMPUTE ...
defaultState() INITIALIZE OBJECT WITH ...
new() WHEN OBJECT ADDED ...
save() WHEN OBJECT CHANGED STORE attrs USING ...
ghost() no real equivalent
thunk() rarely used mix of attribute exprs and trigger code
You'll notice there's also no direct equivalent to WHEN OBJECT
DELETED. There are two kinds of situations where an object would be deleted:
* An object "belongs" to another object, i.e., it is at the child end of a
composite association, and the link to/from the parent is broken, implying
deletion. This should be handled in the "save()" method of the jar on the
child side of the association. If it sees the child object no longer has a
parent pointer, it should respond by deleting its associated data record
(not to mention any of its owned children in outgoing composition
links). This is easiest if the database supports ON DELETE CASCADE
constraints, but it can also be done manually.
* The other possibility is that a top-level (i.e. not a child of anything)
object is to be deleted. This can be handled by a Specialist method which
delegates to something in the data layer, or by mapping a domain-level
attribute such as "active" or "deleted" to the necessary action in save().
As you can see, neither of these situations can be clearly expressed as a
standard method to override in the jar, because the triggering conditions
vary so widely. In the absence of a uniform way to express "delete this"
at the application level, adding logic in 'save()' will have to do. Of
course, once we get to having jars that are driven by metadata, the
composition situation should be handled automatically, and we'll probably
have some way to configure to configure a signal to indicate the top-level
Hm. It may be that we should add something to peak.model.Element to be
able to tell it to delete itself, walking all its reference/collection
features and clearing them...
Anyway, object deletion is rather messy. One particularly messy bit is
that unlike object creation, you can't guarantee operations will be issued
to the DB in an order that's compatible with (undeferred) referential
integrity checks, unless you have cascade deletion support or hardcode the
In any event, I've written up a preliminary version of a
'peak.storage.jars' module with an AbstractJar class, and in the process I
found a few minor issues that weren't covered in the design so far. For
example, I needed a 'commitInProgress' flag in order to ensure certain
invariants held true even when a save() operation during a top-level commit
ends up modifying a persistent object that has already been committed.
Nonetheless, the implementation looks pretty good at about 247 lines of
heavily commented code. I haven't checked it in yet, mainly because
there's still some ambiguity as to where it should live in the PEAK package
'peak.storage' as a top-level package doesn't sound bad, and a lot of the
DB-related stuff I wanted to cram under 'peak.deployment' would probably go
better there. I'm just not sure if Jars should actually be Racks or PDM's
or some other such thing, in PEAK nomenclature.
More information about the PEAK