Hi Tomas,

> (setq *List (; *ID it))
> (when (nth *List *Bubble)
>    (xchg @ (cdr @)) )
> (put!> *ID 'it *List)
> (commit)

This is correct in principle, but will not work here.

The problem here is that 'put!>' always tries to detect whether the new
data are different from the current state of the object. If not, nothing
is written. Otherwise, the object is modified and set to a "dirty" state
so that on subsequent 'commit's it is written to the file. (The 'commit'
is implied in the '!' versions of these functions)

If we use 'xchg', the 'it' list is modified destructively, so that
'put!>' later will believe it did not change at all.

In such a case we can use 'touch' explicitly (which is not necessary
normally). We might do (we can also omit the global '*List' here):

   (when (nth (; *ID it) *Bubble)
      (xchg @ (cdr @))
      (touch *ID)
      (commit) )

Usually, when the DB is used by multiple users or processes, we must
call (dbSync) before the change, and (commit 'upd) after. These two
things are done by 'put!>' internally. So the correct solution would be:

   (when (nth (; *ID it) *Bubble)
      (xchg @ (cdr @))
      (touch *ID)
      (commit 'upd) )

Note that 'put>' is not needed, as the list is already modified and set
to dirty.

If we insist to use 'put!>', we must use a non-destructive way to modify
the list:

   (let L (; *ID it)
      (put!> *ID 'it
            (cut (dec *Bubble) 'L)
            (cons (cadr L) (car L) (cddr L)) ) ) )

This last version is more "standard", but I would go with the 'xchg'
version (it is more clear, I believe).

> but what about locking and maybe other stuff?

The database is locked and synchronized between different (child-)
processes if (dbSync) and (commit 'upd), or 'put!>' is used.

This does not prevent some user, however, to modify the database while
the old state is still visible in the browser of another user. It will
not put the database into an inconsistent state, but the first user's
changes will be lost. That's why the 'form' GUI uses the Save/Edit
button mechanisms.

> Also, I have seen put!> being used to set "simple" relations but is it
> intended for lists?  How would that impact +Joint relation etc.?

It works as well for lists (as you can see in the example above). You
can either

   (put> Obj 'it '(list of it-objects))


   (put> Obj 'it 'single-it-object)

In the latter case the relation daemons will take care of inserting the
single object into the list.

> Also, if the db is big and the list is really long, isn't there a
> mechanism avoiding fetching the whole list from db and just swapping
> the two objects? Or, maybe I am worrying about it too much and it will
> turn out really simple? ;-)

I think you will usually not put a very long list of +It objects into a
single +Cat object. This would indeed be very inefficient, and also
difficult to handle. And no, there is no way to fetch only part of an
object from the DB.

Practically, I don't think this situation will arise. If you know that a
+Cat has very many +It objects, you would not use a mutual +Joint, but
an indexed +Link:

(class +Cat +Entity)
(rel nr (+Need +Key +Number))
(rel nm (+Ref +String))

(class +It +Entity)
(rel nr (+Need +Key +Number))
(rel nm (+Sn +Idx +String))
(rel cat (+List +Ref +Link) NIL (+Cat))

Generally, a +Joint on both sides is equivalent to a (+Ref +Link) on one
side. With that, you can also navigate in both directions, from +It to
+Cut in the same way, i.e.

   (get '{It} 'cat)

and from +Cat to +It using the index, e.g.

   (collect 'cat '+It '{It})

In this case there is virtually no limit of the number of +It objects assigned
to a +Cat object.

- Alex

Reply via email to