Browse Source

Merge pull request #1048 from pelias/staging

Merge staging into production
production
Julian Simioni 7 years ago committed by GitHub
parent
commit
cf89dc0aa7
  1. 12
      README.md
  2. 1
      controller/libpostal.js
  3. 2
      controller/place.js
  4. 13
      index.js
  5. 12
      package.json
  6. 8
      query/structured_geocoding.js
  7. 21
      sanitizer/_geonames_deprecation.js
  8. 4
      test/unit/controller/libpostal.js
  9. 4
      test/unit/controller/place.js
  10. 39
      test/unit/fixture/reverse_null_island.js
  11. 39
      test/unit/fixture/reverse_standard.js
  12. 49
      test/unit/fixture/reverse_with_boundary_country.js
  13. 41
      test/unit/fixture/reverse_with_layer_filtering.js
  14. 41
      test/unit/fixture/reverse_with_layer_filtering_non_coarse_subset.js
  15. 46
      test/unit/fixture/reverse_with_source_filtering.js
  16. 71
      test/unit/fixture/search_linguistic_viewport.js
  17. 71
      test/unit/fixture/search_linguistic_viewport_min_diagonal.js
  18. 59
      test/unit/fixture/structured_geocoding/boundary_country.json
  19. 859
      test/unit/fixture/structured_geocoding/fallback.json
  20. 62
      test/unit/fixture/structured_geocoding/linguistic_bbox.json
  21. 65
      test/unit/fixture/structured_geocoding/linguistic_focus.json
  22. 76
      test/unit/fixture/structured_geocoding/linguistic_focus_bbox.json
  23. 65
      test/unit/fixture/structured_geocoding/linguistic_focus_null_island.json
  24. 51
      test/unit/fixture/structured_geocoding/linguistic_only.json
  25. 51
      test/unit/fixture/structured_geocoding/linguistic_viewport.json
  26. 51
      test/unit/fixture/structured_geocoding/linguistic_viewport_min_diagonal.json
  27. 60
      test/unit/fixture/structured_geocoding/postalcode_only.js
  28. 52
      test/unit/fixture/structured_geocoding/with_source_filtering.json
  29. 7
      test/unit/query/MockQuery.js
  30. 557
      test/unit/query/reverse.js
  31. 48
      test/unit/query/search.js
  32. 663
      test/unit/query/structured_geocoding.js
  33. 44
      test/unit/sanitizer/_geonames_deprecation.js

12
README.md

@ -44,7 +44,7 @@ The API recognizes the following properties under the top-level `api` key in you
|`indexName`|*no*|*pelias*|name of the Elasticsearch index to be used when building queries| |`indexName`|*no*|*pelias*|name of the Elasticsearch index to be used when building queries|
|`relativeScores`|*no*|true|if set to true, confidence scores will be normalized, realistically at this point setting this to false is not tested or desirable |`relativeScores`|*no*|true|if set to true, confidence scores will be normalized, realistically at this point setting this to false is not tested or desirable
|`accessLog`|*no*||name of the format to use for access logs; may be any one of the [predefined values](https://github.com/expressjs/morgan#predefined-formats) in the `morgan` package. Defaults to `"common"`; if set to `false`, or an otherwise falsy value, disables access-logging entirely.| |`accessLog`|*no*||name of the format to use for access logs; may be any one of the [predefined values](https://github.com/expressjs/morgan#predefined-formats) in the `morgan` package. Defaults to `"common"`; if set to `false`, or an otherwise falsy value, disables access-logging entirely.|
|`services`|*no*||service definitions for [point-in-polygon](https://github.com/pelias/pip-service) and [placholder](https://github.com/pelias/placeholder) services. If missing (which is not recommended), the point-in-polygon and placeholder services will not be called.| |`services`|*no*||service definitions for [point-in-polygon](https://github.com/pelias/pip-service), and [placeholder](https://github.com/pelias/placeholder), and [interpolation](https://github.com/pelias/interpolation) services. If missing (which is not recommended), the services will not be called.|
|`defaultParameters.focus.point.lon` <br> `defaultParameters.focus.point.lat`|no | |default coordinates for focus point |`defaultParameters.focus.point.lon` <br> `defaultParameters.focus.point.lat`|no | |default coordinates for focus point
Example configuration file would look something like this: Example configuration file would look something like this:
@ -73,6 +73,10 @@ Example configuration file would look something like this:
}, },
"placeholder": { "placeholder": {
"url": "http://myplaceholderservice.com:5000" "url": "http://myplaceholderservice.com:5000"
},
"interpolation": {
"url": "http://myinterpolationservice.com:3000",
"timeout": 2500
} }
} }
"defaultParameters": { "defaultParameters": {
@ -80,12 +84,6 @@ Example configuration file would look something like this:
"focus.point.lon": 21.212121 "focus.point.lon": 21.212121
} }
}, },
"interpolation": {
"client": {
"adapter": "http",
"host": "internal-pelias-interpolation-dev-130430937.us-east-1.elb.amazonaws.com"
}
},
"logger": { "logger": {
"level": "debug" "level": "debug"
} }

1
controller/libpostal.js

@ -20,6 +20,7 @@ function setup(should_execute) {
parsed_text.country = iso3166.to3(_.toUpper(parsed_text.country)); parsed_text.country = iso3166.to3(_.toUpper(parsed_text.country));
} }
req.clean.parser = 'libpostal';
req.clean.parsed_text = parsed_text; req.clean.parsed_text = parsed_text;
debugLog.push(req, {parsed_text: req.clean.parsed_text}); debugLog.push(req, {parsed_text: req.clean.parsed_text});
} }

2
controller/place.js

