mysqljsonperldbihashref

Perl / DBI query doesn't preserve integer values for JSON output


I can't get this Perl code to return true integer values for integers in the table. The MySQL table columns are correctly specified as integers, yet the JSON output here wraps all query values in quotes. How can I correctly preserve data-types (esp. integers and boolean values) as specified?

use strict;
use warnings;
use DBI;
use JSON;

my $sth = "SELECT id, name, age FROM table";

my $data = $dbh->selectall_arrayref($sth, {Slice => {}});

my $response = encode_json($data);
print $response;

## outputs: {"id":"1","name":"Joe Blodge","age":"42"}

What am I doing wrong here? How can I get this to output the correctly formatted JSON:

{"id":1,"name":"Joe Blodge","age":42}

Solution

  • DBD::mysql returns all results as strings (see https://github.com/perl5-dbi/DBD-mysql/issues/253). Normally Perl doesn't care, encoding to JSON is one of the few times when it matters. You can either use Cpanel::JSON::XS::Type to provide type declarations for your JSON structure:

    use Cpanel::JSON::XS;
    use Cpanel::JSON::XS::Type;
    
    my $response = encode_json($data, {id => JSON_TYPE_INT, name => JSON_TYPE_STRING, age => JSON_TYPE_INT});
    

    or you can go through and numify the appropriate elements before JSON encoding.

    $data->{$_} += 0 for qw(id age);
    

    It is possible to check the type (as indicated by MySQL) of each returned column, if you construct and execute your query using a statement handle then the type will be available as an array in $sth->{TYPE}, but this is pretty complex and may not be reliable.