From f3acf3b30891fb38ed926b4fbd3ca5a7e1e2e5c8 Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Thu, 17 Sep 2015 13:35:38 -0400 Subject: [PATCH] Check for numeric value of lat/lon to avoid null island bug Using the check-types module, check that lat/lon values are numbers, instead of checking their truthyness, to ensure that queries for null island work correctly. --- query/autocomplete.js | 5 +- query/reverse.js | 5 +- query/search.js | 5 +- ...tocomplete_linguistic_focus_null_island.js | 63 +++++++++++++++++++ test/unit/fixture/reverse_null_island.js | 45 +++++++++++++ .../search_linguistic_focus_null_island.js | 63 +++++++++++++++++++ test/unit/query/autocomplete.js | 14 +++++ test/unit/query/reverse.js | 12 ++++ test/unit/query/search.js | 15 +++++ 9 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 test/unit/fixture/autocomplete_linguistic_focus_null_island.js create mode 100644 test/unit/fixture/reverse_null_island.js create mode 100644 test/unit/fixture/search_linguistic_focus_null_island.js diff --git a/query/autocomplete.js b/query/autocomplete.js index d0b82d41..5c956785 100644 --- a/query/autocomplete.js +++ b/query/autocomplete.js @@ -1,6 +1,7 @@ var peliasQuery = require('pelias-query'), - defaults = require('./defaults'); + defaults = require('./defaults'), + check = require('check-types'); //------------------------------ // autocomplete query @@ -31,7 +32,7 @@ function generateQuery( clean ){ vs.var( 'size', 10 ); // focus point - if( clean['focus.point.lat'] && clean['focus.point.lon'] ){ + 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'] diff --git a/query/reverse.js b/query/reverse.js index 029cb4e9..2ee283e3 100644 --- a/query/reverse.js +++ b/query/reverse.js @@ -1,5 +1,6 @@ var peliasQuery = require('pelias-query'), - defaults = require('./defaults'); + defaults = require('./defaults'), + check = require('check-types'); //------------------------------ // reverse geocode query @@ -38,7 +39,7 @@ function generateQuery( clean ){ } // focus point centroid - if( clean['point.lat'] && clean['point.lon'] ){ + if( check.number(clean['point.lat']) && check.number(clean['point.lon']) ){ vs.set({ // focus point to score by distance 'focus:point:lat': clean['point.lat'], diff --git a/query/search.js b/query/search.js index 9dc7702b..9dcf0273 100644 --- a/query/search.js +++ b/query/search.js @@ -1,6 +1,7 @@ var peliasQuery = require('pelias-query'), defaults = require('./defaults'), - textParser = require('./text_parser'); + textParser = require('./text_parser'), + check = require('check-types'); //------------------------------ // general-purpose search query @@ -58,7 +59,7 @@ function generateQuery( clean ){ } // focus point - if( clean['focus.point.lat'] && clean['focus.point.lon'] ){ + 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'] diff --git a/test/unit/fixture/autocomplete_linguistic_focus_null_island.js b/test/unit/fixture/autocomplete_linguistic_focus_null_island.js new file mode 100644 index 00000000..ded463bf --- /dev/null +++ b/test/unit/fixture/autocomplete_linguistic_focus_null_island.js @@ -0,0 +1,63 @@ + +module.exports = { + 'query': { + 'filtered': { + 'query': { + 'bool': { + 'must': [{ + 'match': { + 'name.default': { + 'query': 'test', + 'boost': 1, + 'analyzer': 'peliasOneEdgeGram' + } + } + }], + 'should': [{ + 'match': { + 'phrase.default': { + 'query': 'test', + 'analyzer': 'peliasPhrase', + 'type': 'phrase', + 'boost': 1, + 'slop': 2 + } + } + }, { + 'function_score': { + 'query': { + 'match': { + 'phrase.default': { + 'analyzer': 'peliasPhrase', + 'type': 'phrase', + 'boost': 1, + 'slop': 2, + 'query': 'test' + } + } + }, + 'functions': [{ + 'linear': { + 'center_point': { + 'origin': { + 'lat': 0, + 'lon': 0 + }, + 'offset': '1km', + 'scale': '50km', + 'decay': 0.5 + } + } + }], + 'score_mode': 'avg', + 'boost_mode': 'replace' + } + }] + } + } + } + }, + 'sort': [ '_score' ], + 'size': 10, + 'track_scores': true +}; diff --git a/test/unit/fixture/reverse_null_island.js b/test/unit/fixture/reverse_null_island.js new file mode 100644 index 00000000..f29ab293 --- /dev/null +++ b/test/unit/fixture/reverse_null_island.js @@ -0,0 +1,45 @@ + +module.exports = { + 'query': { + 'filtered': { + 'query': { + 'bool': { + 'must': [] + } + }, + 'filter': { + 'bool': { + 'must': [ + { + 'geo_distance': { + 'distance': '500km', + 'distance_type': 'plane', + 'optimize_bbox': 'indexed', + '_cache': true, + 'center_point': { + 'lat': 0, + 'lon': 0 + } + } + } + ] + } + } + } + }, + 'sort': [ + '_score', + { + '_geo_distance': { + 'center_point': { + 'lat': 0, + 'lon': 0 + }, + 'order': 'asc', + 'distance_type': 'plane' + } + } + ], + 'size': 1, + 'track_scores': true +}; diff --git a/test/unit/fixture/search_linguistic_focus_null_island.js b/test/unit/fixture/search_linguistic_focus_null_island.js new file mode 100644 index 00000000..506dcea9 --- /dev/null +++ b/test/unit/fixture/search_linguistic_focus_null_island.js @@ -0,0 +1,63 @@ + +module.exports = { + 'query': { + 'filtered': { + 'query': { + 'bool': { + 'must': [{ + 'match': { + 'name.default': { + 'query': 'test', + 'boost': 1, + 'analyzer': 'peliasOneEdgeGram' + } + } + }], + 'should': [{ + 'match': { + 'phrase.default': { + 'query': 'test', + 'analyzer': 'peliasPhrase', + 'type': 'phrase', + 'boost': 1, + 'slop': 2 + } + } + }, { + 'function_score': { + 'query': { + 'match': { + 'phrase.default': { + 'analyzer': 'peliasPhrase', + 'type': 'phrase', + 'boost': 1, + 'slop': 2, + 'query': 'test' + } + } + }, + 'functions': [{ + 'linear': { + 'center_point': { + 'origin': { + 'lat': 0, + 'lon': 0 + }, + 'offset': '1km', + 'scale': '50km', + 'decay': 0.5 + } + } + }], + 'score_mode': 'avg', + 'boost_mode': 'replace' + } + }] + } + } + } + }, + 'sort': [ '_sort' ], + 'size': 10, + 'track_scores': true +}; diff --git a/test/unit/query/autocomplete.js b/test/unit/query/autocomplete.js index 3b137fb2..ecdf9553 100644 --- a/test/unit/query/autocomplete.js +++ b/test/unit/query/autocomplete.js @@ -37,6 +37,20 @@ module.exports.tests.query = function(test, common) { t.deepEqual(compiled, expected, 'valid autocomplete query'); t.end(); }); + + test('autocomplete + focus on null island', function(t) { + var query = generate({ + text: 'test', + 'focus.point.lat': 0, + 'focus.point.lon': 0 + }); + + var compiled = JSON.parse( JSON.stringify( query ) ); + var expected = require('../fixture/autocomplete_linguistic_focus_null_island'); + + t.deepEqual(compiled, expected, 'valid autocomplete query'); + t.end(); + }); }; module.exports.all = function (tape, common) { diff --git a/test/unit/query/reverse.js b/test/unit/query/reverse.js index 86a57aa9..cb5e7513 100644 --- a/test/unit/query/reverse.js +++ b/test/unit/query/reverse.js @@ -22,6 +22,18 @@ module.exports.tests.query = function(test, common) { t.end(); }); + test('valid query', function(t) { + var query = generate({ + 'point.lat': 0, 'point.lon': 0 + }); + + var compiled = JSON.parse( JSON.stringify( query ) ); + var expected = require('../fixture/reverse_null_island'); + + t.deepEqual(compiled, expected, 'valid reverse query'); + t.end(); + }); + test('valid query with radius', function(t) { var query = generate({ 'point.lat': 29.49136, 'point.lon': -82.50622, 'boundary.circle.radius': 123 diff --git a/test/unit/query/search.js b/test/unit/query/search.js index 3baa14f8..7da298dd 100644 --- a/test/unit/query/search.js +++ b/test/unit/query/search.js @@ -83,6 +83,21 @@ module.exports.tests.query = function(test, common) { t.end(); }); + test('search search + focus on null island', function(t) { + var query = generate({ + text: 'test', size: 10, + 'focus.point.lat': 0, 'focus.point.lon': 0, + layers: ['test'] + }); + + var compiled = JSON.parse( JSON.stringify( query ) ); + var expected = require('../fixture/search_linguistic_focus_null_island'); + expected.sort = sort; + + t.deepEqual(compiled, expected, 'valid search query'); + t.end(); + }); + test('valid query with a full valid address', function(t) { var address = '123 main st new york ny 10010 US'; var query = generate({ text: address,