[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