Still Suck in the API Moose
Its even more API Day here in the Moose-Pen
In yesterday's post I found a back door to fields in a DB that are not part of a Database::Accessor instance. I was able with this 'gather/group by'
da->add_gather({elements => [{name => 'user_id',
view => 'people'},
{name => 'salary',
view => 'people'}],
view_elements=>[{name => 'user_id'',
view => 'people'},
{name => 'salary',
view => 'people'},]
});
to select out all the salaries of the people in my DB. This is not a good thing if you want to keep you job for any length of time. In today's post I am going to implement a new validation/rule on my API where you can only add 'view_elements' that are part of the current $da instance.
First a test for the 47_dynamic_gathers.t test case.
$da->reset_gather();
$gather2 = {
elements => [
{
name => 'first_name',
view => 'People4'
},
{ name => 'salary',
view => 'People'
}
],
view_elements => [
{
name => 'first_name',
view => 'People4'
},
{
name => 'first_name',
view => 'People4'
}
],
};
like(
exception { $da->add_gather($gather2) },
qr /in not in the elements array! Only elements from that array can be added/,
"Elements not in the elements attribute are not allowed"
);
Now for some code. I am going to try and use a Moose attribute 'trigger' to get this to work; I will start with this;
has dynamic_gather => (
isa => 'Gather|Undef',
traits => ['MooseX::MetaDescription::Meta::Trait'],
description => { not_in_DAD => 1 },
is => 'rw',
++ trigger => \&_check_elements_present
);
the 'trigger' above will now call the sub each time a new items is added to the the 'dynamic_gather' attribute. Now I need to add in that sub;
sub _check_elements_present {
my ( $self, $child ) = @_;
my @check_elements;
push( @check_elements, @{$child->view_elements})
if($child->element_count);
foreach my $element (@check_elements){
die( "Gather view_element "
.$element->name()
." in not in the elements array! Only elements from that array can be added" )
unless ($self->get_element_by_name($element->name()));
}
}
In the above the '$self' will give me my Database::Accessor instance and the '$child' will give me the 'gather' class I am trying to add to. This fires after the add is done so I am quite sure any gather I add will be present.
What I do next is I load any 'view_elements' that are present into the '@check_elements' then I iterate over that array checking to see if each element is found in the 'elements' attribute with the 'get_element_by_name' sub. If I do not find it I will die.
For now I am just trying to get the above to work and throw the error. I do have in the back of my mind that I will have to expand this functions to cover off other eventualities.
Well lets run the test;
can't use an undefined value as an ARRAY reference a
That one again. You would think I would learn by now;
push( @check_elements, @{$child->view_elements})
-- if($child->count_elements);
++ if($child->view_elements);
with the patch above I gave it another go and got;
Gather view_element in not in the elements array! Only elements from that array can be added
I did get the die but my new test did not fire. Hmm.
The reason for the hard fail is the the test before the one above as one of the 'view_elements' is a function;
view_elements => [
{
name => 'first_name',
view => 'People4'
},
{
function => 'count',
left => { name => 'user_id',
view => 'People6'}
}
],
Ok I can kludge that quick;
...
foreach my $element (@check_elements){
++ next
++ unless(ref($element) eq 'Database::Accessor::Element');
die( "Gather view_element "
…
and now when I run my test I get;
…
ok 21 - elements 1 is a function
ok 22 - Elements not in the elements attribute are not allowed
Ok that is a good start for today. I do see I have some re-factoring to do. For one thing my 'get_element_by_name' searches only on name I might be able to sneak another element/field in there if the name is the same but the view/table is different.
A post for tomorrow I guess.
Leave a comment