Baby Moose in the Field

Back to the Field day here in the Moose-Pen

Today I am going to give params and containers a miss and move back into the '30_fields.t' test that I left alone so long ago. One of the planned concepts in Database::Accessor it the ability to have static data as part of the elements array. This is accomplished by using the 'Param' class in place of the “Element' class so you could do an SQL like this


SELECT 'User Name:', username, 'Address:', address FROM user

Why one wold want to do that I am not 100% sure on though I have seen it done in the past like the above for a reporting purposes. I could just simply make the Driver::DBI code insert the scalar values when it detects them but then I would be opening myself up to the good old 'Little Bobby Tables' problem. Fortunately DBI can handle that with a simple bind like this;

SELECT ?, username, ?, address FROM user;

Now my new test is;

$da = Database::Accessor->new(
{
da_compose_only => 1,
view => { name => 'user', },
elements => [
{ value => 'User Name:' },
{ name => 'username', },
{ value => 'Address:' },
{ name => 'address', },
],
conditions => {
left => {
name => 'username',
view => 'user'
},
right => { value => 'Bill' }
}
}
);
$da->retrieve( $utils->connect() );
ok(
$da->result()->query() eq
"SELECT ?, user.username, ?, user.address FROM user WHERE user.username = ?",
"Scalar field bind SQL correct"
);
cmp_deeply(
$da->result()->params,
['User Name:','Address:','Bill'],
"Scalar field in params correct"
);

Now my first run though this will follow the most common path the 'select/retrieve' and on my first run of the test I get;

Can't locate object method "no_retrieve" via package "Database::Accessor::Param" at GitHub\database-accessor\lib/Database/Accessor.pm line 717.

Which means that I have to have a look at the sub 'get_dad_elements' in Accessor.pm first. Now in this sub I am simply iterating over all the passed in elements and adding them to the '@allowed' if they are to be passed down to the DAD for processing.

In this case I just have a 'Scalar' value which is wrapped in the 'Param' class, all I have to do is this;


private_method get_dad_elements => sub {
my $self = shift;
my ($action,$opt) = @_;
my @allowed;
foreach my $element (@{$self->elements()} ) {
++ if (ref($element) eq 'Database::Accessor::Param'){
++ push(@allowed,$element);
++ next;
}
next
if (exists($opt->{only_elements})
and !exists($opt->{only_elements}->{$element->name}));
next


Check the in-comming element to see if it is an 'Param' then push it to '@allowed' and 'next' to carry on.

After I added that in I get
...
ok 4 - Scalar field bind SQL correct
ok 5 - Scalar field in params correct

Now that leads us to the other three actions; 'create', 'update' and 'delete'. Now in a delete there are never any fields, so that is out. In an update you cannot 'update' a field that does not exits and the same for a 'create' so this add on is all we need;

if (ref($element) eq 'Database::Accessor::Param'){
-- push(@allowed,$element);
-- next;
++ push(@allowed,$element)
++ if ( $action eq Database::Accessor::Constants::RETRIEVE);
++ next;

No need to test this in ' 30_fields.t' I will have to add a test in Database::Accessor so I opened up

and added the following;


push(@{$in_hash->{elements}},{value =>'static data'});
$da = Database::Accessor->new($in_hash);
$da->create( Data::Test->new(), {test=>1} );
$dad = $da->result->error();
ok($dad->element_count == 1,"only 1 on create");
$da->retrieve( Data::Test->new() );
$dad = $da->result->error();
ok($dad->element_count == 4,"4 Elements on retrieve");
$dad = $da->result->error();
ok(ref($dad->elements->[3]) eq 'Database::Accessor::Param','4th element is a Param class');
$da->update( Data::Test->new(), {test=>1} );
$dad = $da->result->error();
ok($dad->element_count == 1,"only 1 on update");
$da->delete( Data::Test->new() );
$dad = $da->result->error();
ok($dad->element_count == 0,"none on delete");

I just add in a scalar param and then check that it only shows up on the 'retrieve' to my surprise I got this;

not ok 1 - View taked from DA view name
...
ok 14 - last_name is index 0
ok 15 - only 1 on create
ok 16 - 4 Elements on retrieve
ok 17 - 4th element is a Param class
ok 18 - only 1 on update
not ok 19 - none on delete

opps a bug or two in there. The first one I think is just a bad test;

my $da = Database::Accessor->new($in_hash);
ok($da->elements->[0]->view eq 'People', "View taked from DA view name");
my $return = {};

I no longer set the view up in the ' around BUILDARGS' sub so I just need to set that to look at the returned DAD;

my $da = Database::Accessor->new($in_hash);
--ok($da->elements->[0]->view eq 'People', "View taked from DA view name");
my $return = {};
my $dad = $da->result->error(); #note to others this is a kludge for testing
++ok($dad->elements->[0]->view eq 'People', "View taked from DA view name");

Now the next bug I am breaking my promise to the DAD someplace as I am passing in elements that are not needed and it is a quick fix for that in the 'execute' sub where I pass down the elements;

my $dad = $driver->new(
{
view => $self->view,
-- elements => $self->get_dad_elements($action,$opt):[],
++ elements => ($action ne Database::Accessor::Constants::DELETE) ? $self->get_dad_elements($action,$opt):[],
conditions => [@{$self->conditions},@{$self->dynamic_conditions}],
links => [@{$self->links},@{$self->dynamic_links}],

just need to check the action first and now I get 100% pass.

I think I am going to have to have a quick full run of all the tests to make sure I have not broken anything else over the past little while. But that is for tomorrow's post.

ss87-4.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