Trying to force a scalar to be a number

I love the flexibility of Perl and JavaScript to do anything with a variable, but sometimes it bites me.

I am slurping geometries from a database using PostGIS’s ST_AsGeoJSON function via dbix::class.  I have a loop that stores what I need from each record in the db, and then when all the data is loaded, I bulk dump it to CouchDB.  On the CouchDB side I am running GeoCouch, and have a view that generates a spatial index.

Except that it breaks in a pile of Erlang error dumpage.  The problem is that sometimes in moving from the database through perl to JSON to CouchDB, the scalars that are supposed to be numeric coordinates get misinterpreted as strings!  This is perfectly understandable from a language point of view. The data streaming out of postgres is a string representation of the geometry, so of course perl can’t guess that I really want numbers.  So I wrote a little loop:

my $geojson = $self->json()->decode( $vds->get_column('geojson') );
## **SOMETIMES** but not always, perw writes text, not numbers
## so I must touch every number here and subtract zero
my @coords = ();
for my $pair (@{$geojson->{'coordinates'}}){
    push @coords, [ $pair->[0] -0.0 ,$pair->[1] - 0.0];
}
$geojson->{'coordinates'} = [@coords];
$data->{'geometry'} = $geojson;

That is super ugly, but I can’t find my perl book and I can’t find any search term that hits on some sort of “numeric” cast operator.   My guess from reading http://perldoc.perl.org/perlnumber.html is that somehow perl is deciding that the number is best represented internally as a string, so as to not lose precision.

I’ve run across the same thing in JavaScript.  But I’ve never come across a case where subtracting a number failed to make a string representation of a number numeric!

Even resorting to using  <code>sub getnum { … }</code> from http://perldoc.perl.org/perlfaq4.html#How-do-I-determine-whether-a-scalar-is-a-number/whole/integer/float? didn’t do the trick!

Aha! Thanks to the tip from Martin (below) I re-read the JSON::XS docs.  The problem was my fault.  I was dumping a *single* records to the terminal prior to doing the bulk docs call on CouchDB.  So that one record had a bunch of numbers that were last used as a string, and so my spatial index was failing.

Take out the stupid debug carp call, and the numbers aren’t being used as strings, and JSON::XS does the right thing!  Now I can move on making maps of highways.

Edit Dec 20, 2010.  Just to be clear,  once I took out my debugging call to dump a record to the screen before saving it, I also no longer needed to touch each number and subtract zero.  So my loop for loading data now reads:

    my $geojson = $self->json()->decode( $vds->get_column('geojson') );
    $data->{'geometry'} = $geojson;

Advertisements

2 thoughts on “Trying to force a scalar to be a number

  1. Martin, you missed the url in your link…But thanks for the tip on JSON::XS. I’d forgotten that the JSON::XS module help is where I got the “use in a math expression” idea. I think the culprit is there somewhere, and hopefully will be easier than convincing postgres/postgis to give me numbers.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s