diff --git a/middleware/normalizeParentIds.js b/middleware/normalizeParentIds.js new file mode 100644 index 00000000..2c9d3629 --- /dev/null +++ b/middleware/normalizeParentIds.js @@ -0,0 +1,66 @@ +var logger = require('pelias-logger').get('api'); +var Document = require('pelias-model').Document; + +var placeTypes = [ + 'country', + 'macroregion', + 'region', + 'macrocounty', + 'county', + 'localadmin', + 'locality', + 'neighbourhood', + 'borough' +]; + +/** + * Convert WOF integer ids to Pelias formatted ids that can be used by the /place endpoint. + * This should probably be moved to the import pipeline once we are happy with the way this works. + */ + +function setup() { + return function (req, res, next) { + // do nothing if no result data set + if (!res || !res.data) { + return next(); + } + + res.data = res.data.map(normalizeParentIds); + + next(); + }; +} + +/** + * Update all parent ids in the admin hierarchy + * + * @param {object} place + * @return {object} + */ +function normalizeParentIds(place) { + + if (place && place.parent) { + placeTypes.forEach(function (placeType) { + if (place.parent[placeType] && place.parent[placeType].length > 0 && place.parent[placeType][0]) { + place.parent[placeType + '_id'] = [ makeNewId(placeType, place.parent[placeType + '_id']) ]; + } + }); + } + + return place; +} + +/** + * Generate a valid Pelias ids from placetype and WOF id. + * Assumes all of the incoming ids are WOF ids. + * + * @param {string} placeType + * @param {number} id + * @return {string} + */ +function makeNewId(placeType, id) { + var doc = new Document('whosonfirst', placeType, id); + return doc.getGid(); +} + +module.exports = setup; diff --git a/package.json b/package.json index 84ada6ea..f97df8eb 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "morgan": "1.7.0", "pelias-config": "^1.0.1", "pelias-logger": "^0.0.8", + "pelias-model": "^3.1.0", "pelias-query": "6.2.0", "pelias-suggester-pipeline": "2.0.4", "stats-lite": "1.0.3", diff --git a/routes/v1.js b/routes/v1.js index eacd0a40..c8c88de1 100644 --- a/routes/v1.js +++ b/routes/v1.js @@ -35,7 +35,8 @@ var postProc = { renamePlacenames: require('../middleware/renamePlacenames'), geocodeJSON: require('../middleware/geocodeJSON'), sendJSON: require('../middleware/sendJSON'), - parseBoundingBox: require('../middleware/parseBBox') + parseBoundingBox: require('../middleware/parseBBox'), + normalizeParentIds: require('../middleware/normalizeParentIds') }; /** @@ -67,6 +68,7 @@ function addRoutes(app, peliasConfig) { postProc.localNamingConventions(), postProc.renamePlacenames(), postProc.parseBoundingBox(), + postProc.normalizeParentIds(), postProc.geocodeJSON(peliasConfig, base), postProc.sendJSON ]), @@ -79,6 +81,7 @@ function addRoutes(app, peliasConfig) { postProc.localNamingConventions(), postProc.renamePlacenames(), postProc.parseBoundingBox(), + postProc.normalizeParentIds(), postProc.geocodeJSON(peliasConfig, base), postProc.sendJSON ]), @@ -94,6 +97,7 @@ function addRoutes(app, peliasConfig) { postProc.localNamingConventions(), postProc.renamePlacenames(), postProc.parseBoundingBox(), + postProc.normalizeParentIds(), postProc.geocodeJSON(peliasConfig, base), postProc.sendJSON ]), @@ -103,6 +107,7 @@ function addRoutes(app, peliasConfig) { postProc.localNamingConventions(), postProc.renamePlacenames(), postProc.parseBoundingBox(), + postProc.normalizeParentIds(), postProc.geocodeJSON(peliasConfig, base), postProc.sendJSON ]), diff --git a/test/unit/middleware/normalizeParentIds.js b/test/unit/middleware/normalizeParentIds.js new file mode 100644 index 00000000..9ad603f8 --- /dev/null +++ b/test/unit/middleware/normalizeParentIds.js @@ -0,0 +1,85 @@ +var normalizer = require('../../../middleware/normalizeParentIds')(); + +module.exports.tests = {}; + +module.exports.tests.interface = function(test, common) { + test('WOF ids converted to Pelias ids', function(t) { + + var input = { + data: [{ + 'parent': { + 'country': ['United States'], + 'country_id': ['85633793'], + 'country_a': ['USA'], + 'macroregion': ['MacroRegion Name'], + 'macroregion_id': ['foobar'], + 'macroregion_a': ['MacroRegion Abbreviation'], + 'region': ['New York'], + 'region_id': ['85688543'], + 'region_a': ['NY'], + 'macrocounty': ['MacroCounty Name'], + 'macrocounty_id': ['~~~~~'], + 'macrocounty_a': ['MacroCounty Abbreviation'], + 'county': ['Kings County'], + 'county_id': ['102082361'], + 'county_a': [null], + 'localadmin': ['Brooklyn'], + 'localadmin_id': ['404521211'], + 'localadmin_a': [null], + 'locality': ['Some Locality'], + 'locality_id': ['85977539'], + 'locality_a': [null], + 'neighbourhood': [], + 'neighbourhood_id': [] + } + }] + }; + + var expected = { + data: [{ + 'parent': { + 'country': ['United States'], + 'country_id': ['whosonfirst:country:85633793'], + 'country_a': ['USA'], + 'macroregion': ['MacroRegion Name'], + 'macroregion_id': ['whosonfirst:macroregion:foobar'], + 'macroregion_a': ['MacroRegion Abbreviation'], + 'region': ['New York'], + 'region_id': ['whosonfirst:region:85688543'], + 'region_a': ['NY'], + 'macrocounty': ['MacroCounty Name'], + 'macrocounty_id': ['whosonfirst:macrocounty:~~~~~'], + 'macrocounty_a': ['MacroCounty Abbreviation'], + 'county': ['Kings County'], + 'county_id': ['whosonfirst:county:102082361'], + 'county_a': [null], + 'localadmin': ['Brooklyn'], + 'localadmin_id': ['whosonfirst:localadmin:404521211'], + 'localadmin_a': [null], + 'locality': ['Some Locality'], + 'locality_id': ['whosonfirst:locality:85977539'], + 'locality_a': [null], + 'neighbourhood': [], + 'neighbourhood_id': [] + } + }] + }; + + normalizer({}, input, function () { + t.deepEqual(input, expected); + t.end(); + }); + + }); +}; + +module.exports.all = function (tape, common) { + + function test(name, testFunction) { + return tape('[middleware] normalizeParentIds: ' + name, testFunction); + } + + for( var testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +}; diff --git a/test/unit/run.js b/test/unit/run.js index 2e8b382e..c1ab11b7 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -28,6 +28,7 @@ var tests = [ require('./middleware/localNamingConventions'), require('./middleware/dedupe'), require('./middleware/parseBBox'), + require('./middleware/normalizeParentIds'), require('./query/autocomplete'), require('./query/autocomplete_defaults'), require('./query/search_defaults'),