Moose in a Dark Place

Still stuck in error land in the Moose-Pen.

As I finally got the 'add_condition' to work I still needed to add in a few more tests for the other three 'dynamic' attributes, gather, link and sort.

Well I started with the easiest first 'sort' and on the 'undef' I am getting the now very familiar;

Attribute (name) is required at D:\GitHub\database-accessor\lib/Database/Accessor/Types.pm line 348
It did not take me very long to back track this one to the '_element_coerce' sub in my 'Types' class; As this had the same sort of fall though 'if' case like '_predicate_array_or_object' I at first added my check for undef code in the final 'if' of that statement;

...
 else {
       unless ($hash) {
                my ( $package, $filename, $line, $subroutine ) = caller(4);
                $subroutine =~ s/Database::Accessor:://g;
                my $add = substr($subroutine,4,length($subroutine));
                my $die =
                 MooseX::Constructor::AllErrors::Error::Constructor->new(
                    caller => [ $package, $filename, $line, $subroutine ], );
                $die->add_error(
                    MooseX::Constructor::AllErrors::Error::Misc->new(
                        {
                                message => "Database::Accessor "
                              . $subroutine
                              . " Error:\n"
                              . "You cannot add undef to dynamic_"
                              . $add 
                              . "! "
                        }
                    )
                );
                die $die;
       }
        if ( exists( $hash->{left} ) or exists( $hash->{right} ) ) {
            my %copy = %{ Clone::clone($hash) };
            delete( $copy{left} );
            delete( $copy{right} );
            $LAST = \%copy;

        }
        $object = Database::Accessor::Element->new( %{$hash} );
Silly me I actually though that would work but all I got was the same error;

Attribute (name) is required at D:\GitHub\database-accessor\lib/Database/Accessor/Types.pm line 371
except on a later line.
Well good old perl got me again as the earlier parts of the if statement;

    if ( exists( $hash->{expression} ) ) {
        $hash->{expression} = uc( $hash->{expression} );
        $object = Database::Accessor::Expression->new( %{$hash} );
    }
will automatiley convert the incomming 'undef' to an undefined hash ref '{}' so with what I have above will never work. I had to move the code to the top of the if block and check for undef with an 'unless'

  unless ($hash) {
                my ( $package, $filename, $line, $subroutine ) = caller(4);
                $subroutine =~ s/Database::Accessor:://g;
                my $add = substr($subroutine,4,length($subroutine));
                my $die =
                  MooseX::Constructor::AllErrors::Error::Constructor->new(
                    caller => [ $package, $filename, $line, $subroutine ], );
                $die->add_error(
                    MooseX::Constructor::AllErrors::Error::Misc->new(
                        {
                                message => "Database::Accessor "
                              . $subroutine
                              . " Error:\n"
                              . "You cannot add undef to dynamic_"
                              . $add 
                              . "! "
                        }
                    )
                );
                die $die;
    }
    elsif ( exists( $hash->{expression} ) ) {
…
and now I get that nice

Database::Accessor add_sort Error:
You cannot add undef to dynamic_sort!  at 42_new_validation.t line 87#
Now at this point I think I can do a little re-factoring before I move over to the other two 'dynamic_' adds. Before I did any refactoing I wanted to see what come out of a raw error on the above sub so I added in the test code to see what I get;

sub _element_coerce {
    my ($hash) = @_;
++  eval {
++  $object = Database::Accessor::Element->new( %{$hash} );
++  };
++  warn("Error ref is ".ref($@))
++     if($@); 
    my $object;
    $LAST = $hash;
and when I run my test again I get;

Error ref is MooseX::Constructor::AllErrors::Error::Constructon
which is just what I want to see as I can now reuse that '_one_error' sub in my 'AllErrors' role for this case. Now I just have to back track a little to the '_predicate_array_or_object' sub and start the re-factoring there. The first thing I tried was

             unless ($object) {
                 my ( $package, $filename, $line, $subroutine ) = caller(3);
                 $subroutine =~ s/Database::Accessor:://g;
                 $class      =~ s/Database::Accessor:://g;
                 my $die =
                   MooseX::Constructor::AllErrors::Error::Constructor->new(
                    caller => [ $package, $filename, $line, $subroutine ], );
                 $die->add_error(
                    MooseX::Constructor::AllErrors::Error::Misc->new(
                         {
                                 message => "Database::Accessor "
                              . $subroutine
                               . " Error:\n"
                               . "You cannot add undef to dynamic_"
                               . $class . "s! "
                         }
                     )
                 );
                 die $die;
             }
             push( @{$objects}, $class->new( { predicates => $object } ) );
and I got this;

Database::Accessor  Error:
The following Attribute did  not pass validation: 
'condition->predicates' Constraint: Validation failed for 'Predicate' with value undef (not isa Database::Accessor::Predicate)
With constructor hash:
{
  'predicates' => undef
}
 at  line 0
Which is a start at least I can pass down the correct 'class' and in '$opts' but I am not getting that nice udef error message with the correct line and file; I can fix the file and line numbers by passing in the caller level with this change in the _create_instance sub;

sub _create_instance {
--  my ( $class, $ops ) = @_;
++  my ( $class, $ops,$caller ) = @_;
…

--          my ( $package, $filename, $line, $subroutine ) = caller(12);
++          my ( $package, $filename, $line, $subroutine ) = caller($caller);
 
and this change in '_predicate_array_or_object';

-- push( @{$objects}, _create_instance( $class, { predicates => $object }));
++ push( @{$objects}, _create_instance( $class, { predicates => $object },4));
What to note here is I bumped up the call level one to account for fact I am going to a deeper sub. On my next run I get;

...
at 42_new_validation.t line 88# 
so the correct file and line #. Now for the message; This proved to be very tricky as I could get this out whith undef;

Database::Accessor add_condition Error:
You cannot add 'undef' with add_condition at 42_new_validation.t line 85
however on my next test;

 $da->add_condition( {
                leftx => {
                    name => 'last_name',
                    view => 'People'
                },
                 operator => undef
               });
I was getting this message;

Database::Accessor add_condition Error:
With constructor hash:
{
  'predicates' => {
                    'operator' => undef,
                    'leftx' => {
                                 'view' => 'People',
                                 'name' => 'last_name'
                               }
                  }
}
 at 42_new_validation.t line 92
I should really be getting on2 like this;

Database::Accessor new Error:
The following Attribute is required: (conditions->left)
The following Attribute did  not pass validation: 
'conditions->operator' Constraint: The Operator 'undef', is not a valid Accessor Operator! Try one of '!=', '<', '<=', '<>', '=', '>', '>=', 'ALL', 'AND', 'ANY', 'BETWEEN', 'EXISTS', 'IN', 'IS NOT NULL', 'IS NULL', 'LIKE', 'NOT EXISTS', 'NOT IN', 'NOT LIKE', 'OR'
With constructor hash:
...
I did not find a solution yet but I did figure out what the problem was. I have a little recursion bug going on. When I create a 'condition' class I use the '_create_instance' sub to create it. The problems arises because to create a 'condition' I also have to create a 'predicate' and I also use the '_create_instance' to create that class thus I have a failed eval in a failed eval call and I get two 'AllErrors' objects one that is created by the first eval and then goes away with the second eval; It did try a number of things even this bit of silliness

  my $error = do {
            local $@;
            eval { $object = $class->new( %{$ops} );  };
            $@;
        };
to try an localize the error just did not work for me at least this late at night.

image1233.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