Moose Down the API hole

Still API day here in the Moose-Pen.

The first thing I did today was save all my work to github and create a new branch so I can work on that trigger idea I had yesterday.

This time out no need to write a test first my present test cases should be all that I need so I can dive right into the code today;

The fist code change I made was to comment out all the code that relates to the '' call for dynamic attributes, not need for that here. Next I changed the name of the trigger function;

-- sub _check_elements_present {
++ sub _check_dynamic {

Then I added this line to all four dynamic attributes

trigger => \&_check_dynamic

I adjusted that '_check_dynamic' like this';

sub _check_dynamic {
my ( $self, $child ) = @_;
my @check_elements;
return 1;

then ran the '40_dynamic_not_present.t' test case just to see if I can use one trigger for all of those attributes. The result wad correct as my waring printed out;

child=ARRAY at ...
child=Database::Accessor::Gather at ...
child=Database::Accessor::Gather at ...
child=Database::Accessor::Gather at ...
child=ARRAY at ...
child=ARRAY at ...
which is my expected results. What the above it reflecting is the fact that the 'dynamic_gather' is a singliton 'Gather' class where all of the other attributes are ArrayRefs of classes, good to know.

Now my new check_dynamic sub starts out like this

sub _check_dynamic {
my ( $self, $child ) = @_;
my @check_elements;

if (ref($child) eq 'Database::Accessor::Gather'){
push( @check_elements, @{$child->view_elements})
push( @check_elements, @{$child->elements})
push( @check_elements, @{$child->conditions})
else {
push( @check_elements,@{$child});

and now the next thing I want to do is reset the parens and conditions Counter attributes and then call the


Now the only problem with the above so far is I had to send “” down to '_elements_check' rather the the $action I did before so I do not know what action the error may be in. Will have to fix that later.

What the '_ elements_check' sub should do is set all the 'view' attributes of any elements present in the array and it should die if a there is a missing parentheses or if there is a 'condition' missing between two or more 'condition' elements.

Now that I have all the elements present I think I can add in my check to see if the passed in element is present in the 'elements' attribute of the DA. To do this I have to check not just against element 'name' but 'view' as well.

One problem is the 'Link' class the 'view' of any elements in that class inherent from the 'alias' attribute and this is set in the 'BUILDARGS' sub of that class. This will run well before one can do a 'add_link' therefore I could run into condition where a legitimate link/join fails due to that alias.

I think I need a new attribute or at least a sub to help me out. I ended up adding this to the 'Element' class

has '_lookup_name' => (
is => 'ro',
isa => 'Str',

sub _build_lookup_name {
my $self = shift;
return $self->view.$self->name;


Now the great thing about a 'lazy' build is once an attributes is set via an init_argument the builder will not fire. So now on the around BUILDARGS of Link/Join I can do something this;

$ops->{_lookup_name} = $lookup_view.$ops->{name} ;

where earlier in the code I set ' $lookup_view' to be the value of the 'view' attribute of the 'Link/Join' thus overriding the builder value.

Now I need a way to use that new attribute for the look-up and I will add in this sub;

sub get_element_by_lookup {
my $self = shift;
my ($lookup) = @_;
warn("get_element_by_lookup $self lu=$lookup");
my $found = $self->_get_element_by_lookup(sub { if (!defined($_->_lookup_name)) {return 0} $_->_lookup_name eq $lookup});
return $found;

and a link back to the attribute in the 'Database::Accessor::Roles::Common' role;

has elements => (
isa => 'ArrayRefofElements',
is => 'ro',
traits => ['Array'],
handles => { element_count => 'count',
_get_element_by_name => 'first',
_get_element_by_lookup => 'first'

now I think all I have to do next is add in the patch to the '_check_element' sub

private_method _check_element => sub {
my $self = shift;
my ($element,$right) = @_;
if (ref($element) eq 'Database::Accessor::Element'){
unless ( $element->view() ) {
$element->view( $self->view->name() );
++ 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_lookup($element->_look_up()));
elsif (ref($element) eq 'Database::Accessor::If'){

and I run my '40_dynamic_not_present.t' test case just to see how things are coming together, and I get;

ok 1 - method add_condition attribute->condition is only allowed to have elements that are in the
ok 2 - method add_gather attribute->view_elements is only allowed to have elements that are in the
ok 3 - method add_gather attribute->elements is only allowed to have elements that are in the
ok 4 - method add_gather attribute->conditions is only allowed to have elements that are in the
not ok 5 - method add_link attribute->link is only allowed to have elements that are in the
ok 6 - method add_sort attribute->sort is only allowed to have elements that are in the elements

Wow only one fail?? On the 'Link/Join' and I think I know why a a 'Link' is a collection of objects that may have conditions, I am just skipping over the 'conditions' attribute of the link.

I think this patch to the '_check_element' sub will fix that;

elsif (ref($element) eq 'ARRAY'){

foreach my $sub_element (@{$element}){
++ elsif (ref($element) eq 'Database::Accessor::Link'){
++ foreach my $sub_element (@{$element->conditions}){
++ $self->_check_element($sub_element,0);
++ }
++ }
else {

and when I run the test I now get;

ok 5 - method add_link attribute->link is only allowed to have elements that are in the

That's better.

Now how-many other tests have I in-validated?

Oh well!

I am lucky it is my testing day tomorrow.

inside pulling out midway 2.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