Proper Moose

So carrying on from where I was yesterday in the Moose-Pen I played with a few ideas today on how to solve my problem of not being able to get dynamic attributes down to the DAD from my DA.

In my last post I had the example of a canned 'client' that I wanted to do this to


my $client_da = Data::Tier::Clients->new();
$client_da->add_conditions(...
$client_da->retieve($mongo,$into);
$client_da->retieve($dbh,$into);

I did play about with loading All the DADs at once so and I could accomplish this by do this by storing all the DADs in a new attribute, then I creates a 'add_conditions' sub where I passed these conditions down into the underlying DADs.

There where a few problems with this. First this is not a very thread safe as the DADs that where loaded in the initial Database::Accessor->new would be shared, unless I blessed each new one into its own handle in the same way DBI does. Not going to do that. Secondly I think I will have to add code to cleanup all the DADs dynamic code after all command as they as my DADs are now an instance attribute not a sub level value.

So drop that and onto my klunky interface.


  • Command

  • Dynamic conditions

  • Execute


When you look at DBI it does the same sort of thing

  • Connect

  • Prepare

  • Execute


So I did create some code for this and it looked like this;

my $client_da = Data::Tier::Clients->new();
my $dad = $client_da->retrieve($dbh,$container);
$dad->add_conditions({left =>{name=>'id',
...);
$dad->execute();

Not too bad and very close to the DBI pattern but not as smooth as I would like as the pesky $dad is being return and that may mean I would have to return a handle for this $dad to make it thread safe. As well I wanted a really clean one line interface which I suppose I could get by doing just this

my $client_da = Data::Tier::Clients->new();
$client_da->retrieve($dbh,$container,{conditions=>{left=>{
...

but I could see this getting rather annoying to the end user. Very long hash interfaces are fine for the underlying 'Data::Tier::Clients' package as that would not be worked on very much. I can't really see a end user adding in a 40 element hash to do a simple little filter, very hard to read and follow.

So in the end I just went with expanding my Accessor class with 'dynamic' attributes, like this


has dynamic_elements => (
isa => 'ArrayRefofElements',
traits => ['Array'],
coerce => 1,
is => 'rw',
default => sub { [] },
init_arg => undef,
handles => {
add_element => 'push',
dynamic_elements_count => 'count',
},
);

So now my end user need only

my $client_da = Data::Tier::Clients->new();
$client_da->add_conditions({left =>{name=>'id',
...);
$client_da->retrieve($dbh,$container);

and my DAD is a local var that will go out of scope quickly and is I hope thread safe.

In the above I also want to stop the person writing the ' Data::Tier::Clients' package from using 'dynamic_elements' as a new param and I do that by a little Moose command


init_arg => undef,

You will also see I make these a native array and get my nice little 'add_element' delegation for push, and a count delegation as well though I an not 100% set on the name yet.

In my code I also had to add into the map part of my code like this


Elements => $self->elements,
++ elements => $self->dynamic_elements,

and I then made all the attributes of my DAD role read only so they can't be changed by the underly call to the DAD. I though that might have been a problem but the DAD object is recreated each time so I never have to worry about unwanted params handing about.

Testing was easily in 31_elements.t I just added this


$da = Database::Accessor->new({view => {name => 'People'}});
foreach my $element (@{$in_hash->{elements}}){
ok($da->add_element($element),"can add an single Dynamic element");
}
$dad = $da->retrieve(Data::Test->new(),{});
Test::Database::Accessor::Utils::deep_element($in_hash->{elements},$da->dynamic_elements,$dad->elements,'Single Dynamic Element');

and on the first run I got

ok 8 - can add an single Dynamic element
ok 9 - can add an single Dynamic element
ok 10 - can add an single Dynamic element
ok 11 - DA Single Dynamic Element 0 correct
ok 12 - DAD Single Dynamic Element 0 correct
ok 13 - DA Single Dynamic Element 1 correct
ok 14 - DAD Single Dynamic Element 1 correct
ok 15 - DA Single Dynamic Element 2 correct
ok 16 - DAD Single Dynamic Element 2 correct

Cool not even getting name conflices so finally getting closer to finishing this off.

finish.jpg

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations