[elephant-devel] Database evolution (i.e. schema migration)
Alex Mizrahi
killerstorm at newmail.ru
Fri Jul 9 07:56:51 UTC 2010
RD> For example, when a new slot is introduced it is unbound in existing
RD> instances. I will often set the slot value to nil in the migration
RD> function. Other times I will need to query the web for the correct
RD> value for existing objects' new slots.
Here's how I do it (my-persistent-object is root class for all my persistent
objects):
(defmethod slot-unbound (class (instance my-persistent-object) name)
;; when we've got unbound slot
;; try reinitializing it with initform via shared initialize
(shared-initialize instance (list name))
(if (slot-boundp instance name)
;; if it becomes bound, call slot-value once again.
;; (I hope it does not get into loop.)
(slot-value instance name)
;; otherwise call next method which signals error
(call-next-method)))
Then it boils down to having correct shared-initialize which can fix
partially-initialized classes.
For most cases initform is enough, I think. Initform is a function and it
can do pretty much anything.
If you want to refer to instance in initform, you can do that through
special variables and shared-initialize :around
(defvar *current-instance* nil)
(defmethod shared-initialize :around ((instance my-persistent-object)
slot-names &key)
(let ((*current-instance* instance))
(call-next-method)))
Then initform you can refer to it:
(defpclass foobar ()
((foo :accessor foo-of :initarg :foo)
(bar :initform (+ 10 (foo-of *current-instance*)) :initarg :bar)
Or you can explicitly implement this stuff in shared-initialize methods, if
it doesn't fit into initform somehow.
Of course, this method implies that unbound slots are not possible in
healthy instances.
I haven't yet seen the case where I want slot to be unbound...
RD> The desire is to define a migration framework that satisfies the
RD> following criteria:
RD> * the database should keep track of the version of its schema.
Elephant 1.0 does this and it implements scheme evolution in some way.
But, honestly, I didn't look into it in details.
Check schema.lisp and schema-evolution.lisp.
RD> Perhaps the most straightforward implementation would be to introduce
RD> a new means of defining persistent classes and their indices more
RD> explicitly, instead of letting defclass do all the work.
Hmm, I think the whole point of Elephant is that it is a CLOS persistence
and classes are defined via defclass.
It is actually good that you don't see how class definition was changing
over time -- you see only current class definition.
And code which translates old instances to new ones -- that can be a
separate _temporary_ layer.
RD> Instead of adding ":index t" to a slot definition, you would instead
RD> define a migration and call (add-index-for-slot (find-class 'user)
RD> 'telephone-number).
This is too close to SQL :)
Which is not necessarily a bad thing, but if you want to do it in SQL style,
won't it be easier to use SQL directly?
More information about the elephant-devel
mailing list