@ -38,7 +38,7 @@ function setup( apiConfig, esclient ){
const cmd = req.clean.ids.map( function(id) { const cmd = req.clean.ids.map( function(id) {
return { return {
_index: apiConfig.indexName, _index: apiConfig.indexName,
_type: id.layers, _type: id.layer,
_id: id.id _id: id.id
}; };
}); });

13
index.js

@ -1,7 +1,10 @@
var app = require('./app'), const app = require('./app'),
port = ( process.env.PORT || 3100 ); port = ( process.env.PORT || 3100 ),
host = ( process.env.HOST || undefined );
/** run server on the default setup (single core) **/ const server = app.listen( port, host, () => {
console.log( 'pelias is now running on port ' + port ); // ask server for the actual address and port its listening on
app.listen( port ); const listenAddress = server.address();
console.log( `pelias is now running on ${listenAddress.address}:${listenAddress.port}` );
});

12
package.json

@ -49,21 +49,21 @@
"geolib": "^2.0.18", "geolib": "^2.0.18",
"iso-639-3": "^1.0.0", "iso-639-3": "^1.0.0",
"iso3166-1": "^0.3.0", "iso3166-1": "^0.3.0",
"joi": "^11.0.1", "joi": "^12.0.0",
"locale": "^0.1.0", "locale": "^0.1.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"markdown": "0.5.0", "markdown": "0.5.0",
"morgan": "^1.8.2", "morgan": "^1.8.2",
"pelias-categories": "1.2.0", "pelias-categories": "1.2.0",
"pelias-config": "2.12.1", "pelias-config": "2.13.0",
"pelias-labels": "1.7.0", "pelias-labels": "1.7.0",
"pelias-logger": "0.2.0", "pelias-logger": "0.3.0",
"pelias-microservice-wrapper": "1.2.1", "pelias-microservice-wrapper": "1.2.1",
"pelias-model": "5.1.0", "pelias-model": "5.2.0",
"pelias-query": "9.1.0", "pelias-query": "9.1.0",
"pelias-sorting": "1.0.1", "pelias-sorting": "1.0.1",
"pelias-text-analyzer": "1.9.2", "pelias-text-analyzer": "1.10.2",
"predicates": "^1.0.1", "predicates": "^2.0.0",
"retry": "^0.10.1", "retry": "^0.10.1",
"stats-lite": "^2.0.4", "stats-lite": "^2.0.4",
"through2": "^2.0.3" "through2": "^2.0.3"

8
query/structured_geocoding.js

@ -1,4 +1,4 @@
var peliasQuery = require('pelias-query'), const peliasQuery = require('pelias-query'),
defaults = require('./search_defaults'), defaults = require('./search_defaults'),
textParser = require('./text_parser'), textParser = require('./text_parser'),
check = require('check-types'); check = require('check-types');
@ -6,7 +6,7 @@ var peliasQuery = require('pelias-query'),
//------------------------------ //------------------------------
// general-purpose search query // general-purpose search query
//------------------------------ //------------------------------
var structuredQuery = new peliasQuery.layout.StructuredFallbackQuery(); const structuredQuery = new peliasQuery.layout.StructuredFallbackQuery();
// scoring boost // scoring boost
structuredQuery.score( peliasQuery.view.focus_only_function( peliasQuery.view.phrase ) ); structuredQuery.score( peliasQuery.view.focus_only_function( peliasQuery.view.phrase ) );
@ -29,7 +29,7 @@ structuredQuery.filter( peliasQuery.view.categories );
**/ **/
function generateQuery( clean ){ function generateQuery( clean ){
var vs = new peliasQuery.Vars( defaults ); const vs = new peliasQuery.Vars( defaults );
// input text // input text
vs.var( 'input:name', clean.text ); vs.var( 'input:name', clean.text );
@ -95,7 +95,7 @@ function generateQuery( clean ){
textParser( clean.parsed_text, vs ); textParser( clean.parsed_text, vs );
} }
var q = getQuery(vs); const q = getQuery(vs);
// console.log(JSON.stringify(q.body, null, 2)); // console.log(JSON.stringify(q.body, null, 2));

21
sanitizer/_geonames_deprecation.js

@ -1,21 +1,32 @@
const _ = require('lodash'); const _ = require('lodash');
/** /**
with the release of coarse reverse as a separate thing and ES reverse only * Now that we have the pip-service, we have stopped supporting returning Geonames for coarse reverse.
handling venues, addresses, and streets, geonames make no sense in the reverse context *
* However, until the `/nearby` endpoint is finalized, we still want to support Geonames for
* _non-coarse_ reverse.
**/ **/
const coarse_reverse_message ='coarse /reverse does not support geonames. See https://github.com/pelias/pelias/issues/675 for more info';
function _sanitize( raw, clean, opts ) { function _sanitize( raw, clean, opts ) {
// error & warning messages // error & warning messages
const messages = { errors: [], warnings: [] }; const messages = { errors: [], warnings: [] };
// return taking no action unless this is a coarse-only reverse request
const non_coarse_layers = ['address', 'street', 'venue'];
const is_coarse_reverse = !_.isEmpty(clean.layers) &&
_.isEmpty(_.intersection(clean.layers, non_coarse_layers));
if (!is_coarse_reverse) {
return messages;
}
if (_.isEqual(clean.sources, ['geonames']) || _.isEqual(clean.sources, ['gn'])) { if (_.isEqual(clean.sources, ['geonames']) || _.isEqual(clean.sources, ['gn'])) {
messages.errors.push('/reverse does not support geonames'); messages.errors.push(coarse_reverse_message);
} else if (_.includes(clean.sources, 'geonames') || _.includes(clean.sources, 'gn')) { } else if (_.includes(clean.sources, 'geonames') || _.includes(clean.sources, 'gn')) {
clean.sources = _.without(clean.sources, 'geonames', 'gn'); clean.sources = _.without(clean.sources, 'geonames', 'gn');
messages.warnings.push('/reverse does not support geonames'); messages.warnings.push(coarse_reverse_message);
} }
return messages; return messages;

4
test/unit/controller/libpostal.js

@ -149,6 +149,7 @@ module.exports.tests.parse_is_called = (test, common) => {
controller(req, res, () => { controller(req, res, () => {
t.deepEquals(req, { t.deepEquals(req, {
clean: { clean: {
parser: 'libpostal',
parsed_text: 'replacement parsed_text' parsed_text: 'replacement parsed_text'
} }
}); });
@ -184,6 +185,7 @@ module.exports.tests.iso2_conversion = (test, common) => {
controller(req, res, () => { controller(req, res, () => {
t.deepEquals(req, { t.deepEquals(req, {
clean: { clean: {
parser: 'libpostal',
parsed_text: { parsed_text: {
locality: 'this is the locality' locality: 'this is the locality'
} }
@ -223,6 +225,7 @@ module.exports.tests.iso2_conversion = (test, common) => {
controller(req, res, () => { controller(req, res, () => {
t.deepEquals(req, { t.deepEquals(req, {
clean: { clean: {
parser: 'libpostal',
parsed_text: { parsed_text: {
country: 'unknown country code' country: 'unknown country code'
} }
@ -265,6 +268,7 @@ module.exports.tests.iso2_conversion = (test, common) => {
controller(req, res, () => { controller(req, res, () => {
t.deepEquals(req, { t.deepEquals(req, {
clean: { clean: {
parser: 'libpostal',
parsed_text: { parsed_text: {
country: 'ISO3 COUNTRY CODE' country: 'ISO3 COUNTRY CODE'
} }

4
test/unit/controller/place.js

@ -51,11 +51,11 @@ module.exports.tests.success = (test, common) => {
ids: [ ids: [
{ {
id: 'id1', id: 'id1',
layers: 'layer1' layer: 'layer1'
}, },
{ {
id: 'id2', id: 'id2',
layers: 'layer2' layer: 'layer2'
} }
] ]
}, },

39
test/unit/fixture/reverse_null_island.js

@ -1,39 +0,0 @@
var vs = require('../../../query/reverse_defaults');
module.exports = {
'query': {
'bool': {
'filter': [{
'geo_distance': {
'distance': '3km',
'distance_type': 'plane',
'optimize_bbox': 'indexed',
'center_point': {
'lat': 0,
'lon': 0
}
}
},
{
'terms': {
'layer': ['venue', 'address', 'street']
}
}]
}
},
'sort': [
'_score',
{
'_geo_distance': {
'center_point': {
'lat': 0,
'lon': 0
},
'order': 'asc',
'distance_type': 'plane'
}
}
],
'size': vs.size,
'track_scores': true
};

39
test/unit/fixture/reverse_standard.js

@ -1,39 +0,0 @@
var vs = require('../../../query/reverse_defaults');
module.exports = {
'query': {
'bool': {
'filter': [{
'geo_distance': {
'distance': '3km',
'distance_type': 'plane',
'optimize_bbox': 'indexed',
'center_point': {
'lat': 29.49136,
'lon': -82.50622
}
}
},
{
'terms': {
'layer': ['venue', 'address', 'street']
}
}]
}
},
'sort': [
'_score',
{
'_geo_distance': {
'center_point': {
'lat': 29.49136,
'lon': -82.50622
},
'order': 'asc',
'distance_type': 'plane'
}
}
],
'size': vs.size,
'track_scores': true
};

49
test/unit/fixture/reverse_with_boundary_country.js

@ -1,49 +0,0 @@
var vs = require('../../../query/reverse_defaults');
module.exports = {
'query': {
'bool': {
'must': [
{
'match': {
'parent.country_a': {
'analyzer': 'standard',
'query': 'ABC'
}
}
}
],
'filter': [{
'geo_distance': {
'distance': '3km',
'distance_type': 'plane',
'optimize_bbox': 'indexed',
'center_point': {
'lat': 29.49136,
'lon': -82.50622
}
}
},
{
'terms': {
'layer': ['venue', 'address', 'street']
}
}]
}
},
'sort': [
'_score',
{
'_geo_distance': {
'center_point': {
'lat': 29.49136,
'lon': -82.50622
},
'order': 'asc',
'distance_type': 'plane'
}
}
],
'size': vs.size,
'track_scores': true
};

41
test/unit/fixture/reverse_with_layer_filtering.js

@ -1,41 +0,0 @@
var vs = require('../../../query/reverse_defaults');
module.exports = {
'query': {
'bool': {
'filter': [
{
'geo_distance': {
'distance': '3km',
'distance_type': 'plane',
'optimize_bbox': 'indexed',
'center_point': {
'lat': 29.49136,
'lon': -82.50622
}
}
},
{
'terms': {
'layer': ['venue', 'address', 'street']
}
}
]
}
},
'sort': [
'_score',
{
'_geo_distance': {
'center_point': {
'lat': 29.49136,
'lon': -82.50622
},
'order': 'asc',
'distance_type': 'plane'
}
}
],
'size': vs.size,
'track_scores': true
};

41
test/unit/fixture/reverse_with_layer_filtering_non_coarse_subset.js

@ -1,41 +0,0 @@
var vs = require('../../../query/reverse_defaults');
module.exports = {
'query': {
'bool': {
'filter': [
{
'geo_distance': {
'distance': '3km',
'distance_type': 'plane',
'optimize_bbox': 'indexed',
'center_point': {
'lat': 29.49136,
'lon': -82.50622
}
}
},
{
'terms': {
'layer': ['venue', 'street']
}
}
]
}
},
'sort': [
'_score',
{
'_geo_distance': {
'center_point': {
'lat': 29.49136,
'lon': -82.50622
},
'order': 'asc',
'distance_type': 'plane'
}
}
],
'size': vs.size,
'track_scores': true
};

46
test/unit/fixture/reverse_with_source_filtering.js

@ -1,46 +0,0 @@
var vs = require('../../../query/reverse_defaults');
module.exports = {
'query': {
'bool': {
'filter': [
{
'geo_distance': {
'distance': '3km',
'distance_type': 'plane',
'optimize_bbox': 'indexed',
'center_point': {
'lat': 29.49136,
'lon': -82.50622
}
}
},
{
'terms': {
'source': ['test']
}
},
{
'terms': {
'layer': ['venue', 'address', 'street']
}
}
]
}
},
'sort': [
'_score',
{
'_geo_distance': {
'center_point': {
'lat': 29.49136,
'lon': -82.50622
},
'order': 'asc',
'distance_type': 'plane'
}
}
],
'size': vs.size,
'track_scores': true
};

71
test/unit/fixture/search_linguistic_viewport.js

@ -1,71 +0,0 @@
module.exports = {
'query': {
'function_score': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
'_name': 'fallback.street',
'boost': 5,
'must': [
{
'match_phrase': {
'address_parts.street': 'street value'
}
}
],
'should': [],
'filter': {
'term': {
'layer': 'street'
}
}
}
}
],
'filter': {
'bool': {
'must': [
{
'terms': {
'layer': [
'test'
]
}
}
]
}
}
}
},
'max_boost': 20,
'functions': [
{
'field_value_factor': {
'modifier': 'log1p',
'field': 'popularity',
'missing': 1
},
'weight': 1
},
{
'field_value_factor': {
'modifier': 'log1p',
'field': 'population',
'missing': 1
},
'weight': 2
}
],
'score_mode': 'avg',
'boost_mode': 'multiply'
}
},
'size': 10,
'track_scores': true,
'sort': [
'_score'
]
};

71
test/unit/fixture/search_linguistic_viewport_min_diagonal.js

@ -1,71 +0,0 @@
module.exports = {
'query': {
'function_score': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
'_name': 'fallback.street',
'boost': 5,
'must': [
{
'match_phrase': {
'address_parts.street': 'street value'
}
}
],
'should': [],
'filter': {
'term': {
'layer': 'street'
}
}
}
}
],
'filter': {
'bool': {
'must': [
{
'terms': {
'layer': [
'test'
]
}
}
]
}
}
}
},
'max_boost': 20,
'functions': [
{
'field_value_factor': {
'modifier': 'log1p',
'field': 'popularity',
'missing': 1
},
'weight': 1
},
{
'field_value_factor': {
'modifier': 'log1p',
'field': 'population',
'missing': 1
},
'weight': 2
}
],
'score_mode': 'avg',
'boost_mode': 'multiply'
}
},
'size': 10,
'track_scores': true,
'sort': [
'_score'
]
};

59
test/unit/fixture/structured_geocoding/boundary_country.json

@ -1,59 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"match": {
"parent.country_a": {
"analyzer": "standard",
"query": "ABC"
}
}
},
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

859
test/unit/fixture/structured_geocoding/fallback.json

@ -1,859 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"bool": {
"_name": "fallback.venue",
"must": [
{
"multi_match": {
"query": "query value",
"type": "phrase",
"fields": [
"phrase.default",
"category"
]
}
},
{
"multi_match": {
"query": "neighbourhood value",
"type": "phrase",
"fields": [
"parent.neighbourhood",
"parent.neighbourhood_a"
]
}
},
{
"multi_match": {
"query": "borough value",
"type": "phrase",
"fields": [
"parent.borough",
"parent.borough_a"
]
}
},
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.locality",
"parent.locality_a",
"parent.localadmin",
"parent.localadmin_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "venue"
}
}
}
},
{
"bool": {
"_name": "fallback.address",
"must": [
{
"match_phrase": {
"address_parts.number": "number value"
}
},
{
"match_phrase": {
"address_parts.street": "street value"
}
},
{
"multi_match": {
"query": "neighbourhood value",
"type": "phrase",
"fields": [
"parent.neighbourhood",
"parent.neighbourhood_a"
]
}
},
{
"multi_match": {
"query": "borough value",
"type": "phrase",
"fields": [
"parent.borough",
"parent.borough_a"
]
}
},
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.locality",
"parent.locality_a",
"parent.localadmin",
"parent.localadmin_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"should": [
{
"match_phrase": {
"address_parts.zip": "postalcode value"
}
}
],
"filter": {
"term": {
"layer": "address"
}
},
"boost": 10
}
},
{
"bool": {
"_name": "fallback.street",
"must": [
{
"match_phrase": {
"address_parts.street": "street value"
}
},
{
"multi_match": {
"query": "neighbourhood value",
"type": "phrase",
"fields": [
"parent.neighbourhood",
"parent.neighbourhood_a"
]
}
},
{
"multi_match": {
"query": "borough value",
"type": "phrase",
"fields": [
"parent.borough",
"parent.borough_a"
]
}
},
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.locality",
"parent.locality_a",
"parent.localadmin",
"parent.localadmin_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"should": [
{
"match_phrase": {
"address_parts.zip": "postalcode value"
}
}
],
"filter": {
"term": {
"layer": "street"
}
},
"boost": 5
}
},
{
"bool": {
"_name": "fallback.postalcode",
"must": [
{
"multi_match": {
"query": "postalcode value",
"type": "phrase",
"fields": [
"parent.postalcode"
]
}
},
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.locality",
"parent.locality_a",
"parent.localadmin",
"parent.localadmin_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "postalcode"
}
}
}
},
{
"bool": {
"_name": "fallback.neighbourhood",
"must": [
{
"multi_match": {
"query": "neighbourhood value",
"type": "phrase",
"fields": [
"parent.neighbourhood",
"parent.neighbourhood_a"
]
}
},
{
"multi_match": {
"query": "borough value",
"type": "phrase",
"fields": [
"parent.borough",
"parent.borough_a"
]
}
},
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.locality",
"parent.locality_a",
"parent.localadmin",
"parent.localadmin_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "neighbourhood"
}
}
}
},
{
"bool": {
"_name": "fallback.borough",
"must": [
{
"multi_match": {
"query": "borough value",
"type": "phrase",
"fields": [
"parent.borough",
"parent.borough_a"
]
}
},
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.locality",
"parent.locality_a",
"parent.localadmin",
"parent.localadmin_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "borough"
}
}
}
},
{
"bool": {
"_name": "fallback.locality",
"must": [
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.locality",
"parent.locality_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "locality"
}
}
}
},
{
"bool": {
"_name": "fallback.localadmin",
"must": [
{
"multi_match": {
"query": "city value",
"type": "phrase",
"fields": [
"parent.localadmin",
"parent.localadmin_a"
]
}
},
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a",
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "localadmin"
}
}
}
},
{
"bool": {
"_name": "fallback.county",
"must": [
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.county",
"parent.county_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "county"
}
}
}
},
{
"bool": {
"_name": "fallback.macrocounty",
"must": [
{
"multi_match": {
"query": "county value",
"type": "phrase",
"fields": [
"parent.macrocounty",
"parent.macrocounty_a"
]
}
},
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a",
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "macrocounty"
}
}
}
},
{
"bool": {
"_name": "fallback.region",
"must": [
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.region",
"parent.region_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "region"
}
}
}
},
{
"bool": {
"_name": "fallback.macroregion",
"must": [
{
"multi_match": {
"query": "state value",
"type": "phrase",
"fields": [
"parent.macroregion",
"parent.macroregion_a"
]
}
},
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a",
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "macroregion"
}
}
}
},
{
"bool": {
"_name": "fallback.dependency",
"must": [
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.dependency",
"parent.dependency_a"
]
}
}
],
"filter": {
"term": {
"layer": "dependency"
}
}
}
},
{
"bool": {
"_name": "fallback.country",
"must": [
{
"multi_match": {
"query": "country value",
"type": "phrase",
"fields": [
"parent.country",
"parent.country_a"
]
}
}
],
"filter": {
"term": {
"layer": "country"
}
}
}
}
]
}
},
"max_boost": 20,
"functions": [
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 20,
"track_scores": true
}

62
test/unit/fixture/structured_geocoding/linguistic_bbox.json

@ -1,62 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"geo_bounding_box": {
"type": "indexed",
"center_point": {
"top": 11.51,
"right": -61.84,
"bottom": 47.47,
"left": -103.16
}
}
},
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

65
test/unit/fixture/structured_geocoding/linguistic_focus.json

@ -1,65 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"weight": 2,
"linear": {
"center_point": {
"origin": {
"lat": 29.49136,
"lon": -82.50622
},
"offset": "0km",
"scale": "50km",
"decay": 0.5
}
}
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

76
test/unit/fixture/structured_geocoding/linguistic_focus_bbox.json

@ -1,76 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"geo_bounding_box": {
"type": "indexed",
"center_point": {
"top": 11.51,
"right": -61.84,
"bottom": 47.47,
"left": -103.16
}
}
},
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"weight": 2,
"linear": {
"center_point": {
"origin": {
"lat": 29.49136,
"lon": -82.50622
},
"offset": "0km",
"scale": "50km",
"decay": 0.5
}
}
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

65
test/unit/fixture/structured_geocoding/linguistic_focus_null_island.json

@ -1,65 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"weight": 2,
"linear": {
"center_point": {
"origin": {
"lat": 0,
"lon": 0
},
"offset": "0km",
"scale": "50km",
"decay": 0.5
}
}
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

51
test/unit/fixture/structured_geocoding/linguistic_only.json

@ -1,51 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

51
test/unit/fixture/structured_geocoding/linguistic_viewport.json

@ -1,51 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

51
test/unit/fixture/structured_geocoding/linguistic_viewport_min_diagonal.json

@ -1,51 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [],
"filter": {
"bool": {
"must": [
{
"terms": {
"layer": [
"test"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 10,
"track_scores": true
}

60
test/unit/fixture/structured_geocoding/postalcode_only.js

@ -1,60 +0,0 @@
module.exports = {
'query': {
'function_score': {
'query': {
'bool': {
'minimum_should_match': 1,
'should': [
{
'bool': {
'_name': 'fallback.postalcode',
'must': [
{
'multi_match': {
'query': 'postalcode value',
'type': 'phrase',
'fields': [
'parent.postalcode'
]
}
}
],
'filter': {
'term': {
'layer': 'postalcode'
}
}
}
}
]
}
},
'max_boost': 20,
'functions': [
{
'field_value_factor': {
'modifier': 'log1p',
'field': 'popularity',
'missing': 1
},
'weight': 1
},
{
'field_value_factor': {
'modifier': 'log1p',
'field': 'population',
'missing': 1
},
'weight': 2
}
],
'score_mode': 'avg',
'boost_mode': 'multiply'
}
},
'size': 20,
'track_scores': true,
'sort': [
'_score'
]
};

52
test/unit/fixture/structured_geocoding/with_source_filtering.json

@ -1,52 +0,0 @@
{
"query": {
"function_score": {
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
],
"filter": {
"bool": {
"must": [
{
"terms": {
"source": [
"test_source"
]
}
}
]
}
}
}
},
"max_boost": 20,
"functions": [
{
"field_value_factor": {
"modifier": "log1p",
"field": "popularity",
"missing": 1
},
"weight": 1
},
{
"field_value_factor": {
"modifier": "log1p",
"field": "population",
"missing": 1
},
"weight": 2
}
],
"score_mode": "avg",
"boost_mode": "multiply"
}
},
"sort": [
"_score"
],
"size": 20,
"track_scores": true
}

7
test/unit/query/MockQuery.js

@ -3,6 +3,7 @@
module.exports = class MockQuery { module.exports = class MockQuery {
constructor() { constructor() {
this._score_functions = []; this._score_functions = [];
this._sort_functions = [];
this._filter_functions = []; this._filter_functions = [];
} }
@ -10,6 +11,7 @@ module.exports = class MockQuery {
return { return {
vs: vs, vs: vs,
score_functions: this._score_functions, score_functions: this._score_functions,
sort_functions: this._sort_functions,
filter_functions: this._filter_functions filter_functions: this._filter_functions
}; };
} }
@ -19,6 +21,11 @@ module.exports = class MockQuery {
return this; return this;
} }
sort(view) {
this._sort_functions.push(view);
return this;
}
filter(view) { filter(view) {
this._filter_functions.push(view); this._filter_functions.push(view);
return this; return this;

557
test/unit/query/reverse.js

@ -1,190 +1,503 @@
var generate = require('../../../query/reverse'); const generate = require('../../../query/reverse');
const _ = require('lodash');
const proxyquire = require('proxyquire').noCallThru();
const MockQuery = require('./MockQuery');
const all_layers = require('../../../helper/type_mapping').layers;
// helper for canned views
const views = {
boundary_country: 'boundary_country view',
boundary_circle: 'boundary_circle view',
sources: 'sources view',
layers: 'layers view',
categories: 'categories view',
sort_distance: 'sort_distance view'
};
module.exports.tests = {}; module.exports.tests = {};
module.exports.tests.interface = function(test, common) { module.exports.tests.interface = (test, common) => {
test('valid interface', function(t) { test('valid interface', t => {
t.equal(typeof generate, 'function', 'valid function'); t.equal(typeof generate, 'function', 'valid function');
t.end(); t.end();
}); });
}; };
module.exports.tests.query = function(test, common) { module.exports.tests.query = (test, common) => {
test('valid query', function(t) { test('base no frills', t => {
var query = generate({ const clean = {};
'point.lat': 29.49136,
'point.lon': -82.50622, const query = proxyquire('../../../query/reverse', {
'boundary.circle.lat': 29.49136, 'pelias-query': {
'boundary.circle.lon': -82.50622, layout: {
'boundary.circle.radius': 3 FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {
default_parameter_1: 'first default parameter',
default_parameter_2: 'second default parameter'
}
})(clean);
t.equals(query.type, 'reverse', 'query type set');
t.deepEquals(query.body.vs.var('default_parameter_1').toString(), 'first default parameter');
t.deepEquals(query.body.vs.var('default_parameter_2').toString(), 'second default parameter');
t.notOk(query.body.vs.isset('size'));
t.notOk(query.body.vs.isset('sources'));
t.notOk(query.body.vs.isset('layers'));
t.notOk(query.body.vs.isset('focus:point:lat'));
t.notOk(query.body.vs.isset('focus:point:lon'));
t.notOk(query.body.vs.isset('boundary:circle:lat'));
t.notOk(query.body.vs.isset('boundary:circle:lon'));
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.notOk(query.body.vs.isset('boundary:country'));
t.notOk(query.body.vs.isset('input:categories'));
t.deepEquals(query.body.score_functions, [
'boundary_country view'
]);
t.deepEquals(query.body.filter_functions, [
'boundary_circle view',
'sources view',
'layers view',
'categories view'
]);
t.deepEquals(query.body.sort_functions, [
'sort_distance view'
]);
t.end();
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); test('clean.querySize should set size parameter', t => {
var expected = require('../fixture/reverse_standard'); const clean = {
querySize: 17
};
t.deepEqual(compiled.type, 'reverse', 'query type set'); const query = proxyquire('../../../query/reverse', {
t.deepEqual(compiled.body, expected, 'reverse_standard'); 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.deepEquals(query.body.vs.var('size').toString(), 17);
t.end(); t.end();
}); });
test('valid query - null island', function(t) { };
var query = generate({
'point.lat': 0, module.exports.tests.sources = (test, common) => {
'point.lon': 0, test('non-array clean.sources should not set sources in vs', t => {
'boundary.circle.lat': 0, const clean = {
'boundary.circle.lon': 0, sources: 'this is not an array'
'boundary.circle.radius': 3 };
const query = proxyquire('../../../query/reverse', {
'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('sources'));
t.end();
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); test('empty array clean.sources should not set sources in vs', t => {
var expected = require('../fixture/reverse_null_island'); const clean = {
sources: []
};
t.deepEqual(compiled.type, 'reverse', 'query type set'); const query = proxyquire('../../../query/reverse', {
t.deepEqual(compiled.body, expected, 'reverse_null_island'); 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('sources'));
t.end(); t.end();
}); });
test('valid query with radius', function(t) { test('non-empty array clean.sources should set sources in vs', t => {
var query = generate({ const clean = {
'point.lat': 29.49136, sources: ['source 1', 'source 2']
'point.lon': -82.50622, };
'boundary.circle.lat': 29.49136,
'boundary.circle.lon': -82.50622, const query = proxyquire('../../../query/reverse', {
'boundary.circle.radius': 123 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.deepEquals(query.body.vs.var('sources').toString(), ['source 1', 'source 2']);
t.end();
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); };
var expected = '123km';
module.exports.tests.layers = (test, common) => {
test('non-array clean.layers should not set sources in vs', t => {
const clean = {
layers: 'this is not an array'
};
t.deepEqual(compiled.type, 'reverse', 'query type set'); const query = proxyquire('../../../query/reverse', {
t.deepEqual(compiled.body.query.bool.filter[0].geo_distance.distance, expected, 'distance set to boundary circle radius'); 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('layers'));
t.end(); t.end();
}); });
// for coarse reverse cases where boundary circle radius isn't used test('empty array clean.layers should not set sources in vs', t => {
test('undefined radius set to default radius', function(t) { const clean = {
var query = generate({ layers: []
'point.lat': 12.12121, };
'point.lon': 21.21212,
'boundary.circle.lat': 12.12121, const query = proxyquire('../../../query/reverse', {
'boundary.circle.lon': 21.21212 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('layers'));
t.end();
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); test('non-empty array clean.layers should only set non-coarse layers in vs', t => {
var expected = '1km'; const clean = {
layers: all_layers
};
t.deepEqual(compiled.type, 'reverse', 'query type set'); const query = proxyquire('../../../query/reverse', {
t.deepEqual(compiled.body.query.bool.filter[0].geo_distance.distance, expected, 'distance set to default boundary circle radius'); 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.deepEquals(query.body.vs.var('layers').toString(), ['address', 'venue', 'street']);
t.end(); t.end();
}); });
test('boundary.circle lat/lon/radius - overrides point.lat/lon when set', function(t) {
var clean = {
'point.lat': 29.49136,
'point.lon': -82.50622,
'boundary.circle.lat': 111,
'boundary.circle.lon': 333,
'boundary.circle.radius': 3
}; };
var query = generate(clean);
var compiled = JSON.parse( JSON.stringify( query ) );
// this should not equal `point.lat` and `point.lon` as it was explitely specified module.exports.tests.focus_point = (test, common) => {
var expected = { lat: clean['boundary.circle.lat'], lon: clean['boundary.circle.lon'] }; test('numeric point.lat and non-numeric point.lon should not add focus:point:* fields', t => {
var centroid = compiled.body.query.bool.filter[0].geo_distance.center_point; const clean = {
'point.lat': 12.121212,
'point.lon': 'this is non-numeric'
};
t.deepEqual(compiled.type, 'reverse', 'query type set'); const query = proxyquire('../../../query/reverse', {
t.deepEqual(centroid, expected, 'reverse: boundary.circle/lon overrides point.lat/lon'); 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('focus:point:lat'));
t.notOk(query.body.vs.isset('focus:point:lon'));
t.end(); t.end();
});
test('size fuzz test', function(t) {
// test different sizes
var sizes = [1,4,20,undefined,null];
var expected = [1,4,20,1,1];
sizes.forEach( function( size, index ){
var query = generate({
'point.lat': 29.49136, 'point.lon': -82.50622, querySize: size
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); test('non-numeric point.lat and numeric point.lon should not add focus:point:* fields', t => {
t.equal( compiled.body.size, expected[index], 'valid reverse query for size: '+ size); const clean = {
'point.lat': 'this is non-numeric',
'point.lon': 21.212121
};
const query = proxyquire('../../../query/reverse', {
'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('focus:point:lat'));
t.notOk(query.body.vs.isset('focus:point:lon'));
t.end();
}); });
test('numeric point.lat and point.lon should add focus:point:* fields', t => {
const clean = {
'point.lat': 12.121212,
'point.lon': 21.212121
};
const query = proxyquire('../../../query/reverse', {
'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.deepEquals(query.body.vs.var('focus:point:lat').toString(), 12.121212);
t.deepEquals(query.body.vs.var('focus:point:lon').toString(), 21.212121);
t.end(); t.end();
}); });
test('valid boundary.country reverse search', function(t) { };
var query = generate({
'point.lat': 29.49136, module.exports.tests.boundary_circle = (test, common) => {
'point.lon': -82.50622, test('numeric lat and non-numeric lon should not add boundary:circle:* fields', t => {
'boundary.circle.lat': 29.49136, const clean = {
'boundary.circle.lon': -82.50622, 'boundary.circle.lat': 12.121212,
'boundary.circle.radius': 3, 'boundary.circle.lon': 'this is non-numeric'
'boundary.country': 'ABC' };
const query = proxyquire('../../../query/reverse', {
'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('boundary:circle:lat'));
t.notOk(query.body.vs.isset('boundary:circle:lon'));
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.end();
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); test('non-numeric lat and numeric lon should not add boundary:circle:* fields', t => {
var expected = require('../fixture/reverse_with_boundary_country'); const clean = {
'boundary.circle.lat': 'this is non-numeric',
'boundary.circle.lon': 21.212121
};
t.deepEqual(compiled.type, 'reverse', 'query type set'); const query = proxyquire('../../../query/reverse', {
t.deepEqual(compiled.body, expected, 'valid reverse query with boundary.country'); 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('boundary:circle:lat'));
t.notOk(query.body.vs.isset('boundary:circle:lon'));
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.end(); t.end();
}); });
test('valid sources filter', function(t) { test('radius not supplied should default to value from reverse_defaults', t => {
var query = generate({ const clean = {
'point.lat': 29.49136, 'boundary.circle.lat': 12.121212,
'point.lon': -82.50622, 'boundary.circle.lon': 21.212121
'boundary.circle.lat': 29.49136, };
'boundary.circle.lon': -82.50622,
'boundary.circle.radius': 3, const query = proxyquire('../../../query/reverse', {
'sources': ['test'] 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {
'boundary:circle:radius': 17
}
})(clean);
t.deepEquals(query.body.vs.var('boundary:circle:lat').toString(), 12.121212);
t.deepEquals(query.body.vs.var('boundary:circle:lon').toString(), 21.212121);
t.deepEquals(query.body.vs.var('boundary:circle:radius').toString(), 17);
t.end();
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); test('numeric radius supplied should be used instead of value from reverse_defaults', t => {
var expected = require('../fixture/reverse_with_source_filtering'); const clean = {
'boundary.circle.lat': 12.121212,
'boundary.circle.lon': 21.212121,
'boundary.circle.radius': 17
};
const query = proxyquire('../../../query/reverse', {
'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {
'boundary:circle:radius': 18
}
})(clean);
t.deepEqual(compiled.type, 'reverse', 'query type set'); t.deepEquals(query.body.vs.var('boundary:circle:lat').toString(), 12.121212);
t.deepEqual(compiled.body, expected, 'valid reverse query with source filtering'); t.deepEquals(query.body.vs.var('boundary:circle:lon').toString(), 21.212121);
t.deepEquals(query.body.vs.var('boundary:circle:radius').toString(), '17km');
t.end(); t.end();
}); });
test('valid layers filter', (t) => { test('non-numeric radius supplied should not set any boundary:circle:radius', t => {
const query = generate({ const clean = {
'point.lat': 29.49136, 'boundary.circle.lat': 12.121212,
'point.lon': -82.50622, 'boundary.circle.lon': 21.212121,
'boundary.circle.lat': 29.49136, 'boundary.circle.radius': 'this is non-numeric'
'boundary.circle.lon': -82.50622, };
'boundary.circle.radius': 3,
// only venue, address, and street layers should be retained const query = proxyquire('../../../query/reverse', {
'layers': ['neighbourhood', 'venue', 'locality', 'address', 'region', 'street', 'country'] 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {
'boundary:circle:radius': 18
}
})(clean);
t.deepEquals(query.body.vs.var('boundary:circle:lat').toString(), 12.121212);
t.deepEquals(query.body.vs.var('boundary:circle:lon').toString(), 21.212121);
t.deepEquals(query.body.vs.var('boundary:circle:radius').toString(), 18);
t.end();
}); });
const compiled = JSON.parse( JSON.stringify( query ) ); };
const expected = require('../fixture/reverse_with_layer_filtering');
module.exports.tests.boundary_country = (test, common) => {
test('non-string boundary.country should not set boundary:country', t => {
[17, undefined, {}, [], true, null].forEach(value => {
const clean = {
'boundary.country': value
};
const query = proxyquire('../../../query/reverse', {
'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.notOk(query.body.vs.isset('boundary:country'));
});
t.deepEqual(compiled.type, 'reverse', 'query type set');
t.deepEqual(compiled.body, expected, 'valid reverse query with source filtering');
t.end(); t.end();
}); });
test('valid layers filter - subset of non-coarse layers', (t) => { test('string boundary.country should set boundary:country', t => {
const query = generate({ const clean = {
'point.lat': 29.49136, 'boundary.country': 'boundary country value'
'point.lon': -82.50622, };
'boundary.circle.lat': 29.49136,
'boundary.circle.lon': -82.50622, const query = proxyquire('../../../query/reverse', {
'boundary.circle.radius': 3, 'pelias-query': {
// only venue, address, and street layers should be retained layout: {
'layers': ['neighbourhood', 'venue', 'street', 'locality'] FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.deepEquals(query.body.vs.var('boundary:country').toString(), 'boundary country value');
t.end();
}); });
const compiled = JSON.parse( JSON.stringify( query ) ); };
const expected = require('../fixture/reverse_with_layer_filtering_non_coarse_subset');
module.exports.tests.categories = (test, common) => {
test('categories supplied should set input:categories', t => {
const clean = {
categories: 'categories value'
};
t.deepEqual(compiled.type, 'reverse', 'query type set'); const query = proxyquire('../../../query/reverse', {
t.deepEqual(compiled.body, expected, 'valid reverse query with source filtering'); 'pelias-query': {
layout: {
FilteredBooleanQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./reverse_defaults': {}
})(clean);
t.deepEquals(query.body.vs.var('input:categories').toString(), 'categories value');
t.end(); t.end();
}); });

48
test/unit/query/search.js

@ -99,54 +99,6 @@ module.exports.tests.query = function(test, common) {
t.end(); 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) { test('search search + focus on null island', function(t) {
var clean = { var clean = {
parsed_text: { parsed_text: {

663
test/unit/query/structured_geocoding.js

@ -1,253 +1,606 @@
var generate = require('../../../query/structured_geocoding'); const generate = require('../../../query/structured_geocoding');
var fs = require('fs'); const _ = require('lodash');
const proxyquire = require('proxyquire').noCallThru();
const MockQuery = require('./MockQuery');
// helper for canned views
const views = {
focus_only_function: () => 'focus_only_function view',
popularity_only_function: 'popularity_only_function view',
population_only_function: 'population_only_function view',
boundary_country: 'boundary_country view',
boundary_circle: 'boundary_circle view',
boundary_rect: 'boundary_rect view',
sources: 'sources view',
layers: 'layers view',
categories: 'categories view'
};
module.exports.tests = {}; module.exports.tests = {};
module.exports.tests.interface = function(test, common) { module.exports.tests.interface = (test, common) => {
test('valid interface', function(t) { test('valid interface', t => {
t.equal(typeof generate, 'function', 'valid function'); t.equal(typeof generate, 'function', 'valid function');
t.end(); t.end();
}); });
}; };
module.exports.tests.query = function(test, common) { module.exports.tests.query = (test, common) => {
test('valid search + focus + bbox', function(t) { test('base no frills', t => {
var clean = { const clean = {
parsed_text: { text: 'text value',
}, sources: 'sources value',
text: 'test', layers: 'layers value'
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); const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': {
default_parameter_1: 'first default parameter',
default_parameter_2: 'second default parameter'
},
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
t.equals(query.type, 'fallback', 'query type set');
t.equals(query.body.vs.var('input:name').toString(), 'text value');
t.equals(query.body.vs.var('sources').toString(), 'sources value');
t.equals(query.body.vs.var('layers').toString(), 'layers value');
t.deepEquals(query.body.vs.var('default_parameter_1').toString(), 'first default parameter');
t.deepEquals(query.body.vs.var('default_parameter_2').toString(), 'second default parameter');
t.notOk(query.body.vs.isset('size'));
t.notOk(query.body.vs.isset('focus:point:lat'));
t.notOk(query.body.vs.isset('focus:point:lon'));
t.notOk(query.body.vs.isset('boundary:rect:top'));
t.notOk(query.body.vs.isset('boundary:rect:right'));
t.notOk(query.body.vs.isset('boundary:rect:bottom'));
t.notOk(query.body.vs.isset('boundary:rect:left'));
t.notOk(query.body.vs.isset('boundary:circle:lat'));
t.notOk(query.body.vs.isset('boundary:circle:lon'));
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.notOk(query.body.vs.isset('boundary:country'));
t.deepEquals(query.body.score_functions, [
'focus_only_function view',
'popularity_only_function view',
'population_only_function view'
]);
t.deepEquals(query.body.filter_functions, [
'boundary_country view',
'boundary_circle view',
'boundary_rect view',
'sources view',
'layers view',
'categories view'
]);
var compiled = JSON.parse( JSON.stringify( query ) ); t.end();
var expected = require('../fixture/structured_geocoding/linguistic_focus_bbox'); });
t.deepEqual(compiled.type, 'fallback', 'query type set'); test('clean.parsed_text and vs should be passed to textParser', t => {
t.deepEqual(compiled.body, expected, 'search_linguistic_focus_bbox'); const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
parsed_text: 'parsed_text value'
};
const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': {
default_parameter_1: 'first default parameter',
default_parameter_2: 'second default parameter'
},
'./text_parser': (parsed_text, vs) => {
vs.var('text_parser:value', 'this value populated by text_parser');
}
})(clean);
t.deepEquals(query.body.vs.var('text_parser:value').toString(), 'this value populated by text_parser');
t.end(); t.end();
}); });
test('valid search + bbox', function(t) {
var clean = {
parsed_text: {
},
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); module.exports.tests.query_size = (test, common) => {
test('size should be set when querySize is available', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
querySize: 17
};
var compiled = JSON.parse( JSON.stringify( query ) ); const query = proxyquire('../../../query/structured_geocoding', {
var expected = require('../fixture/structured_geocoding/linguistic_bbox'); 'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
t.equals(query.body.vs.var('size').toString(), 17);
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'search_linguistic_bbox');
t.end(); t.end();
}); });
test('valid lingustic-only search', function(t) {
var clean = {
parsed_text: {
},
text: 'test', querySize: 10,
layers: ['test']
}; };
var query = generate(clean); module.exports.tests.focus_point_lat_lon = (test, common) => {
test('missing focus.point.lat shouldn\'t set focus:point:lat/lon', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'focus.point.lon': 21.212121
};
var compiled = JSON.parse( JSON.stringify( query ) ); const query = proxyquire('../../../query/structured_geocoding', {
var expected = require('../fixture/structured_geocoding/linguistic_only'); 'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
t.notOk(query.body.vs.isset('focus:point:lat'));
t.notOk(query.body.vs.isset('focus:point:lon'));
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'search_linguistic_only');
t.end(); t.end();
}); });
test('search search + focus', function(t) { test('missing focus.point.lon shouldn\'t set focus:point:lat/lon', t => {
var clean = { const clean = {
parsed_text: { text: 'text value',
}, sources: 'sources value',
text: 'test', querySize: 10, layers: 'layers value',
'focus.point.lat': 29.49136, 'focus.point.lon': -82.50622, 'focus.point.lat': 12.121212
layers: ['test']
}; };
var query = generate(clean); const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
var compiled = JSON.parse( JSON.stringify( query ) ); t.notOk(query.body.vs.isset('focus:point:lat'));
var expected = require('../fixture/structured_geocoding/linguistic_focus'); t.notOk(query.body.vs.isset('focus:point:lon'));
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'search_linguistic_focus');
t.end(); t.end();
}); });
test('search search + viewport', function(t) { test('focus.point.lat/lon should set focus:point:lat/lon', t => {
var clean = { const clean = {
parsed_text: { text: 'text value',
}, sources: 'sources value',
text: 'test', querySize: 10, layers: 'layers value',
'focus.viewport.min_lat': 28.49136, 'focus.point.lat': 12.121212,
'focus.viewport.max_lat': 30.49136, 'focus.point.lon': 21.212121
'focus.viewport.min_lon': -87.50622,
'focus.viewport.max_lon': -77.50622,
layers: ['test']
}; };
var query = generate(clean); const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
var compiled = JSON.parse( JSON.stringify( query ) ); t.equals(query.body.vs.var('focus:point:lat').toString(), 12.121212);
var expected = require('../fixture/structured_geocoding/linguistic_viewport'); t.equals(query.body.vs.var('focus:point:lon').toString(), 21.212121);
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'search_linguistic_viewport');
t.end(); 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: {
},
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); module.exports.tests.boundary_rect = (test, common) => {
test('missing boundary.rect.min_lat shouldn\'t set boundary:rect fields', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.rect.max_lat': 13.131313,
'boundary.rect.min_lon': 21.212121,
'boundary.rect.max_lon': 31.313131
};
var compiled = JSON.parse( JSON.stringify( query ) ); const query = proxyquire('../../../query/structured_geocoding', {
var expected = require('../fixture/structured_geocoding/linguistic_viewport_min_diagonal'); 'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
t.notOk(query.body.vs.isset('boundary:rect:top'));
t.notOk(query.body.vs.isset('boundary:rect:right'));
t.notOk(query.body.vs.isset('boundary:rect:bottom'));
t.notOk(query.body.vs.isset('boundary:rect:left'));
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'valid search query');
t.end(); t.end();
}); });
test('search search + focus on null island', function(t) { test('missing boundary.rect.max_lat shouldn\'t set boundary:rect fields', t => {
var clean = { const clean = {
parsed_text: { text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.rect.min_lat': 12.121212,
'boundary.rect.min_lon': 21.212121,
'boundary.rect.max_lon': 31.313131
};
const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
}, },
text: 'test', querySize: 10, view: views,
'focus.point.lat': 0, 'focus.point.lon': 0, Vars: require('pelias-query').Vars
layers: ['test'] },
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
t.notOk(query.body.vs.isset('boundary:rect:top'));
t.notOk(query.body.vs.isset('boundary:rect:right'));
t.notOk(query.body.vs.isset('boundary:rect:bottom'));
t.notOk(query.body.vs.isset('boundary:rect:left'));
t.end();
});
test('missing boundary.rect.min_lon shouldn\'t set boundary:rect fields', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.rect.min_lat': 12.121212,
'boundary.rect.max_lat': 13.131313,
'boundary.rect.max_lon': 31.313131
}; };
var query = generate(clean); const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
var compiled = JSON.parse( JSON.stringify( query ) ); t.notOk(query.body.vs.isset('boundary:rect:top'));
var expected = require('../fixture/structured_geocoding/linguistic_focus_null_island'); t.notOk(query.body.vs.isset('boundary:rect:right'));
t.notOk(query.body.vs.isset('boundary:rect:bottom'));
t.notOk(query.body.vs.isset('boundary:rect:left'));
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'search_linguistic_focus_null_island');
t.end(); t.end();
}); });
test('parsed_text with all fields should use FallbackQuery', function(t) { test('missing boundary.rect.max_lon shouldn\'t set boundary:rect fields', t => {
var clean = { const clean = {
parsed_text: { text: 'text value',
query: 'query value', sources: 'sources value',
category: 'category value', layers: 'layers value',
number: 'number value', 'boundary.rect.min_lat': 12.121212,
street: 'street value', 'boundary.rect.max_lat': 13.131313,
neighbourhood: 'neighbourhood value', 'boundary.rect.min_lon': 21.212121
borough: 'borough value', };
postalcode: 'postalcode value',
city: 'city value', const query = proxyquire('../../../query/structured_geocoding', {
county: 'county value', 'pelias-query': {
state: 'state value', layout: {
country: 'country value' StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
} }
})(clean);
t.notOk(query.body.vs.isset('boundary:rect:top'));
t.notOk(query.body.vs.isset('boundary:rect:right'));
t.notOk(query.body.vs.isset('boundary:rect:bottom'));
t.notOk(query.body.vs.isset('boundary:rect:left'));
t.end();
});
test('focus.point.lat/lon should set focus:point:lat/lon', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.rect.min_lat': 12.121212,
'boundary.rect.max_lat': 13.131313,
'boundary.rect.min_lon': 21.212121,
'boundary.rect.max_lon': 31.313131
}; };
var query = generate(clean); const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
var compiled = JSON.parse(JSON.stringify(query)); t.equals(query.body.vs.var('boundary:rect:top').toString(), 13.131313);
var expected = require('../fixture/structured_geocoding/fallback'); t.equals(query.body.vs.var('boundary:rect:right').toString(), 31.313131);
t.equals(query.body.vs.var('boundary:rect:bottom').toString(), 12.121212);
t.equals(query.body.vs.var('boundary:rect:left').toString(), 21.212121);
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'fallbackQuery');
t.end(); t.end();
}); });
test('parsed_text with all fields should use FallbackQuery', function(t) { };
var clean = {
parsed_text: { module.exports.tests.boundary_circle = (test, common) => {
postalcode: 'postalcode value' test('missing boundary.circle.lat shouldn\'t set boundary:circle fields', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.circle.lon': 21.212121,
'boundary.circle.radius': 17
};
const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
} }
})(clean);
t.notOk(query.body.vs.isset('boundary:circle:lat'));
t.notOk(query.body.vs.isset('boundary:circle:lon'));
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.end();
});
test('missing boundary.circle.lon shouldn\'t set boundary:circle fields', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.circle.lat': 12.121212,
'boundary.circle.radius': 17
}; };
var query = generate(clean); const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
var compiled = JSON.parse(JSON.stringify(query)); t.notOk(query.body.vs.isset('boundary:circle:lat'));
var expected = require('../fixture/structured_geocoding/postalcode_only'); t.notOk(query.body.vs.isset('boundary:circle:lon'));
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'structured postalcode only');
t.end(); t.end();
}); });
test('valid boundary.country search', function(t) { test('missing boundary.circle.radius should set lat/lon but not radius', t => {
var clean = { const clean = {
parsed_text: { text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.circle.lat': 12.121212,
'boundary.circle.lon': 21.212121
};
const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
}, },
text: 'test', querySize: 10, './search_defaults': { },
layers: ['test'], './text_parser': () => {
'boundary.country': 'ABC' t.fail('text_parser should not have been called');
}
})(clean);
t.equals(query.body.vs.var('boundary:circle:lat').toString(), 12.121212);
t.equals(query.body.vs.var('boundary:circle:lon').toString(), 21.212121);
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.end();
});
test('boundary.circle.* should set lat/lon/radius with last rounded and in kilometers', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.circle.lat': 12.121212,
'boundary.circle.lon': 21.212121,
'boundary.circle.radius': 17.5
}; };
var query = generate(clean); const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
var compiled = JSON.parse( JSON.stringify( query ) ); t.equals(query.body.vs.var('boundary:circle:lat').toString(), 12.121212);
var expected = require('../fixture/structured_geocoding/boundary_country'); t.equals(query.body.vs.var('boundary:circle:lon').toString(), 21.212121);
t.equals(query.body.vs.var('boundary:circle:radius').toString(), '18km');
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'search: valid boundary.country query');
t.end(); t.end();
}); });
test('valid sources filter', function(t) { test('missing boundary.circle.lat/lon but existing boundary.circle.radius should not set any', t => {
var clean = { const clean = {
parsed_text: { text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.circle.radius': 17
};
const query = proxyquire('../../../query/structured_geocoding', {
'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
}, },
'text': 'test', view: views,
'sources': ['test_source'] Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
t.notOk(query.body.vs.isset('boundary:circle:lat'));
t.notOk(query.body.vs.isset('boundary:circle:lon'));
t.notOk(query.body.vs.isset('boundary:circle:radius'));
t.end();
});
}; };
var query = generate(clean); module.exports.tests.boundary_country = (test, common) => {
test('boundary.country available shoul set boundary:country', t => {
const clean = {
text: 'text value',
sources: 'sources value',
layers: 'layers value',
'boundary.country': 'boundary country value'
};
var compiled = JSON.parse( JSON.stringify( query ) ); const query = proxyquire('../../../query/structured_geocoding', {
var expected = require('../fixture/structured_geocoding/with_source_filtering'); 'pelias-query': {
layout: {
StructuredFallbackQuery: MockQuery
},
view: views,
Vars: require('pelias-query').Vars
},
'./search_defaults': { },
'./text_parser': () => {
t.fail('text_parser should not have been called');
}
})(clean);
t.equals(query.body.vs.var('boundary:country').toString(), 'boundary country value');
t.deepEqual(compiled.type, 'fallback', 'query type set');
t.deepEqual(compiled.body, expected, 'search: valid search query with source filtering');
t.end(); t.end();
}); });
}; };
module.exports.all = function (tape, common) { module.exports.all = (tape, common) => {
function test(name, testFunction) { function test(name, testFunction) {
return tape('structured_geocoding query ' + name, testFunction); return tape(`structured_geocoding query ${name}`, testFunction);
} }
for( var testCase in module.exports.tests ){ for( var testCase in module.exports.tests ){

44
test/unit/sanitizer/_geonames_deprecation.js

@ -2,6 +2,8 @@ const sanitizer = require('../../../sanitizer/_geonames_deprecation')();
module.exports.tests = {}; module.exports.tests = {};
const coarse_reverse_message ='coarse /reverse does not support geonames. See https://github.com/pelias/pelias/issues/675 for more info';
module.exports.tests.no_warnings_or_errors_conditions = (test, common) => { module.exports.tests.no_warnings_or_errors_conditions = (test, common) => {
test('undefined sources should add neither warnings nor errors', (t) => { test('undefined sources should add neither warnings nor errors', (t) => {
const clean = {}; const clean = {};
@ -27,41 +29,71 @@ module.exports.tests.no_warnings_or_errors_conditions = (test, common) => {
}); });
test('geonames/gn in sources with layers=venue should add neither warnings nor errors', (t) => {
const clean = {
sources: ['geonames'],
layers: ['venue']
};
const messages = sanitizer.sanitize(undefined, clean);
t.deepEquals(clean.sources, ['geonames']);
t.deepEquals(messages, { errors: [], warnings: [] });
t.end();
});
}; };
module.exports.tests.error_conditions = (test, common) => { module.exports.tests.error_conditions = (test, common) => {
test('only geonames in sources should not modify clean.sources and add error message', (t) => { test('only geonames in sources with layers=coarse should not modify clean.sources and add error message', (t) => {
['gn', 'geonames'].forEach((sources) => { ['gn', 'geonames'].forEach((sources) => {
const clean = { const clean = {
sources: [sources] sources: [sources],
layers: ['coarse']
}; };
const messages = sanitizer.sanitize(undefined, clean); const messages = sanitizer.sanitize(undefined, clean);
t.deepEquals(clean.sources, [sources]); t.deepEquals(clean.sources, [sources]);
t.deepEquals(messages.errors, ['/reverse does not support geonames']); t.deepEquals(messages.errors, [ coarse_reverse_message ]);
t.deepEquals(messages.warnings, []); t.deepEquals(messages.warnings, []);
}); });
t.end(); t.end();
});
test('only geonames in sources with layers=locality should not modify clean.sources and add error message', (t) => {
['gn', 'geonames'].forEach((sources) => {
const clean = {
sources: [sources],
layers: ['locality']
};
const messages = sanitizer.sanitize(undefined, clean);
t.deepEquals(clean.sources, [sources]);
t.deepEquals(messages.errors, [ coarse_reverse_message ]);
t.deepEquals(messages.warnings, []);
}); });
t.end();
});
}; };
module.exports.tests.warning_conditions = (test, common) => { module.exports.tests.warning_conditions = (test, common) => {
test('only geonames in sources should not modify clean.sources and add error message', (t) => { test('only geonames in sources and layers=coarse should not modify clean.sources and add error message', (t) => {
['gn', 'geonames'].forEach((sources) => { ['gn', 'geonames'].forEach((sources) => {
const clean = { const clean = {
sources: ['another source', sources, 'yet another source'] sources: ['another source', sources, 'yet another source'],
layers: ['coarse']
}; };
const messages = sanitizer.sanitize(undefined, clean); const messages = sanitizer.sanitize(undefined, clean);
t.deepEquals(clean.sources, ['another source', 'yet another source']); t.deepEquals(clean.sources, ['another source', 'yet another source']);
t.deepEquals(messages.errors, []); t.deepEquals(messages.errors, []);
t.deepEquals(messages.warnings, ['/reverse does not support geonames']); t.deepEquals(messages.warnings, [ coarse_reverse_message ]);
}); });

Loading…
Cancel
Save