Skip to Content

Moose and KiokuDB, one week in Syndicate content

Dave Sherohman's picture

As mentioned in my last post here, I've recently started in on a free-time project to teach myself some of the more-currently-popular modules that I haven't been using. So far, that means Moose and KiokuDB. Moose has been coming along pretty readily so far (I'm not entirely sure whether that's because of MooseX::Declare or in spite of it), but KiokuDB has had me scratching my head quite a bit and sent me off to IRC twice for help.

The first trip to IRC was brought on by my attempt to load-or-create an object with a specific ID, then later save it (with that specific ID). My first attempt looked something like

my $dir = KiokuDB->connect('dbi:SQLite:dbname=test.db', create => 1);
my $scope = $dir->new_scope;

my $supply = $dir->lookup('water') || Lillon:::Supply->new('water');
$supply->adjust_quantity($amount);
$dir->store(water => $supply);

Worked great the first time around. Didn't do so well the second time, though, as it failed with a complaint that there was already an object with the ID 'water'. Given that the docs on ->store say that it "inserts or updates the entries", I was expecting it to insert the entry at 'water' if it didn't exist or to update 'water' if it did. Leaving the ID out and just using $dir->store($supply) worked fine for re-storing a loaded object, but was no good for the initial create, since it didn't let me specify the ID to save it under.

I managed to work around this by doing the load and the create separately and setting a flag to track whether I'd loaded or created it, but that was hardly satisfactory, so I asked #kiokudb and got this solution:

if ($dir->object_to_id($supply)) {
  $dir->store($supply);
} else {
  $dir->store(water => $supply);
}

While it avoids the flag, I'm still not entirely happy with it. There are reasons why Kioku can't be relied on, in the general case, to store a new object under an existing ID, but the fact that it can re-store an object under its original ID without needing the ID to be restated (i.e., $dir->store($supply)) implies that it should be possible for it to determine whether the existing object with the ID and the object now being stored at that ID are the same object or not and, if they are the same object, do an update instead of attempting (and failing) to create a new entry there.

And the second stumper? I think I'll save that for my next post. This one is already long enough and it's so rare for me to have things to write about which actually seem worthwhile to me that I don't want to use them all up at once...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

insert vs. update

Anonymous's picture

The different between an update and an insert is explicit because otherwise you could accidentally overwrite data very easily.

Technically it is possible (and in fact SimpleDB and MongoDB both *fail* the test that ensures that insert will not overwrite existing data ;-), but there is no API for it (at least not yet).

A few more comments:

In my code I've always used KiokuDB::Role::ID for objects which have a meaningful primary key, which means that $dir->store($supply) would know to store under the id 'water' automatically.

Secondly, I always try to pre-seed data to make the find-or-create case less common, and if I do have a find-or-create requirement I usually write that once in my KiokuX::Model subclass as some explicitly named method (e.g. $model->get_water()).

The combination of these two things made it such that I have not really felt a need to figure out an API for overwrite yet.

Stealing my thunder

Dave Sherohman's picture

Your suggestion in IRC of KiokuDB::Role::ID when I was asking about objects that know their IDs is the central point in my planned followup to this post, I just hadn't gotten to it yet...

The reason that come up in the original IRC conversation about this topic for why in-place replacement wasn't possible was that not all objects are blessed hashrefs, so, in the broadly general case, it's possible that the old object and the new one may be implemented in fundamentally incompatible ways, making in-place replacement unreasonably difficult to do reliably.

I've added KiokuX::Model to my list of things to check out as I continue my exploration. Thanks for mentioning it.

Oops, sorry ;-)

Anonymous's picture

I don't think it devalues the next post though ^_^