Forest, Trees and Handel 1.0

jk2addict on 2006-08-02T16:38:56

Warning: no-coherent think out loud rambling ahead.

I've been knee deep in refactoring for Handel 1.x. For the most part, it's going well and I've had to resort to minuscule amounts of magic to alter/enhance/molest DBIC schemas on the fly. The current progress can be found here.

It's been a long journey, mostly spent figuring out how to genericize the use of DBIC schemas away from the actual Cart/Order/Item classes. The Intro and Storage manual pages give a basic overview of how it is currently.

Unfortunately, I'm at a point where I can't see the forest any more because I've been staring at the trees too long. From the Storage perspective, I can call create/search methods, and get generic Storage::Result objects. it all works. Everything is happy.

my $storage = Handel::Storage::Cart->new({
    schema_class      => 'Handel::Cart::Schema',
    schema_source     => 'Carts',
    connection_info   => ['dbi:SQLite:handel.db'],
    item_relationship => 'items'
});

# returns Storage::Result object my $result = $storage->create({ shopper => 1, name => 'My Favorites' }); print $result->name;

# returns Handel::Iterator, that inflates to Storage::Result objects my $results = $storage->search; while (my $result = $results->next) { print $result->name; };


Where I'm having problems is trying to use the storage results from the top level classes without making any assumptions on where the results came from. Right now, it's all DBIC, but it could just as well be result objects from a custom storage layer.

package Handel::Cart;
__PACKAGE__->storage_class('Handel::Storage::Cart');

sub new { my ($self, $data) = @_; my $result = $self->storage->create($data); # creates a new Handel::Cart instance, storing storage result as needed return $self->create_instance($result); };

sub add { my ($self, $data) = @_; my $result = $self->result;

# which is worse here? my $item = $result->add($data); # or, where add_item in storage does $dbicresult->add_related('items', $data) $my $item = $self->storage->add_item($self->result, $data); # or $my $item = $result->storage->add_item($self->result, $data); ... };


My real struggle is one of relationships. In a DBIC world, I create a cart, then add items into the cart result itself using add_related(), instead of adding new items through the item->create pathway. That's a strange thing to try and abstract away from. Creating a new cart above is easy. Adding an item to that new cart can go many ways, and I'm not sure which way sucks worse than the others.

In a DBIC world, one would almost never add an item to the items table using the item schema class, and would almost always add an item through the cart->add_to_item or cart_add_related relationship. This means Cart is a first class citizen, and items aren't.

But above the DBIC level, abstracted away, I get the urge to treat the Items abstraction as equally as the Carts.

sub add {
    my ($self, $data) = @_;
    my $result = $result;

# like Handel::Cart::Item->storage->create($data) my $item Handel::Cart::Item->new($data); $result->storage->add_item($item); };


From an abstraction standpoint, this code makes sense to me. I'm creating a new item using the Item class/storage from top to bottom. But I lose all of the DBIC add_related and relationship magic. It sucks if I'm using DBIC. It's great if I'm going something like:

package Handel::Cart;
__PACKAGE__->storage_class('Handel::Google::CheckoutAPI::Cart');


If any of this makes sense to you. I'm sorry. I ramble, and I have too much code in my head the formulate sane questions. :-)

Thoughts?


I see the forest!!!

jk2addict on 2006-08-03T19:59:26

I think I finally got past my mental block. It's not the most elegant solution, but hey, I'm a double music major. What the hell do I know. :-)

The answer I settled on was: do both.
Handel::Cart::add {
    return $self->result->add_item($data);
};
...
$result::add_item {
    return $self->storage->add_item($self, $item);
};
...
$storage::add_item {
    return $result->add_related($self->item_relationship, $data);
};
So, people writing custom storage layers can either tweak behavour at the result level, or at the storage level, or both. A custom storage layer will know what to do with it's own stuff; be that adding through a relation on the result object, or adding a new item through a completely different storage object in the item class.

Famous last words. We'll see what happens when I try and write a Tutorial on how to write a custom storage layer. :-)