Moose Crud May be done but API isn't

Its back to the API day here in the Moose-pen

As my practical tests against a real DB are humming along I noticed that I was missing some-thing quick basic on my API namely retrieving more that just a array-ref of data from the DB. Reading some of my earlier posts I did leave this part to latter so I better do it now before I get too close to my first release.

Now in the present Data::Accessor that Database::Accessor is based off of I noticed that I could pass in an optional $container on the 'retrieve' method and depending on the nature or the 'container' it would handle the results in different ways.

If it was not present that it just did as I do now return and array-ref of results. If a hash-ref was passed in then the the underlying DB would try to do a fetch for each key on the hash and the return an array-ref of hash-refs of the matched keys.

I could also pass an instantiated class down as a container and it would create a new object and set any of the matching keys and then return an array-ref of these classes.

So a sort of scattered API in the old system but useful.

Now on my latest incarnation my calling pattern for 'retrieve' is now;


$da->retrieve($db,$ops);

Just the $db and the $ops are allowed. Now the question here is how do I want to handle what is returned to the results class. Do I add it in here as an option like this

$da->retrieve($dbh,{result_as_hash=>1});

or

$da->retrieve($dbh,{result_as_class=>'Xtest::DA::People'});

Now the problem I see with this is that I will be constantly having to set that option each time I use retrieve if I want to use anything other than the present array-ref return. Therefore a high level option should be my route of choice. Now where to stick it and what to call it??

Now one thing I did discover from using the original Data::Accessor was that the feature to turn the result set into an array-ref of classes was used quite a lot but the manner in which it was used was not really compatible with more modern perl and Moose especially and lent itself to the use of an anti-pattern in some of the code-bases I examined.

Given that I want fairly modern API I think I will have to include JSON as a possible output as well. So far I have four


  1. Array-ref

  2. Hash-ref

  3. Class

  4. JSON


possible contents for my return set. Fortunlety there is a MooseX for this kind of thing 'MooseX::Enumeration', from 'Toby Inkster', and I will add it into the 'Database::Accessor::Roles::Common' role with the enumerations as follows;

use Moose::Role;
with qw(Database::Accessor::Types);
use MooseX::AlwaysCoerce;
++ use MooseX::Enumeration;
use namespace::autoclean;

++ has da_result_set => (
++ traits => ["Enumeration"],
++ is => "rw",
++ enum => [qw/ ArrayRef HashRef Class JSON /],
++ handles => 1,
++ default => 'ArrayRef'
++ );

has [
qw(da_compose_only


Now what I have set up if I have done things correctly is with that handels =>1 it should set up a serires of methods like this;

  • is_ArrayRef

  • is_HashRef

  • is_Class

  • is_JSON


that I can use in my DAD to figure out what sort of return is wanted. Right now I am not 100% sure how I am going to get the 'Class' to work I think I will have to supply another attribute to pass along.

However before I go too far along lets try a simple test;

The best place to start is good old '20_dad_load.t' and I just need to add a few things in;


my %read_write = (da_compose_only=>1,
da_no_effect=>1,
da_raise_error_off=>1,
da_warning=>1,
da_suppress_view_name=>1,
++ da_result_set=>1);


ok( $da->no_update() == 1, "Cannot Update" );
ok( $da->no_delete() == 1, "Cannot Delete" );
++ok( $da->da_result_set() eq 'ArrayRef', "Result set is an ArrayRef" );
++ok( $da->is_ArrayRef() == 1, "is_ArrayRef is true" );
++ok( $da->is_HashRef() == 0, "is_HashRef is false" );
++ok( $da->is_Class() == 0, "is_Class is false" );
++ok( $da->is_JSON() == 0, "is_JSON is false" );

ok( ref($da) eq 'Database::Accessor', "DA is a Database::Accessor" );


and on my test run I get;

...
ok 27 - Role DAD attribute: sorts is Read Only
ok 28 - Role DAD can da_result_set
...
ok 40 - Cannot Delete
ok 41 - Result set is an ArrayRef
ok 42 - is_ArrayRef is true
ok 43 - is_HashRef is false
ok 44 - is_Class is false
ok 45 - is_JSON is false


so all those are working as expected; Finally one more test for today and I will add this one in here

foreach my $type (qw(create retrieve update )){

ok($da_new->$type(Data::Test->new(),$container) == 1,"$type Query ran");
if ($type eq 'create' or $type eq 'update') {

}
++ else {
++ my $dad = $da_new->result()->error;
++ ok($dad->is_ArrayRef ==1,"DAD is_ArrayRef is true")
++ }


and this time round I am checking the DAD to ensure that the correct 'enumeration' is being passed down and the result is a pass as expected;

...
ok 62 - retrieve Query ran
ok 63 - DAD is_ArrayRef is true
ok 64 - update Query ran


Now to get this working with Driver::DBI but I guess that will be tomorrow's post;

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