mirror of https://github.com/pelias/api.git
Browse Source
- created `/component` route - broke out trimByGranularityComponent but could conceivably be combined with existing - added `address` support to text_parser - added `component` sanitizer wrapperpull/712/head
Stephen Hess
8 years ago
10 changed files with 1080 additions and 1 deletions
@ -0,0 +1,74 @@
|
||||
var _ = require('lodash'); |
||||
|
||||
// This middleware component trims the results array by granularity when
|
||||
// FallbackQuery was used. FallbackQuery is used for inputs like
|
||||
// `1090 N Charlotte St, Lancaster, PA` where the address may not exist and
|
||||
// we must fall back to trying `Lancaster, PA`. If the address does exist then
|
||||
// FallbackQuery will return results for:
|
||||
// - address+city+state
|
||||
// - city+state
|
||||
// - state
|
||||
//
|
||||
// Because the address matched, we're not interested in city+state or state, so
|
||||
// this component removes results that aren't the most granular.
|
||||
|
||||
// layers in increasing order of granularity
|
||||
var layers = [ |
||||
'venue', |
||||
'street', |
||||
'address', |
||||
'neighbourhood', |
||||
'borough', |
||||
'locality', |
||||
'localadmin', |
||||
'county', |
||||
'macrocounty', |
||||
'region', |
||||
'macroregion', |
||||
'dependency', |
||||
'country' |
||||
]; |
||||
|
||||
// this helper method returns `true` if every result has a matched_query
|
||||
// starting with `fallback.`
|
||||
function isFallbackQuery(results) { |
||||
return results.every(function(result) { |
||||
return result.hasOwnProperty('_matched_queries') && |
||||
!_.isEmpty(result._matched_queries) && |
||||
_.startsWith(result._matched_queries[0], 'fallback.'); |
||||
}); |
||||
} |
||||
|
||||
function hasRecordsAtLayers(results, layer) { |
||||
return results.some(function(result) { |
||||
return result._matched_queries[0] === 'fallback.' + layer; |
||||
}); |
||||
} |
||||
|
||||
function retainRecordsAtLayers(results, layer) { |
||||
return results.filter(function(result) { |
||||
return result._matched_queries[0] === 'fallback.' + layer; |
||||
}); |
||||
} |
||||
|
||||
function setup() { |
||||
return function trim(req, res, next) { |
||||
// don't do anything if there are no results or there are non-fallback.* named queries
|
||||
// there should never be a mixture of fallback.* and non-fallback.* named queries
|
||||
if (_.isUndefined(res.data) || !isFallbackQuery(res.data)) { |
||||
return next(); |
||||
} |
||||
|
||||
// start at the most granular possible layer. if there are results at a layer
|
||||
// then remove everything not at that layer.
|
||||
layers.forEach(function(layer) { |
||||
if (hasRecordsAtLayers(res.data, layer )) { |
||||
res.data = retainRecordsAtLayers(res.data, layer); |
||||
} |
||||
}); |
||||
|
||||
next(); |
||||
}; |
||||
} |
||||
|
||||
module.exports = setup; |
@ -0,0 +1,117 @@
|
||||
var peliasQuery = require('pelias-query'), |
||||
defaults = require('./search_defaults'), |
||||
textParser = require('./text_parser'), |
||||
check = require('check-types'); |
||||
|
||||
//------------------------------
|
||||
// general-purpose search query
|
||||
//------------------------------
|
||||
var componentQuery = new peliasQuery.layout.ComponentFallbackQuery(); |
||||
|
||||
// scoring boost
|
||||
componentQuery.score( peliasQuery.view.focus_only_function( peliasQuery.view.phrase ) ); |
||||
componentQuery.score( peliasQuery.view.popularity_only_function ); |
||||
componentQuery.score( peliasQuery.view.population_only_function ); |
||||
// --------------------------------
|
||||
|
||||
// non-scoring hard filters
|
||||
componentQuery.filter( peliasQuery.view.boundary_country ); |
||||
componentQuery.filter( peliasQuery.view.boundary_circle ); |
||||
componentQuery.filter( peliasQuery.view.boundary_rect ); |
||||
componentQuery.filter( peliasQuery.view.sources ); |
||||
componentQuery.filter( peliasQuery.view.layers ); |
||||
componentQuery.filter( peliasQuery.view.categories ); |
||||
// --------------------------------
|
||||
|
||||
/** |
||||
map request variables to query variables for all inputs |
||||
provided by this HTTP request. |
||||
**/ |
||||
function generateQuery( clean ){ |
||||
|
||||
var vs = new peliasQuery.Vars( defaults ); |
||||
|
||||
// input text
|
||||
vs.var( 'input:name', clean.text ); |
||||
|
||||
// sources
|
||||
vs.var( 'sources', clean.sources); |
||||
|
||||
// layers
|
||||
vs.var( 'layers', clean.layers); |
||||
|
||||
// categories
|
||||
if (clean.categories) { |
||||
vs.var('input:categories', clean.categories); |
||||
} |
||||
|
||||
// size
|
||||
if( clean.querySize ) { |
||||
vs.var( 'size', clean.querySize ); |
||||
} |
||||
|
||||
// focus point
|
||||
if( check.number(clean['focus.point.lat']) && |
||||
check.number(clean['focus.point.lon']) ){ |
||||
vs.set({ |
||||
'focus:point:lat': clean['focus.point.lat'], |
||||
'focus:point:lon': clean['focus.point.lon'] |
||||
}); |
||||
} |
||||
|
||||
// boundary rect
|
||||
if( check.number(clean['boundary.rect.min_lat']) && |
||||
check.number(clean['boundary.rect.max_lat']) && |
||||
check.number(clean['boundary.rect.min_lon']) && |
||||
check.number(clean['boundary.rect.max_lon']) ){ |
||||
vs.set({ |
||||
'boundary:rect:top': clean['boundary.rect.max_lat'], |
||||
'boundary:rect:right': clean['boundary.rect.max_lon'], |
||||
'boundary:rect:bottom': clean['boundary.rect.min_lat'], |
||||
'boundary:rect:left': clean['boundary.rect.min_lon'] |
||||
}); |
||||
} |
||||
|
||||
// boundary circle
|
||||
// @todo: change these to the correct request variable names
|
||||
if( check.number(clean['boundary.circle.lat']) && |
||||
check.number(clean['boundary.circle.lon']) ){ |
||||
vs.set({ |
||||
'boundary:circle:lat': clean['boundary.circle.lat'], |
||||
'boundary:circle:lon': clean['boundary.circle.lon'] |
||||
}); |
||||
|
||||
if( check.number(clean['boundary.circle.radius']) ){ |
||||
vs.set({ |
||||
'boundary:circle:radius': Math.round( clean['boundary.circle.radius'] ) + 'km' |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// boundary country
|
||||
if( check.string(clean['boundary.country']) ){ |
||||
vs.set({ |
||||
'boundary:country': clean['boundary.country'] |
||||
}); |
||||
} |
||||
|
||||
// run the address parser
|
||||
if( clean.parsed_text ){ |
||||
textParser( clean.parsed_text, vs ); |
||||
} |
||||
|
||||
var q = getQuery(vs); |
||||
|
||||
console.log(JSON.stringify(q.body, null, 2)); |
||||
|
||||
return q; |
||||
} |
||||
|
||||
function getQuery(vs) { |
||||
return { |
||||
type: 'fallback', |
||||
body: componentQuery.render(vs) |
||||
}; |
||||
} |
||||
|
||||
module.exports = generateQuery; |
@ -0,0 +1,26 @@
|
||||
var type_mapping = require('../helper/type_mapping'); |
||||
|
||||
var sanitizeAll = require('../sanitizer/sanitizeAll'), |
||||
sanitizers = { |
||||
quattroshapes_deprecation: require('../sanitizer/_deprecate_quattroshapes'), |
||||
singleScalarParameters: require('../sanitizer/_single_scalar_parameters'), |
||||
synthesize_analysis: require('../sanitizer/_synthesize_analysis'), |
||||
size: require('../sanitizer/_size')(/* use defaults*/), |
||||
layers: require('../sanitizer/_targets')('layers', type_mapping.layer_mapping), |
||||
sources: require('../sanitizer/_targets')('sources', type_mapping.source_mapping), |
||||
// depends on the layers and sources sanitizers, must be run after them
|
||||
sources_and_layers: require('../sanitizer/_sources_and_layers'), |
||||
private: require('../sanitizer/_flag_bool')('private', false), |
||||
geo_search: require('../sanitizer/_geo_search'), |
||||
boundary_country: require('../sanitizer/_boundary_country'), |
||||
categories: require('../sanitizer/_categories') |
||||
}; |
||||
|
||||
var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; |
||||
|
||||
// middleware
|
||||
module.exports.middleware = function( req, res, next ){ |
||||
sanitize( req, function( err, clean ){ |
||||
next(); |
||||
}); |
||||
}; |
@ -0,0 +1,431 @@
|
||||
var trimByGranularity = require('../../../middleware/trimByGranularityComponent')(); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.trimByGranularity = function(test, common) { |
||||
test('empty res and req should not throw exception', function(t) { |
||||
function testIt() { |
||||
trimByGranularity({}, {}, function() {}); |
||||
} |
||||
|
||||
t.doesNotThrow(testIt, 'an exception should not have been thrown'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only venues when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'venue 1', _matched_queries: ['fallback.venue'] }, |
||||
{ name: 'venue 2', _matched_queries: ['fallback.venue'] }, |
||||
{ name: 'street 1', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'address 1', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ 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: 'venue 1', _matched_queries: ['fallback.venue'] }, |
||||
{ name: 'venue 2', _matched_queries: ['fallback.venue'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only venue records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only streets when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'street 1', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'street 2', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'address 1', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ 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: 'street 1', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'street 2', _matched_queries: ['fallback.street'] } |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only street records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only address when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'address 1', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'address 2', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ 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: 'address 1', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'address 2', _matched_queries: ['fallback.address'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only address records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only neighbourhoods when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'neighbourhood 2', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ 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: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'neighbourhood 2', _matched_queries: ['fallback.neighbourhood'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only neighbourhood 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: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ 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: '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 locality records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only localadmins when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'localadmin 2', _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: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'localadmin 2', _matched_queries: ['fallback.localadmin'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only localadmin records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only counties when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'county 2', _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: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'county 2', _matched_queries: ['fallback.county'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only county records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only macrocounties when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'macrocounty 2', _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: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'macrocounty 2', _matched_queries: ['fallback.macrocounty'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only macrocounty records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only regions when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'region 2', _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: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'region 2', _matched_queries: ['fallback.region'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only region records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only macroregions when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'macroregion 2', _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: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'macroregion 2', _matched_queries: ['fallback.macroregion'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only macroregion records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only dependencies when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'dependency 2', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'dependency 2', _matched_queries: ['fallback.dependency'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only dependency records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only countries when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'country 2', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'country 2', _matched_queries: ['fallback.country'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only country records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('presence of any non-fallback.* named queries should not trim', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'region', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'country', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'result with non-named query' } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'region', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'country', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'result with non-named query' } |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'all should results should have been retained'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('[middleware] trimByGranularity: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,283 @@
|
||||
var generate = require('../../../query/component'); |
||||
var fs = require('fs'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.interface = function(test, common) { |
||||
test('valid interface', function(t) { |
||||
t.equal(typeof generate, 'function', 'valid function'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.tests.query = function(test, common) { |
||||
test('valid search + focus + bbox', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', |
||||
querySize: 10, |
||||
'focus.point.lat': 29.49136, 'focus.point.lon': -82.50622, |
||||
'boundary.rect.min_lat': 47.47, |
||||
'boundary.rect.max_lon': -61.84, |
||||
'boundary.rect.max_lat': 11.51, |
||||
'boundary.rect.min_lon': -103.16, |
||||
layers: ['test'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_focus_bbox'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_focus_bbox'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid search + bbox', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', |
||||
querySize: 10, |
||||
'boundary.rect.min_lat': 47.47, |
||||
'boundary.rect.max_lon': -61.84, |
||||
'boundary.rect.max_lat': 11.51, |
||||
'boundary.rect.min_lon': -103.16, |
||||
layers: ['test'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_bbox'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_bbox'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid lingustic-only search', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', querySize: 10, |
||||
layers: ['test'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_only'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_only'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('search search + focus', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', querySize: 10, |
||||
'focus.point.lat': 29.49136, 'focus.point.lon': -82.50622, |
||||
layers: ['test'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_focus'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_focus'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('search search + viewport', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', querySize: 10, |
||||
'focus.viewport.min_lat': 28.49136, |
||||
'focus.viewport.max_lat': 30.49136, |
||||
'focus.viewport.min_lon': -87.50622, |
||||
'focus.viewport.max_lon': -77.50622, |
||||
layers: ['test'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_viewport'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_viewport'); |
||||
t.end(); |
||||
}); |
||||
|
||||
// viewport scale sizing currently disabled.
|
||||
// ref: https://github.com/pelias/api/pull/388
|
||||
test('search with viewport diagonal < 1km should set scale to 1km', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', querySize: 10, |
||||
'focus.viewport.min_lat': 28.49135, |
||||
'focus.viewport.max_lat': 28.49137, |
||||
'focus.viewport.min_lon': -87.50622, |
||||
'focus.viewport.max_lon': -87.50624, |
||||
layers: ['test'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_viewport_min_diagonal'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'valid search query'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('search search + focus on null island', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', querySize: 10, |
||||
'focus.point.lat': 0, 'focus.point.lon': 0, |
||||
layers: ['test'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_focus_null_island'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_focus_null_island'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('parsed_text with all fields should use FallbackQuery', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
query: 'query value', |
||||
category: 'category value', |
||||
number: 'number value', |
||||
street: 'street value', |
||||
neighbourhood: 'neighbourhood value', |
||||
borough: 'borough value', |
||||
postalcode: 'postalcode value', |
||||
city: 'city value', |
||||
county: 'county value', |
||||
state: 'state value', |
||||
country: 'country value' |
||||
} |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse(JSON.stringify(query)); |
||||
var expected = require('../fixture/search_fallback'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'fallbackQuery'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('parsed_text with single admin field should return undefined', function(t) { |
||||
['neighbourhood', 'borough', 'city', 'county', 'state', 'country'].forEach(function(placeType) { |
||||
var clean = { |
||||
parsed_text: {} |
||||
}; |
||||
|
||||
clean.parsed_text[placeType] = placeType + ' value'; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
t.equals(query, undefined, 'geodisambiguationQuery'); |
||||
|
||||
}); |
||||
|
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('valid boundary.country search', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
text: 'test', querySize: 10, |
||||
layers: ['test'], |
||||
'boundary.country': 'ABC' |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_boundary_country'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search: valid boundary.country query'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid sources filter', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
'text': 'test', |
||||
'sources': ['test_source'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_with_source_filtering'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search: valid search query with source filtering'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('categories filter', function(t) { |
||||
var clean = { |
||||
parsed_text: { |
||||
street: 'street value' |
||||
}, |
||||
'text': 'test', |
||||
'categories': ['retail','food'] |
||||
}; |
||||
|
||||
var query = generate(clean); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_with_category_filtering'); |
||||
|
||||
t.deepEqual(compiled.type, 'fallback', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'valid search query with category filtering'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('search query ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,113 @@
|
||||
var proxyquire = require('proxyquire').noCallThru(); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.sanitize = function(test, common) { |
||||
test('verify that all sanitizers were called as expected', function(t) { |
||||
var called_sanitizers = []; |
||||
|
||||
// rather than re-verify the functionality of all the sanitizers, this test just verifies that they
|
||||
// were all called correctly
|
||||
var search = proxyquire('../../../sanitizer/component', { |
||||
'../sanitizer/_deprecate_quattroshapes': function() { |
||||
called_sanitizers.push('_deprecate_quattroshapes'); |
||||
return { errors: [], warnings: [] }; |
||||
}, |
||||
'../sanitizer/_single_scalar_parameters': function() { |
||||
called_sanitizers.push('_single_scalar_parameters'); |
||||
return { errors: [], warnings: [] }; |
||||
}, |
||||
'../sanitizer/_synthesize_analysis': function() { |
||||
called_sanitizers.push('_synthesize_analysis'); |
||||
return { errors: [], warnings: [] }; |
||||
}, |
||||
'../sanitizer/_size': function() { |
||||
if (arguments.length === 0) { |
||||
return function() { |
||||
called_sanitizers.push('_size'); |
||||
return { errors: [], warnings: [] }; |
||||
}; |
||||
|
||||
} else { |
||||
throw new Error('should not have passed any parameters to _size'); |
||||
} |
||||
|
||||
}, |
||||
'../sanitizer/_targets': function(type) { |
||||
if (['layers', 'sources'].indexOf(type) !== -1) { |
||||
return function() { |
||||
called_sanitizers.push('_targets/' + type); |
||||
return { errors: [], warnings: [] }; |
||||
}; |
||||
|
||||
} |
||||
else { |
||||
throw new Error('incorrect parameters passed to _targets'); |
||||
} |
||||
|
||||
}, |
||||
'../sanitizer/_sources_and_layers': function() { |
||||
called_sanitizers.push('_sources_and_layers'); |
||||
return { errors: [], warnings: [] }; |
||||
}, |
||||
'../sanitizer/_flag_bool': function() { |
||||
if (arguments[0] === 'private' && arguments[1] === false) { |
||||
return function() { |
||||
called_sanitizers.push('_flag_bool'); |
||||
return { errors: [], warnings: [] }; |
||||
}; |
||||
|
||||
} |
||||
else { |
||||
throw new Error('incorrect parameters passed to _flag_bool'); |
||||
} |
||||
|
||||
}, |
||||
'../sanitizer/_geo_search': function() { |
||||
called_sanitizers.push('_geo_search'); |
||||
return { errors: [], warnings: [] }; |
||||
}, |
||||
'../sanitizer/_boundary_country': function() { |
||||
called_sanitizers.push('_boundary_country'); |
||||
return { errors: [], warnings: [] }; |
||||
}, |
||||
'../sanitizer/_categories': function() { |
||||
called_sanitizers.push('_categories'); |
||||
return { errors: [], warnings: [] }; |
||||
}, |
||||
}); |
||||
|
||||
var expected_sanitizers = [ |
||||
'_deprecate_quattroshapes', |
||||
'_single_scalar_parameters', |
||||
'_synthesize_analysis', |
||||
'_size', |
||||
'_targets/layers', |
||||
'_targets/sources', |
||||
'_sources_and_layers', |
||||
'_flag_bool', |
||||
'_geo_search', |
||||
'_boundary_country', |
||||
'_categories' |
||||
]; |
||||
|
||||
var req = {}; |
||||
var res = {}; |
||||
|
||||
search.middleware(req, res, function(){ |
||||
t.deepEquals(called_sanitizers, expected_sanitizers); |
||||
t.end(); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
|
||||
function test(name, testFunction) { |
||||
return tape('SANTIZE /component ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
Loading…
Reference in new issue