Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ var Metadata = require('./lib/metadata');
var queue = require('queue-async');
var Dyno = require('@mapbox/dyno');
var AWS = require('aws-sdk');
var geobuf = require('geobuf');
var stream = require('stream');
var decodeFeature = require('./lib/geobuf-helpers').decodeFeature;

var MAX_GEOMETRY_SIZE = 1024 * 10; // 10KB

Expand Down Expand Up @@ -121,7 +121,7 @@ function Cardboard(config) {
if (encoded[1]) q.defer(config.s3.putObject.bind(config.s3), encoded[1]);
q.defer(config.dyno.putItem, {Item: encoded[0]});
q.await(function(err) {
var result = geobuf.geobufToFeature(encoded[0].val || encoded[1].Body);
var result = decodeFeature(encoded[0].val || encoded[1].Body);
result.id = utils.idFromRecord(encoded[0]);
callback(err, result);
});
Expand Down
6 changes: 3 additions & 3 deletions lib/batch.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
var queue = require('queue-async');
var geobuf = require('geobuf');
var _ = require('lodash');
var Dyno = require('@mapbox/dyno');
var AWS = require('aws-sdk');
var decodeFeature = require('./geobuf-helpers').decodeFeature;

module.exports = function(config) {
if (!config.bucket) throw new Error('No bucket set');
Expand Down Expand Up @@ -60,7 +60,7 @@ module.exports = function(config) {
var unprocessed = res.UnprocessedItems ? res.UnprocessedItems[table] : null;

if (!unprocessed) {
var features = geobufs.map(geobuf.geobufToFeature.bind(geobuf));
var features = geobufs.map(function(buf) { return decodeFeature(buf); });
return callback(null, { type: 'FeatureCollection', features: features });
}

Expand All @@ -70,7 +70,7 @@ module.exports = function(config) {
return utils.idFromRecord(record) === id;
});

collection.features.push(geobuf.geobufToFeature(geobufs[i]));
collection.features.push(decodeFeature(geobufs[i]));
return collection;
}, { type: 'FeatureCollection', features: [] });

Expand Down
41 changes: 41 additions & 0 deletions lib/geobuf-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
var geobuf = require('geobuf');
var Pbf = require('pbf');

/**
* Normalize a feature decoded from geobuf to ensure consistent API output.
* geobuf 3.x omits empty properties and preserves numeric IDs as numbers.
* This function ensures backwards compatibility with cardboard's external API.
* @param {object} feature - a GeoJSON feature decoded from geobuf
* @returns {object} the normalized feature
*/
function normalizeFeature(feature) {
if (!feature) return feature;
if (!feature.properties) feature.properties = {};
// geobuf 3.x preserves numeric IDs; convert to strings for backwards compatibility
if (typeof feature.id === 'number') feature.id = String(feature.id);
return feature;
}

/**
* Encode a GeoJSON feature to geobuf format
* @param {object} feature - a GeoJSON feature
* @returns {Buffer} the encoded geobuf buffer
*/
function encodeFeature(feature) {
return Buffer.from(geobuf.encode(feature, new Pbf()));
}

/**
* Decode a geobuf buffer to a GeoJSON feature, with normalization for API consistency
* @param {Buffer} buffer - a geobuf encoded buffer
* @returns {object} the decoded and normalized GeoJSON feature
*/
function decodeFeature(buffer) {
return normalizeFeature(geobuf.decode(new Pbf(buffer)));
}

module.exports = {
normalizeFeature: normalizeFeature,
encodeFeature: encodeFeature,
decodeFeature: decodeFeature
};
4 changes: 2 additions & 2 deletions lib/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var through = require('through2');
var SphericalMercator = require('sphericalmercator');
var merc = new SphericalMercator();
var _ = require('lodash');
var geobuf = require('geobuf');
var encodeFeature = require('./geobuf-helpers').encodeFeature;

module.exports = Metadata;

Expand Down Expand Up @@ -56,7 +56,7 @@ function Metadata(dyno, dataset) {
metadata.getFeatureInfo = function(feature) {
var bounds = extent(feature);
return {
size: geobuf.featureToGeobuf(feature).toBuffer().length,
size: encodeFeature(feature).length,
bounds: bounds,
west: bounds[0],
south: bounds[1],
Expand Down
14 changes: 10 additions & 4 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
var queue = require('queue-async');
var geobuf = require('geobuf');
var url = require('url');
var geojsonNormalize = require('geojson-normalize');
var _ = require('lodash');
var cuid = require('cuid');
var Metadata = require('./metadata');
var tilebelt = require('tilebelt');
var geobufHelpers = require('./geobuf-helpers');
var encodeFeature = geobufHelpers.encodeFeature;
var decodeFeature = geobufHelpers.decodeFeature;

module.exports = Utils;
// Re-export geobuf helpers for external use
module.exports.normalizeFeature = geobufHelpers.normalizeFeature;
module.exports.encodeFeature = encodeFeature;
module.exports.decodeFeature = decodeFeature;

function Utils(config) {
/**
Expand All @@ -30,7 +36,7 @@ function Utils(config) {
var feature;
if (val) {
try {
feature = geobuf.geobufToFeature(val);
feature = decodeFeature(val);
} catch(e) {
return next(e);
}
Expand All @@ -44,7 +50,7 @@ function Utils(config) {
}, function(err, data) {
if (err) return next(err);
try {
feature = geobuf.geobufToFeature(data.Body);
feature = decodeFeature(data.Body);
} catch(e) {
return next(e);
}
Expand Down Expand Up @@ -92,7 +98,7 @@ function Utils(config) {
}

var info = Metadata(config.dyno, dataset).getFeatureInfo(f);
var buf = geobuf.featureToGeobuf(f).toBuffer();
var buf = encodeFeature(f);
var tile = tilebelt.bboxToTile([info.west, info.south, info.east, info.north]);
var cell = tilebelt.tileToQuadkey(tile);
var useS3 = buf.length >= config.MAX_GEOMETRY_SIZE;
Expand Down
Loading