On Thu, Oct 07, 2004 at 11:31:37PM +0900, Kirk Haines wrote:
> That's an interesting suggestion, as it gives one a defense against some 
> external process coming in and changing things unexpectedly.  Putting this 
> on my todo for Kansas!

That's another O<->R mapping engine? Looks like there's a big ecosystem to
choose from :-)

> > These 'old' properties might also be useful for object-level 
> > transactions, without serialisation as 
> > ActiveRecord/Transaction::Simple does.
> 
> In Kansas, it keeps each old value within the context of a transaction, but 
> after the transaction is committed, the old values go away.  I don't provide 
> any interface, however, for actually access the old values at any time.  Can 
> you elaborate more on ways that you would see the old values being used?  
> This is quite educational.

I think that once they're committed to the database, the old values are no
longer needed (and indeed, should be reset to the known current values in
the DB). The 'old' values represent a database snapshot at the last instance
that the DB was touched, and I think this is useful even before a
transaction starts.

My main worry is users A and B both pulling up the same record onto a
screen, making changes, and then writing back both; the one who gets there
first risks having their changes overwritten. Checking the old values have
not been changed as part of an atomic update is simple and robust, and
doesn't require record locking.

I wrote a system once which incorporated this concept, but since it had a
web interface, I think I ended up putting the 'old' values in hidden form
variables anyway.

> As for object-level transactions without serialization, I'm not sure about 
> AR, but with Kansas one can set a read-only attribute on data objects, and 
> can direct a query to return the data with the objects already in a read-
> only state.  While read-only is on, changes to the object will not get 
> serialized back to the db.

OK, I think perhaps we're talking about something else. With AR (which I've
only looked at briefly), you can make changes to an object within a
transaction, and if it fails, the objects themselves are rolled back to
their state at the start of the transaction. This is done using Austin
Ziegler's Transaction::Simple library, which just keeps a copy of the object
in marshalled form in an instance variable. It rolls it back using, in
outline:

    r = Marshal.restore(@__foo__)
    self.replace(r) if respond_to?(:replace)
    r.instance_variables.each do |i|
      instance_variable_set(i, r.instance_variable_get(i))
    end

I was just thinking that if you're keeping the properties in a hash, and
have a separate hash for their snapshot values, then you get this capability
for free:

    @props = @oldprops.dup

But it's not clear to me whether the best approach is to have 'obj'
containing both old and new values, or whether you should just have two
separate objects representing then and now:

    obj1 = $db.get(n)
    obj2 = obj1.dup
    ... make changes to obj2
    obj2.save(obj1)   # => generates SQL to update obj1 to obj2 atomically

Incidentally, talking about the OR ecosystem, I have some proof-of-concept
code which takes XML and stores it in SQL. It takes a stream of tag_start(),
element(), text(), tag_end() method calls (as generated by an
REXML::StreamParser), and writes rows in a DB. <foo>text</foo> ends up as a
single row. It can then spool out any subtree by doing a single 'select' and
converting this back into method calls; there are helper methods to turn a
method call stream into either XML text or a tree of REXML::Element objects.
The nice thing is that no intermediate representation is built in RAM, so
in principle you could spool gigabytes of XML in and out of SQL.

Dunno if anyone is interested in this... I was going to add a mechanism to
convert XPATH queries into SQL queries, and was starting to think about how
different element types could be mapped to different tables, at which point
it starts to look like an OR mapping solution. At the moment there are
just global 'elements' and 'attributes' tables. I will look at Kansas, AR,
NDB and others and see what good ideas I can steal from them :-)

But in principle an object with attributes should map quite nicely to
   <class attr1=val1 attr2=val2...>
Having a hierarchy can be useful too, e.g. for access control, where a
user can only "see" objects which are below them in the tree. And XML is
still useful as an export/import tool, even if most people on this list use
YAML anyway :-)

Regards,

Brian.