From c6a5fdcd4347cacf52db402c6463b3e6c42de8b7 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Thu, 28 Jul 2016 12:37:20 -0700 Subject: [PATCH 01/16] chore(package): update pelias-query to version 8.2.0 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19314d04..79e36404 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "pelias-config": "2.1.0", "pelias-logger": "0.0.8", "pelias-model": "4.1.0", - "pelias-query": "8.1.3", + "pelias-query": "8.2.0", "pelias-text-analyzer": "1.2.0", "stats-lite": "2.0.3", "through2": "2.0.1" From 06b6db1cc625b75b78e91a8bd133d0d17f473415 Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Thu, 28 Jul 2016 19:07:46 -0400 Subject: [PATCH 02/16] feat: set up semantic-release --- .travis.yml | 8 ++++++++ package.json | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e51a8ea7..3f462ba9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,3 +28,11 @@ before_install: - npm i -g npm@^2.0.0 before_script: - npm prune +after_success: + - 'curl -Lo travis_after_all.py https://git.io/travis_after_all' + - python travis_after_all.py + - export $(cat .to_export_back) &> /dev/null + - npm run semantic-release +branches: + except: + - /^v\d+\.\d+\.\d+$/ diff --git a/package.json b/package.json index 19314d04..c273dd8f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "pelias-api", "author": "mapzen", - "version": "2.2.0", "description": "Pelias API", "homepage": "https://github.com/pelias/api", "license": "MIT", @@ -16,11 +15,12 @@ "test": "npm run unit", "travis": "npm test", "unit": "./bin/units", - "validate": "npm ls" + "validate": "npm ls", + "semantic-release": "semantic-release pre && npm publish && semantic-release post" }, "repository": { "type": "git", - "url": "git://github.com/pelias/api.git" + "url": "https://github.com/pelias/api.git" }, "keywords": [ "pelias", @@ -68,7 +68,8 @@ "source-map": "^0.5.6", "tap-dot": "1.0.5", "tape": "^4.5.1", - "uglify-js": "^2.6.2" + "uglify-js": "^2.6.2", + "semantic-release": "^4.3.5" }, "pre-commit": [ "lint", From 4863daa8c85d079dfad3bed921e6a38c7a50eb28 Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Thu, 28 Jul 2016 19:11:05 -0400 Subject: [PATCH 03/16] Version 3.0.0 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index c273dd8f..4bb41dce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "pelias-api", "author": "mapzen", + "version": "3.0.0", "description": "Pelias API", "homepage": "https://github.com/pelias/api", "license": "MIT", From 63d73f99d884d869ce26af34fe15746643a275ac Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Thu, 28 Jul 2016 19:12:25 -0400 Subject: [PATCH 04/16] fix: remove version from package.json This and the previous commit were needed because whenever we last pushed to NPM, we apparently did it from a branch that never got merged into master. --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 4bb41dce..c273dd8f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "pelias-api", "author": "mapzen", - "version": "3.0.0", "description": "Pelias API", "homepage": "https://github.com/pelias/api", "license": "MIT", From 6cde730e49d2f711b783b0c4994080e435ad2aae Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Thu, 28 Jul 2016 19:14:27 -0400 Subject: [PATCH 05/16] fix: URL for Gitter does not appear correctly on NPM --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6ca7b57..a28ceb52 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This is the API server for the Pelias project. It's the service that runs to process user HTTP requests and return results as GeoJSON by querying Elasticsearch. -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/pelias/api?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/pelias/api?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/pelias/api.png?branch=master)](https://travis-ci.org/pelias/api) ## Documentation From 5b8a9a31d2877452060eddcd32ec727cd8df4105 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Fri, 29 Jul 2016 19:44:45 +0200 Subject: [PATCH 06/16] wrap coordinates at poles --- sanitiser/_geo_common.js | 8 ++++ sanitiser/wrap.js | 36 +++++++++++++++ test/unit/run.js | 1 + test/unit/sanitiser/_geo_common.js | 58 ++++++++++++++++++++++++ test/unit/sanitiser/reverse.js | 2 - test/unit/sanitiser/search.js | 2 - test/unit/sanitiser/wrap.js | 71 ++++++++++++++++++++++++++++++ 7 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 sanitiser/wrap.js create mode 100644 test/unit/sanitiser/wrap.js diff --git a/sanitiser/_geo_common.js b/sanitiser/_geo_common.js index 3287bc31..1992a50d 100644 --- a/sanitiser/_geo_common.js +++ b/sanitiser/_geo_common.js @@ -4,6 +4,7 @@ var groups = require('./_groups'), util = require('util'), check = require('check-types'), + wrap = require('./wrap'), _ = require('lodash'); /** @@ -68,6 +69,7 @@ function sanitize_circle( key_prefix, clean, raw, circle_is_required ) { * @param {bool} point_is_required */ function sanitize_point( key_prefix, clean, raw, point_is_required ) { + // calculate full property names from the key_prefix var properties = [ 'lat', 'lon'].map(function(prop) { return key_prefix + '.' + prop; @@ -91,6 +93,11 @@ function sanitize_point( key_prefix, clean, raw, point_is_required ) { properties.forEach(function(prop) { sanitize_coord(prop, clean, raw, true); }); + + // normalize co-ordinates by wrapping around the poles + var normalized = wrap(clean[properties[0]], clean[properties[1]]); + clean[properties[0]] = normalized.lat; + clean[properties[1]] = normalized.lon; } /** @@ -103,6 +110,7 @@ function sanitize_point( key_prefix, clean, raw, point_is_required ) { */ function sanitize_coord( key, clean, raw, latlon_is_required ) { var parsedValue = parseFloat( raw[key] ); + if ( _.isFinite( parsedValue ) ) { clean[key] = parsedValue; } diff --git a/sanitiser/wrap.js b/sanitiser/wrap.js new file mode 100644 index 00000000..f1a482e5 --- /dev/null +++ b/sanitiser/wrap.js @@ -0,0 +1,36 @@ + +/** + normalize co-ordinates that lie outside of the normal ranges. +**/ + +function wrap( lat, lon ){ + + var flip = false; + var point = { lat: lat, lon: lon }; + + // north pole + if( point.lat > 90 ){ + point.lat = 90 - point.lat % 90; + point.lon += 180; + } + + // south pole + else if( point.lat < -90 ){ + point.lat = -90 - point.lat % 90; + point.lon += 180; + } + + // reduce lon + while( point.lon > 180 ){ + point.lon -= 360; + } + + // increase lon + while( point.lon < -180 ){ + point.lon += 360; + } + + return point; +} + +module.exports = wrap; diff --git a/test/unit/run.js b/test/unit/run.js index 62516bc9..2a89b161 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -56,6 +56,7 @@ var tests = [ require('./sanitiser/place'), require('./sanitiser/reverse'), require('./sanitiser/search'), + require('./sanitiser/wrap'), require('./service/mget'), require('./service/search'), ]; diff --git a/test/unit/sanitiser/_geo_common.js b/test/unit/sanitiser/_geo_common.js index f8a27a8b..d8e174d3 100644 --- a/test/unit/sanitiser/_geo_common.js +++ b/test/unit/sanitiser/_geo_common.js @@ -12,6 +12,64 @@ module.exports.tests.interface = function(test, common) { }); }; +module.exports.tests.wrapping = function(test, common) { + test('control - no wrapping required', function (t) { + var clean = {}; + var params = { + 'point.lat': 40.7, + 'point.lon': -73.9 + }; + sanitize.sanitize_point( 'point', clean, params, false ); + t.equal(clean['point.lat'], params['point.lat']); + t.equal(clean['point.lon'], params['point.lon']); + t.end(); + }); + test('positive longitude wrapping', function (t) { + var clean = {}; + var params = { + 'point.lat': 40.7, + 'point.lon': 195.1 + }; + sanitize.sanitize_point( 'point', clean, params, false ); + t.equal(clean['point.lat'], 40.7); + t.equal(clean['point.lon'], -164.9); + t.end(); + }); + test('negative longitude wrapping', function (t) { + var clean = {}; + var params = { + 'point.lat': 40.7, + 'point.lon': -195.1 + }; + sanitize.sanitize_point( 'point', clean, params, false ); + t.equal(clean['point.lat'], 40.7); + t.equal(clean['point.lon'], 164.9); + t.end(); + }); + test('positive latitudinal wrapping', function (t) { + var clean = {}; + var params = { + 'point.lat': 98.1, + 'point.lon': -73.9 + }; + sanitize.sanitize_point( 'point', clean, params, false ); + t.equal(clean['point.lat'], 81.9); + t.equal(clean['point.lon'], 106.1); + t.end(); + }); + test('negative latitudinal wrapping', function (t) { + var clean = {}; + var params = { + 'point.lat': -98.1, + 'point.lon': -73.9 + }; + sanitize.sanitize_point( 'point', clean, params, false ); + t.equal(clean['point.lat'], -81.9); + t.equal(clean['point.lon'], 106.1); + t.end(); + }); +}; + module.exports.tests.coord = function(test, common) { test('valid coord', function (t) { var clean = {}; diff --git a/test/unit/sanitiser/reverse.js b/test/unit/sanitiser/reverse.js index fcce8226..089e1aaf 100644 --- a/test/unit/sanitiser/reverse.js +++ b/test/unit/sanitiser/reverse.js @@ -65,7 +65,6 @@ module.exports.tests.sanitize_lat = function(test, common) { sanitize(req, function(){ var expected_lat = parseFloat( lat ); t.deepEqual(req.errors, [], 'no errors'); - t.equal(req.clean['point.lat'], expected_lat, 'clean set correctly (' + lat + ')'); }); }); t.end(); @@ -93,7 +92,6 @@ module.exports.tests.sanitize_lon = function(test, common) { sanitize(req, function(){ var expected_lon = parseFloat( lon ); t.deepEqual(req.errors, [], 'no errors'); - t.equal(req.clean['point.lon'], expected_lon, 'clean set correctly (' + lon + ')'); }); }); t.end(); diff --git a/test/unit/sanitiser/search.js b/test/unit/sanitiser/search.js index 864195a8..53bdb6af 100644 --- a/test/unit/sanitiser/search.js +++ b/test/unit/sanitiser/search.js @@ -129,7 +129,6 @@ module.exports.tests.sanitize_lat = function(test, common) { sanitize(req, function(){ var expected_lat = parseFloat( lat ); t.equal(req.errors[0], undefined, 'no error'); - t.equal(req.clean['focus.point.lat'], expected_lat, 'clean lat set correctly (' + lat + ')'); }); }); t.end(); @@ -146,7 +145,6 @@ module.exports.tests.sanitize_lon = function(test, common) { sanitize( req, function(){ var expected_lon = parseFloat( lon ); t.equal(req.errors[0], undefined, 'no error'); - t.deepEqual(req.clean['focus.point.lon'], expected_lon, 'clean set correctly (' + lon + ')'); }); }); t.end(); diff --git a/test/unit/sanitiser/wrap.js b/test/unit/sanitiser/wrap.js new file mode 100644 index 00000000..73e2ec0e --- /dev/null +++ b/test/unit/sanitiser/wrap.js @@ -0,0 +1,71 @@ + +var wrap = require('../../../sanitiser/wrap'); + +module.exports.tests = {}; + +module.exports.tests.wrapping = function(test, common) { + test('control - no wrapping required', function (t) { + var norm = wrap(55.555, 22.222); + t.equal(norm.lat, 55.555); + t.equal(norm.lon, 22.222); + t.end(); + }); + test('positive longitude wrapping', function (t) { + var norm = wrap(0, 181); + t.equal(norm.lat, 0); + t.equal(norm.lon, -179); + t.end(); + }); + test('positive longitude wrapping (double)', function (t) { + var norm = wrap(0, 541); + t.equal(norm.lat, 0); + t.equal(norm.lon, -179); + t.end(); + }); + test('negative longitude wrapping', function (t) { + var norm = wrap(0, -181); + t.equal(norm.lat, 0); + t.equal(norm.lon, 179); + t.end(); + }); + test('negative longitude wrapping (double)', function (t) { + var norm = wrap(0, -541); + t.equal(norm.lat, 0); + t.equal(norm.lon, 179); + t.end(); + }); + test('positive latitudinal wrapping', function (t) { + var norm = wrap(91, 0); + t.equal(norm.lat, 89); + t.equal(norm.lon, 180); + t.end(); + }); + test('positive latitudinal wrapping (double)', function (t) { + var norm = wrap(271, 0); + t.equal(norm.lat, 89); + t.equal(norm.lon, 180); + t.end(); + }); + test('negative latitudinal wrapping', function (t) { + var norm = wrap(-91, 0); + t.equal(norm.lat, -89); + t.equal(norm.lon, 180); + t.end(); + }); + test('negative latitudinal wrapping (double)', function (t) { + var norm = wrap(-271, 0); + t.equal(norm.lat, -89); + t.equal(norm.lon, 180); + t.end(); + }); +}; + +module.exports.all = function (tape, common) { + function test(name, testFunction) { + return tape('SANTIZE wrap ' + name, testFunction); + } + + for( var testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +}; From a0de139fd2ceca68b6cc65808351834f4f6a3123 Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Fri, 29 Jul 2016 16:20:50 -0400 Subject: [PATCH 07/16] Add placeholder package version We are using [semantic release](https://github.com/semantic-release/semantic-release) to manage our NPM releases, but it's still important to have some sort of version in the file at all times. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index c273dd8f..e4c6d887 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "pelias-api", + "version": "0.0.0-semantic-release", "author": "mapzen", "description": "Pelias API", "homepage": "https://github.com/pelias/api", From c317d4f3215213f3f782418bf74de8a031f66d49 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Tue, 2 Aug 2016 12:45:58 +0200 Subject: [PATCH 08/16] fix/improve coordinate wrapping function, added more tests --- sanitiser/wrap.js | 38 +++++-- test/unit/sanitiser/_geo_common.js | 41 +++---- test/unit/sanitiser/wrap.js | 172 ++++++++++++++++++++++++----- 3 files changed, 193 insertions(+), 58 deletions(-) diff --git a/sanitiser/wrap.js b/sanitiser/wrap.js index f1a482e5..c89088e7 100644 --- a/sanitiser/wrap.js +++ b/sanitiser/wrap.js @@ -1,23 +1,37 @@ /** normalize co-ordinates that lie outside of the normal ranges. + + longitude wrapping simply requires adding +- 360 to the value until it comes + in to range. + + for the latitude values we need to flip the longitude whenever the latitude + crosses a pole. **/ + function wrap( lat, lon ){ - var flip = false; var point = { lat: lat, lon: lon }; - - // north pole - if( point.lat > 90 ){ - point.lat = 90 - point.lat % 90; - point.lon += 180; - } - - // south pole - else if( point.lat < -90 ){ - point.lat = -90 - point.lat % 90; - point.lon += 180; + var quadrant = Math.floor( Math.abs(lat) / 90) % 4; + var pole = ( lat > 0 ) ? 90 : -90; + var offset = lat % 90; + + switch( quadrant ){ + case 0: + point.lat = offset; + break; + case 1: + point.lat = pole - offset; + point.lon += 180; + break; + case 2: + point.lat = -offset; + point.lon += 180; + break; + case 3: + point.lat = -pole + offset; + break; } // reduce lon diff --git a/test/unit/sanitiser/_geo_common.js b/test/unit/sanitiser/_geo_common.js index d8e174d3..93ec5d11 100644 --- a/test/unit/sanitiser/_geo_common.js +++ b/test/unit/sanitiser/_geo_common.js @@ -12,60 +12,61 @@ module.exports.tests.interface = function(test, common) { }); }; +// @note: for better coverage see unit tests for 'wrap.js'. module.exports.tests.wrapping = function(test, common) { test('control - no wrapping required', function (t) { var clean = {}; var params = { - 'point.lat': 40.7, - 'point.lon': -73.9 + 'point.lat': +1.1, + 'point.lon': -1.1 }; sanitize.sanitize_point( 'point', clean, params, false ); - t.equal(clean['point.lat'], params['point.lat']); - t.equal(clean['point.lon'], params['point.lon']); + t.equal(clean['point.lat'], +1.1, 'not changed'); + t.equal(clean['point.lon'], -1.1, 'not changed'); t.end(); }); test('positive longitude wrapping', function (t) { var clean = {}; var params = { - 'point.lat': 40.7, - 'point.lon': 195.1 + 'point.lat': +1.1, + 'point.lon': +181.1 }; sanitize.sanitize_point( 'point', clean, params, false ); - t.equal(clean['point.lat'], 40.7); - t.equal(clean['point.lon'], -164.9); + t.equal(clean['point.lat'], +1.1, 'not changed'); + t.equal(clean['point.lon'], -178.9, 'equal to (-180 + 1.1)'); t.end(); }); test('negative longitude wrapping', function (t) { var clean = {}; var params = { - 'point.lat': 40.7, - 'point.lon': -195.1 + 'point.lat': -1.1, + 'point.lon': -181.1 }; sanitize.sanitize_point( 'point', clean, params, false ); - t.equal(clean['point.lat'], 40.7); - t.equal(clean['point.lon'], 164.9); + t.equal(clean['point.lat'], -1.1, 'not changed'); + t.equal(clean['point.lon'], +178.9, 'equal to (+180 - 1.1)'); t.end(); }); test('positive latitudinal wrapping', function (t) { var clean = {}; var params = { - 'point.lat': 98.1, - 'point.lon': -73.9 + 'point.lat': 91.1, + 'point.lon': 1.1 }; sanitize.sanitize_point( 'point', clean, params, false ); - t.equal(clean['point.lat'], 81.9); - t.equal(clean['point.lon'], 106.1); + t.equal(clean['point.lat'], +88.9, 'equal to (+90 - 1.1)'); + t.equal(clean['point.lon'], -178.9, 'equal to (-180 - 1.1)'); // polar flip t.end(); }); test('negative latitudinal wrapping', function (t) { var clean = {}; var params = { - 'point.lat': -98.1, - 'point.lon': -73.9 + 'point.lat': -91.1, + 'point.lon': -1.1 }; sanitize.sanitize_point( 'point', clean, params, false ); - t.equal(clean['point.lat'], -81.9); - t.equal(clean['point.lon'], 106.1); + t.equal(clean['point.lat'], -88.9, 'equal to (-90 + 1.1)'); + t.equal(clean['point.lon'], +178.9, 'equal to (+180 - 1.1)'); // polar flip t.end(); }); }; diff --git a/test/unit/sanitiser/wrap.js b/test/unit/sanitiser/wrap.js index 73e2ec0e..ea9a75a5 100644 --- a/test/unit/sanitiser/wrap.js +++ b/test/unit/sanitiser/wrap.js @@ -3,59 +3,179 @@ var wrap = require('../../../sanitiser/wrap'); module.exports.tests = {}; -module.exports.tests.wrapping = function(test, common) { +module.exports.tests.control = function(test, common) { test('control - no wrapping required', function (t) { var norm = wrap(55.555, 22.222); t.equal(norm.lat, 55.555); t.equal(norm.lon, 22.222); t.end(); }); - test('positive longitude wrapping', function (t) { +}; + +module.exports.tests.latitude_positive = function(test, common) { + test('positive latitude wrapping - 1 degree', function (t) { + var norm = wrap(1, 0); + t.equal(norm.lat, 1); + t.equal(norm.lon, 0); + t.end(); + }); + test('positive latitude wrapping - 91 degrees', function (t) { + var norm = wrap(91, 0); + t.equal(norm.lat, 89); + t.equal(norm.lon, 180); + t.end(); + }); + test('positive latitude wrapping - 181 degrees', function (t) { + var norm = wrap(181, 0); + t.equal(norm.lat, -1); + t.equal(norm.lon, 180); + t.end(); + }); + test('positive latitude wrapping - 271 degrees', function (t) { + var norm = wrap(271, 0); + t.equal(norm.lat, -89); + t.equal(norm.lon, 0); + t.end(); + }); + test('positive latitude wrapping - 361 degrees', function (t) { + var norm = wrap(361, 0); + t.equal(norm.lat, 1); + t.equal(norm.lon, 0); + t.end(); + }); + test('positive latitude wrapping - 631 degrees', function (t) { + var norm = wrap(631, 0); + t.equal(norm.lat, -89); + t.equal(norm.lon, 0); + t.end(); + }); + test('positive latitude wrapping - 721 degrees', function (t) { + var norm = wrap(721, 0); + t.equal(norm.lat, 1); + t.equal(norm.lon, 0); + t.end(); + }); +}; + +module.exports.tests.latitude_negative = function(test, common) { + test('negative latitude wrapping - 1 degree', function (t) { + var norm = wrap(-1, 0); + t.equal(norm.lat, -1); + t.equal(norm.lon, 0); + t.end(); + }); + test('negative latitude wrapping - 91 degrees', function (t) { + var norm = wrap(-91, 0); + t.equal(norm.lat, -89); + t.equal(norm.lon, 180); + t.end(); + }); + test('negative latitude wrapping - 181 degrees', function (t) { + var norm = wrap(-181, 0); + t.equal(norm.lat, 1); + t.equal(norm.lon, 180); + t.end(); + }); + test('negative latitude wrapping - 271 degrees', function (t) { + var norm = wrap(-271, 0); + t.equal(norm.lat, 89); + t.equal(norm.lon, 0); + t.end(); + }); + test('negative latitude wrapping - 361 degrees', function (t) { + var norm = wrap(-361, 0); + t.equal(norm.lat, -1); + t.equal(norm.lon, 0); + t.end(); + }); + test('negative latitude wrapping - 631 degrees', function (t) { + var norm = wrap(-631, 0); + t.equal(norm.lat, 89); + t.equal(norm.lon, 0); + t.end(); + }); + test('positive latitude wrapping - 721 degrees', function (t) { + var norm = wrap(721, 0); + t.equal(norm.lat, 1); + t.equal(norm.lon, 0); + t.end(); + }); +}; + +module.exports.tests.longitude_positive = function(test, common) { + test('positive longitude wrapping - 1 degree', function (t) { + var norm = wrap(0, 1); + t.equal(norm.lat, 0); + t.equal(norm.lon, 1); + t.end(); + }); + test('positive longitude wrapping - 181 degrees', function (t) { var norm = wrap(0, 181); t.equal(norm.lat, 0); t.equal(norm.lon, -179); t.end(); }); - test('positive longitude wrapping (double)', function (t) { - var norm = wrap(0, 541); + test('positive longitude wrapping - 271 degrees', function (t) { + var norm = wrap(0, 271); t.equal(norm.lat, 0); - t.equal(norm.lon, -179); + t.equal(norm.lon, -89); t.end(); }); - test('negative longitude wrapping', function (t) { - var norm = wrap(0, -181); + test('positive longitude wrapping - 361 degrees', function (t) { + var norm = wrap(0, 361); t.equal(norm.lat, 0); - t.equal(norm.lon, 179); + t.equal(norm.lon, 1); + t.end(); + }); + test('positive longitude wrapping - 631 degrees', function (t) { + var norm = wrap(0, 631); + t.equal(norm.lat, 0); + t.equal(norm.lon, -89); t.end(); }); - test('negative longitude wrapping (double)', function (t) { - var norm = wrap(0, -541); + test('positive longitude wrapping - 721 degrees', function (t) { + var norm = wrap(0, 721); + t.equal(norm.lat, 0); + t.equal(norm.lon, 1); + t.end(); + }); +}; + +module.exports.tests.longitude_negative = function(test, common) { + test('negative longitude wrapping - 1 degree', function (t) { + var norm = wrap(0, -1); + t.equal(norm.lat, 0); + t.equal(norm.lon, -1); + t.end(); + }); + test('negative longitude wrapping - 181 degrees', function (t) { + var norm = wrap(0, -181); t.equal(norm.lat, 0); t.equal(norm.lon, 179); t.end(); }); - test('positive latitudinal wrapping', function (t) { - var norm = wrap(91, 0); - t.equal(norm.lat, 89); - t.equal(norm.lon, 180); + test('negative longitude wrapping - 271 degrees', function (t) { + var norm = wrap(0, -271); + t.equal(norm.lat, 0); + t.equal(norm.lon, 89); t.end(); }); - test('positive latitudinal wrapping (double)', function (t) { - var norm = wrap(271, 0); - t.equal(norm.lat, 89); - t.equal(norm.lon, 180); + test('negative longitude wrapping - 361 degrees', function (t) { + var norm = wrap(0, -361); + t.equal(norm.lat, 0); + t.equal(norm.lon, -1); t.end(); }); - test('negative latitudinal wrapping', function (t) { - var norm = wrap(-91, 0); - t.equal(norm.lat, -89); - t.equal(norm.lon, 180); + test('negative longitude wrapping - 631 degrees', function (t) { + var norm = wrap(0, -631); + t.equal(norm.lat, 0); + t.equal(norm.lon, 89); t.end(); }); - test('negative latitudinal wrapping (double)', function (t) { - var norm = wrap(-271, 0); - t.equal(norm.lat, -89); - t.equal(norm.lon, 180); + test('negative longitude wrapping - 721 degrees', function (t) { + var norm = wrap(0, -721); + t.equal(norm.lat, 0); + t.equal(norm.lon, -1); t.end(); }); }; From 39e3156019c8969487a549f65b1108b793bd1c56 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Tue, 2 Aug 2016 12:51:56 +0200 Subject: [PATCH 09/16] typo --- test/unit/sanitiser/_geo_common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/sanitiser/_geo_common.js b/test/unit/sanitiser/_geo_common.js index 93ec5d11..a7bff983 100644 --- a/test/unit/sanitiser/_geo_common.js +++ b/test/unit/sanitiser/_geo_common.js @@ -55,7 +55,7 @@ module.exports.tests.wrapping = function(test, common) { }; sanitize.sanitize_point( 'point', clean, params, false ); t.equal(clean['point.lat'], +88.9, 'equal to (+90 - 1.1)'); - t.equal(clean['point.lon'], -178.9, 'equal to (-180 - 1.1)'); // polar flip + t.equal(clean['point.lon'], -178.9, 'equal to (-180 + 1.1)'); // polar flip t.end(); }); test('negative latitudinal wrapping', function (t) { From 791052e259ae96dda56f9cfa2157f2a7a3040cbd Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Wed, 3 Aug 2016 15:06:57 +0200 Subject: [PATCH 10/16] cleaner code: replace while() statements --- sanitiser/wrap.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sanitiser/wrap.js b/sanitiser/wrap.js index c89088e7..bc8a9cd2 100644 --- a/sanitiser/wrap.js +++ b/sanitiser/wrap.js @@ -34,14 +34,8 @@ function wrap( lat, lon ){ break; } - // reduce lon - while( point.lon > 180 ){ - point.lon -= 360; - } - - // increase lon - while( point.lon < -180 ){ - point.lon += 360; + if( point.lon > 180 || point.lon <= -180 ){ + point.lon -= Math.floor(( point.lon + 180 ) / 360) * 360; } return point; From 7f1856159576c020472a1c0adf9eea67169e9d57 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Thu, 4 Aug 2016 13:45:27 +0200 Subject: [PATCH 11/16] remove focus.viewport API --- query/search.js | 29 +-------------- sanitiser/_geo_search.js | 14 +------ test/unit/query/search.js | 36 ------------------ test/unit/sanitiser/search.js | 69 ----------------------------------- 4 files changed, 3 insertions(+), 145 deletions(-) diff --git a/query/search.js b/query/search.js index a6c2fd6a..92a9db00 100644 --- a/query/search.js +++ b/query/search.js @@ -1,8 +1,8 @@ var peliasQuery = require('pelias-query'), defaults = require('./search_defaults'), textParser = require('./text_parser'), - check = require('check-types'), - geolib = require('geolib'); + check = require('check-types'); + var placeTypes = require('../helper/placeTypes'); // region_a is also an admin field. addressit tries to detect @@ -77,19 +77,6 @@ function generateQuery( clean ){ }); } - // focus viewport - if( check.number(clean['focus.viewport.min_lat']) && - check.number(clean['focus.viewport.max_lat']) && - check.number(clean['focus.viewport.min_lon']) && - check.number(clean['focus.viewport.max_lon']) ) { - // calculate the centroid from the viewport box - vs.set({ - 'focus:point:lat': clean['focus.viewport.min_lat'] + ( clean['focus.viewport.max_lat'] - clean['focus.viewport.min_lat'] ) / 2, - 'focus:point:lon': clean['focus.viewport.min_lon'] + ( clean['focus.viewport.max_lon'] - clean['focus.viewport.min_lon'] ) / 2 - //, 'focus:scale': calculateDiagonalDistance(clean) + 'km' - }); - } - // boundary rect if( check.number(clean['boundary.rect.min_lat']) && check.number(clean['boundary.rect.max_lat']) && @@ -134,16 +121,4 @@ function generateQuery( clean ){ return query.render( vs ); } -// return diagonal distance in km, with min=1 -function calculateDiagonalDistance(clean) { - var diagonalDistance = geolib.getDistance( - { latitude: clean['focus.viewport.min_lat'], longitude: clean['focus.viewport.min_lon'] }, - { latitude: clean['focus.viewport.max_lat'], longitude: clean['focus.viewport.max_lon'] }, - 1000 - ) / 1000; - - return Math.max(diagonalDistance, 1); - -} - module.exports = generateQuery; diff --git a/sanitiser/_geo_search.js b/sanitiser/_geo_search.js index 8aef9b7f..ae820fbf 100644 --- a/sanitiser/_geo_search.js +++ b/sanitiser/_geo_search.js @@ -1,9 +1,9 @@ var check = require('check-types'); var geo_common = require ('./_geo_common'); + var LAT_LON_IS_REQUIRED = false; var RECT_IS_REQUIRED = false; var CIRCLE_IS_REQUIRED = false; -var VIEWPORT_IS_REQUIRED = false; // validate inputs, convert types and apply defaults module.exports = function sanitize( raw, clean ){ @@ -11,22 +11,10 @@ module.exports = function sanitize( raw, clean ){ // error & warning messages var messages = { errors: [], warnings: [] }; - // disallow specifying both focus.point and focus.viewport - if ( ( raw['focus.viewport.min_lat'] || - raw['focus.viewport.max_lat'] || - raw['focus.viewport.min_lon'] || - raw['focus.viewport.max_lon'] ) && - ( raw['focus.point.lat'] || - raw['focus.point.lon'] ) ) { - messages.errors.push( 'focus.point and focus.viewport can\'t both be set' ); - return messages; - } - try { geo_common.sanitize_point( 'focus.point', clean, raw, LAT_LON_IS_REQUIRED ); geo_common.sanitize_rect( 'boundary.rect', clean, raw, RECT_IS_REQUIRED ); geo_common.sanitize_circle( 'boundary.circle', clean, raw, CIRCLE_IS_REQUIRED ); - geo_common.sanitize_rect( 'focus.viewport', clean, raw, VIEWPORT_IS_REQUIRED ); } catch (err) { messages.errors.push( err.message ); diff --git a/test/unit/query/search.js b/test/unit/query/search.js index 29c8a06e..4ff414c0 100644 --- a/test/unit/query/search.js +++ b/test/unit/query/search.js @@ -73,42 +73,6 @@ module.exports.tests.query = function(test, common) { t.end(); }); - test('search search + viewport', function(t) { - var query = generate({ - 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 compiled = JSON.parse( JSON.stringify( query ) ); - var expected = require('../fixture/search_linguistic_viewport'); - - t.deepEqual(compiled, 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 query = generate({ - // 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 compiled = JSON.parse( JSON.stringify( query ) ); - // var expected = require('../fixture/search_linguistic_viewport_min_diagonal'); - // - // t.deepEqual(compiled, expected, 'valid search query'); - // t.end(); - // }); - test('search search + focus on null island', function(t) { var query = generate({ text: 'test', querySize: 10, diff --git a/test/unit/sanitiser/search.js b/test/unit/sanitiser/search.js index 53bdb6af..70c4400f 100644 --- a/test/unit/sanitiser/search.js +++ b/test/unit/sanitiser/search.js @@ -206,75 +206,6 @@ module.exports.tests.sanitize_bounding_rect = function(test, common) { }); }; -module.exports.tests.sanitize_viewport = function(test, common) { - test('valid viewport', function(t) { - var req = { - query: { - text: 'test', - 'focus.viewport.min_lat': '37', - 'focus.viewport.max_lat': '38', - 'focus.viewport.min_lon': '-123', - 'focus.viewport.max_lon': '-122' - } - }; - sanitize(req, function() { - t.equal(req.errors[0], undefined, 'no error'); - t.equal(req.clean['focus.viewport.min_lat'], parseFloat(req.query['focus.viewport.min_lat']), 'correct min_lat in clean'); - t.equal(req.clean['focus.viewport.max_lat'], parseFloat(req.query['focus.viewport.max_lat']), 'correct max_lat in clean'); - t.equal(req.clean['focus.viewport.min_lon'], parseFloat(req.query['focus.viewport.min_lon']), 'correct min_lon in clean'); - t.equal(req.clean['focus.viewport.max_lon'], parseFloat(req.query['focus.viewport.max_lon']), 'correct max_lon in clean'); - t.end(); - }); - }); - - test('error returned if focus.point and focus.viewpoint specified', function(t) { - var req = { - query: { - text: 'test', - 'focus.point.lat': '10', - 'focus.point.lon': '15', - 'focus.viewport.min_lat': '37', - 'focus.viewport.max_lat': '38', - 'focus.viewport.min_lon': '-123', - 'focus.viewport.max_lon': '-122' - } - }; - - sanitize(req, function() { - t.equal(req.errors[0], 'focus.point and focus.viewport can\'t both be set', 'no error'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.min_lat'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.max_lat'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.min_lon'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.max_lon'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.point.lat'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.point.lon'), 'clean should be empty'); - t.end(); - }); - }); - - test('error returned if focus.point and focus.viewpoint partially specified', function(t) { - var req = { - query: { - text: 'test', - 'focus.point.lat': '10', - 'focus.viewport.min_lat': '37', - 'focus.viewport.max_lon': '-122' - } - }; - - sanitize(req, function() { - t.equal(req.errors[0], 'focus.point and focus.viewport can\'t both be set', 'no error'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.min_lat'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.max_lat'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.min_lon'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.viewport.max_lon'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.point.lat'), 'clean should be empty'); - t.notOk(req.clean.hasOwnProperty('focus.point.lon'), 'clean should be empty'); - t.end(); - }); - }); -}; - module.exports.tests.sanitize_size = function(test, common) { test('invalid size value', function(t) { var req = { query: { size: 'a', text: 'test', lat: 0, lon: 0 } }; From d43a16f780bd2a0797834e6d61176235b6f89a34 Mon Sep 17 00:00:00 2001 From: avulfson17 Date: Tue, 26 Jul 2016 16:00:55 -0400 Subject: [PATCH 12/16] Add borough as a possible layer for geonames --- helper/type_mapping.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helper/type_mapping.js b/helper/type_mapping.js index 59dbb590..fde1fab1 100644 --- a/helper/type_mapping.js +++ b/helper/type_mapping.js @@ -48,7 +48,7 @@ var LAYERS_BY_SOURCE = { openstreetmap: [ 'address', 'venue' ], openaddresses: [ 'address' ], geonames: [ 'country','macroregion', 'region', 'county','localadmin', - 'locality', 'neighbourhood', 'venue' ], + 'locality','borough', 'neighbourhood', 'venue' ], whosonfirst: [ 'continent', 'country', 'dependency', 'macroregion', 'region', 'locality', 'localadmin', 'macrocounty', 'county', 'macrohood', 'borough', 'neighbourhood', 'microhood', 'disputed'] From 61ac4a99c1a61ccb37ffc1affa0f2688a6436c6a Mon Sep 17 00:00:00 2001 From: avulfson17 Date: Wed, 3 Aug 2016 13:14:53 -0400 Subject: [PATCH 13/16] add test for borough in geonames --- test/unit/sanitiser/_sources_and_layers.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/unit/sanitiser/_sources_and_layers.js b/test/unit/sanitiser/_sources_and_layers.js index dfb997fa..b943770c 100644 --- a/test/unit/sanitiser/_sources_and_layers.js +++ b/test/unit/sanitiser/_sources_and_layers.js @@ -52,6 +52,17 @@ module.exports.tests.no_errors = function(test, common) { }); test('valid combination', function(t) { + var raw = {}; + var clean = { sources: ['geonames'], layers: ['borough'] }; + + var messages = sanitize(raw, clean); + + t.equal(messages.errors.length, 0, 'should return no errors'); + t.equal(messages.warnings.length, 0, 'should return no warnings'); + t.end(); + }); + + test('valid combination', function(t) { var raw = {}; var clean = { sources: ['geonames'], layers: ['macroregion'] }; From af33a333ffa1282e584e42dfdaaa558174702a52 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Thu, 4 Aug 2016 08:42:07 -0700 Subject: [PATCH 14/16] chore(package): update pelias-query to version 8.3.0 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed3d499f..1732b338 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pelias-config": "2.1.0", "pelias-logger": "0.0.8", "pelias-model": "4.1.0", - "pelias-query": "8.2.0", + "pelias-query": "8.3.0", "pelias-text-analyzer": "1.2.0", "stats-lite": "2.0.3", "through2": "2.0.1" From 1716c9e34c55cbfb7ca4be00dfc2ac54fa32080e Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Thu, 4 Aug 2016 08:53:28 -0700 Subject: [PATCH 15/16] chore(package): update pelias-text-analyzer to version 1.3.0 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1732b338..4fa1488e 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "pelias-logger": "0.0.8", "pelias-model": "4.1.0", "pelias-query": "8.3.0", - "pelias-text-analyzer": "1.2.0", + "pelias-text-analyzer": "1.3.0", "stats-lite": "2.0.3", "through2": "2.0.1" }, From 76e54bf7d3968dc3d906e06e5c8459766f86f30e Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Thu, 4 Aug 2016 12:00:58 -0400 Subject: [PATCH 16/16] Update test expectations to be better! addressit can now detect that "new york" the state should be abbreviated "NY". --- test/unit/fixture/search_partial_address.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/fixture/search_partial_address.js b/test/unit/fixture/search_partial_address.js index 10a2bb74..b0c82a3f 100644 --- a/test/unit/fixture/search_partial_address.js +++ b/test/unit/fixture/search_partial_address.js @@ -78,7 +78,7 @@ module.exports = { 'parent.region_a': { 'analyzer': 'peliasAdmin', 'boost': 1, - 'query': 'new york' + 'query': 'NY' } } }, {