Browse Source

preserve both `locality` and `borough` results when no `borough` supplied

because we have to treat the `city` value as a possible `borough` when not supplied, both `borough` and `locality` results must be preserved when no `borough` is explicitly supplied.  For example, `city=Manhattan` must preserve both the borough of Manhattan in New York and the locality of Manhattan in Kansas.
pull/712/head
Stephen Hess 8 years ago
parent
commit
3bb6a30a9c
  1. 52
      middleware/trimByGranularityComponent.js
  2. 87
      test/unit/middleware/trimByGranularityComponent.js

52
middleware/trimByGranularityComponent.js

@ -18,7 +18,31 @@ const _ = require('lodash');
// more important than addresses due to how ES matches
// - country outranks dependency, this was done to ensure that "country=United States" doesn't
// bump up US dependencies containing "United States" above the country
// - retain both borough and locality results if both exist for when city=Manhattan is
// supplied we want to retain borough=Manhattan and city=Manhattan results
const layers = [
'venue',
'street',
'address',
'neighbourhood',
['borough', 'locality'],
'localadmin',
'county',
'macrocounty',
'region',
'macroregion',
'country',
'dependency'
];
// these layers are strictly used to drive one special case:
// - when there was a borough explicitly supplied
// for example, if the user passed borough=manhattan and city=new york
// then we want to preserve just boroughs if they're most granular and throw away
// city results. In the usual case where no borough is passed, the city value
// is looked up as a borough in the off chance that the user passed
// city=Manhattan
const explicit_borough_layers = [
'venue',
'street',
'address',
@ -46,16 +70,38 @@ function isFallbackQuery(results) {
function hasRecordsAtLayers(results, layer) {
return results.some( (result) => {
return result._matched_queries[0] === 'fallback.' + layer;
if (_.isArray(layer)) {
return layer.some( (sublayer) => {
return result._matched_queries[0] === 'fallback.' + sublayer;
});
} else {
return result._matched_queries[0] === 'fallback.' + layer;
}
});
}
function retainRecordsAtLayers(results, layer) {
return results.filter( (result) => {
return result._matched_queries[0] === 'fallback.' + layer;
if (_.isArray(layer)) {
return layer.some( (sublayer) => {
return result._matched_queries[0] === 'fallback.' + sublayer;
});
}
else {
return result._matched_queries[0] === 'fallback.' + layer;
}
});
}
function getLayers(parsed_text) {
if (parsed_text && parsed_text.hasOwnProperty('borough')) {
return explicit_borough_layers;
}
return layers;
}
function setup() {
return function trim(req, res, next) {
// don't do anything if there are no results or there are non-fallback.* named queries
@ -64,6 +110,8 @@ function setup() {
return next();
}
const layers = getLayers(req.clean.parsed_text);
// start at the most granular possible layer. if there are results at a layer
// then remove everything not at that layer.
layers.forEach( (layer) => {

87
test/unit/middleware/trimByGranularityComponent.js

@ -22,6 +22,7 @@ module.exports.tests.trimByGranularity = function(test, common) {
{ name: 'street 1', _matched_queries: ['fallback.street'] },
{ name: 'address 1', _matched_queries: ['fallback.address'] },
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] },
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'locality 1', _matched_queries: ['fallback.locality'] },
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] },
{ name: 'county 1', _matched_queries: ['fallback.county'] },
@ -58,6 +59,7 @@ module.exports.tests.trimByGranularity = function(test, common) {
{ name: 'street 2', _matched_queries: ['fallback.street'] },
{ name: 'address 1', _matched_queries: ['fallback.address'] },
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] },
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'locality 1', _matched_queries: ['fallback.locality'] },
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] },
{ name: 'county 1', _matched_queries: ['fallback.county'] },
@ -93,6 +95,7 @@ module.exports.tests.trimByGranularity = function(test, common) {
{ name: 'address 1', _matched_queries: ['fallback.address'] },
{ name: 'address 2', _matched_queries: ['fallback.address'] },
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] },
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'locality 1', _matched_queries: ['fallback.locality'] },
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] },
{ name: 'county 1', _matched_queries: ['fallback.county'] },
@ -127,6 +130,7 @@ module.exports.tests.trimByGranularity = function(test, common) {
data: [
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] },
{ name: 'neighbourhood 2', _matched_queries: ['fallback.neighbourhood'] },
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'locality 1', _matched_queries: ['fallback.locality'] },
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] },
{ name: 'county 1', _matched_queries: ['fallback.county'] },
@ -154,6 +158,89 @@ module.exports.tests.trimByGranularity = function(test, common) {
testIt();
});
test('all records with fallback.* matched_queries name should retain only boroughs when they are most granular', function(t) {
var req = {
clean: {
parsed_text: {
borough: 'borough value'
}
}
};
var res = {
data: [
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'borough 2', _matched_queries: ['fallback.borough'] },
{ name: 'locality 1', _matched_queries: ['fallback.locality'] },
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] },
{ name: 'county 1', _matched_queries: ['fallback.county'] },
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] },
{ name: 'region 1', _matched_queries: ['fallback.region'] },
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] },
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] },
{ name: 'country 1', _matched_queries: ['fallback.country'] },
{ name: 'unknown', _matched_queries: ['fallback.unknown'] }
]
};
var expected_data = [
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'borough 2', _matched_queries: ['fallback.borough'] },
];
function testIt() {
trimByGranularity(req, res, function() {
t.deepEquals(res.data, expected_data, 'only borough records should be here');
t.end();
});
}
testIt();
});
test('if req.parsed_text has city but not borough then borough and city results should be returned', function(t) {
var req = {
clean: {
parsed_text: {
city: 'city value'
}
}
};
var res = {
data: [
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'borough 2', _matched_queries: ['fallback.borough'] },
{ name: 'locality 1', _matched_queries: ['fallback.locality'] },
{ name: 'locality 2', _matched_queries: ['fallback.locality'] },
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] },
{ name: 'county 1', _matched_queries: ['fallback.county'] },
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] },
{ name: 'region 1', _matched_queries: ['fallback.region'] },
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] },
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] },
{ name: 'country 1', _matched_queries: ['fallback.country'] },
{ name: 'unknown', _matched_queries: ['fallback.unknown'] }
]
};
var expected_data = [
{ name: 'borough 1', _matched_queries: ['fallback.borough'] },
{ name: 'borough 2', _matched_queries: ['fallback.borough'] },
{ name: 'locality 1', _matched_queries: ['fallback.locality'] },
{ name: 'locality 2', _matched_queries: ['fallback.locality'] }
];
function testIt() {
trimByGranularity(req, res, function() {
t.deepEquals(res.data, expected_data, 'only borough/locality records should be here');
t.end();
});
}
testIt();
});
test('all records with fallback.* matched_queries name should retain only localities when they are most granular', function(t) {
var req = { clean: {} };

Loading…
Cancel
Save