Moose Likes JSON

Its get back to 'da_result_set' to-day in the Moose-pen.

Getting back on track with 'da_result_set' I still have two JSON which should be quite straightforward and Class which could be problematic, so I am going to JSON first.

I will need a test first of course so the fist thing I will do is add that into '20_result_sets.t'


$da->da_key_case('Lower');
$da->da_result_set('JSON');
ok($da->is_JSON ==1,"return set is a JSON");
cmp_deeply( $da->result()->set->[0], $user_db->new_person_data->[3],"JSON returned with correct data");

In the above the first thing I do is reset the case back to 'Lower' then I do the same tests as I have done before and this this time I add in yet another row, this time with JSON in the new_person_data array ref;

Now with that test in hand back to Driver::DBI I go and add the first thig I will add in is;



use Database::Accessor::Driver::DBI::SQL;
++use JSON qw(to_json);
use Moose;

which is a package I am at least familiar with and at this stage I will limit what I import to just the 'to_json' sub as I know my name-space must be getting very crowded.

Now the code to return the JSON;


if (!$self->is_ArrayRef()) {
while (my $hash_ref = $sth->fetchrow_hashref(
Database::Accessor::Driver::DBI::SQL::DA_KEY_CASE->{$self->da_key_case})) {
-- push(@{$results},$hash_ref);
++ if ($self->is_JSON()){
++ push(@{$results},JSON::to_json($hash_ref));
++ }
++ else {
++ push(@{$results},$hash_ref);
++ }
};
}

All I did in the above was add in an if checking 'is_JSON' and if this is true it adds in JSON string rather than a hash-ref to the @results. Now I am not 100% sure what that 'to_json' will do with my hash so lets run the test and see what comet out;

ok 7 - return set is a JSON
not ok 8 - JSON returned with correct data
# Failed test 'JSON returned with correct data'
# at 20_result_sets.t line 53.
# Compared $data
# got : HASH(0x5d208e8)
# expect : 'first_name:'Diego',last_name: …

hmm so something not right in there;

Opps! that was a simple one forgot to add in a 'retreive' before I did the compare so this fixes;


$da->da_key_case('Lower');
$da->da_result_set('JSON');
ok($da->is_JSON ==1,"return set is a JSON");
++$da->retrieve($dbh);
cmp_deeply( $da->result()->set->[0], $user_db->new_person_data->[3],"JSON returned with correct data");

that and I will give it another go;

not ok 8 - JSON returned with correct data
# Failed test 'JSON returned with correct data'
# at 20_result_sets.t line 54.
# Compared $data
# got : '{"street":"Plaza de la Constitucion ...
# expect : 'first_name:'Diego',..

hmm perhaps I have to take a different tack on this test. Obviously when I do the convert of the hash-ref to JSON the order of the keys is muddled and actually changes each time I run the code as one would expect as hashes in perl are not ordered.

I did check the perl JSON module and there is a 'conical' option however this will place the keys in sorted order which might make each run have a consistent order but in the long run the overhead of this function combined with the fact that it is accepted that JSON data is unsorted means I will just use what comes out of the 'to_json'.

I will have to make sure in my POD I make it clear that the order of the keys when using JSON will be random. I also found out while I was reading the JSON POD that 'to_json' is the old interface and is much slower than 'encode_json' so I will swap that out while I am at it as well.

I will have to change my test to this;


...
my $json_to_hash = {};
eval {
$json_to_hash = decode_json($da->result()->set->[0]);
};
if ($@){
fail("Result set is not Json->Errro".$@);
}
else {
pass("Result set is Json");
}

--cmp_deeply($json_to_hash, $user_db->new_person_data->[3],"JSON returned with correct data");
++cmp_deeply($json_to_hash, $new_person,"JSON returned with correct data");


This time round I attempt to convert the result set to Json which will either fail or pass and then I simply compare the $json_to_hash to the $new_person hash which should be the same hash.

When I run it I get;


...
ok 7 - return set is a JSON
ok 8 - Result set is Json
ok 9 - JSON returned with correct data

so looking good.

I decided to get a little fancy and re-factor my test a little so I can hit each of the 'da_key_case' in a loop so I took what I had above and replaced it with this;


my $expected = {
Lower => $new_person,
Upper => $user_db->new_person_data->[1],
Native => $user_db->new_person_data->[2]
};

$da->da_result_set('JSON');
ok( $da->is_JSON == 1, "return set is a JSON" );

foreach my $case (qw(Lower Upper Native)) {
$da->da_key_case($case);
$da->retrieve($dbh);

my $json_to_hash = {};
eval { $json_to_hash = decode_json( $da->result()->set->[0] ); };
if ($@) {
fail( "Result set for $case is not Json! Error=" . $@ );
}
else {
pass("Result set for $case is Json");
}
cmp_deeply( $json_to_hash, $expected->{$case},
"JSON for for $case returned with correct data" );
}


and on the run I get;


ok 7 - return set is a JSON
ok 8 - Result set for Lower is Json
ok 9 - JSON for for Lower returned with correct data
ok 10 - Result set for Upper is Json
ok 11 - JSON for for Upper returned with correct data
ok 12 - Result set for Native is Json
ok 13 - JSON for for Native returned with correct data

Finally I got a little ambitious and re-factored the whole test case to just;

my $expected = {
Lower => $new_person,
Upper => $user_db->new_person_data->[1],
Native => $user_db->new_person_data->[2]
};

foreach my $case (qw(Lower Upper Native)) {
$da->da_key_case($case);
foreach my $set_type (qw(HashRef JSON)) {
$da->da_result_set($set_type);
my $type = "is_$set_type";
ok( $da->$type == 1, "return set is a $set_type" );
$da->retrieve($dbh);
my $results;
if ( $da->is_JSON ) {
eval { $results = decode_json( $da->result()->set->[0] ); };
if ($@) {
fail( "Result set for $case is not Json! Error=" . $@ );
}
else {
pass("Result set for $case is Json");
}
}
else {
$results = $da->result()->set->[0];
}
cmp_deeply( $results, $expected->{$case},
"$set_type for $case returned with correct data" );

}
}


and I still get a full pass;

ok 1 - return set is a HashRef
ok 2 - HashRef for Lower returned with correct data
ok 3 - return set is a JSON
ok 4 - Result set for Lower is Json
ok 5 - JSON for Lower returned with correct data
ok 6 - return set is a HashRef
ok 7 - HashRef for Upper returned with correct data
ok 8 - return set is a JSON
ok 9 - Result set for Upper is Json
ok 10 - JSON for Upper returned with correct data
ok 11 - return set is a HashRef
ok 12 - HashRef for Native returned with correct data
ok 13 - return set is a JSON
ok 14 - Result set for Native is Json
ok 15 - JSON for Native returned with correct data

so not a bad days work;

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