mirror of https://github.com/pelias/api.git
Diana Shkolnikov
9 years ago
51 changed files with 541 additions and 379 deletions
@ -0,0 +1,87 @@
|
||||
var extend = require('extend'), |
||||
_ = require('lodash'); |
||||
|
||||
var TYPE_TO_SOURCE = { |
||||
'geoname': 'gn', |
||||
'osmnode': 'osm', |
||||
'osmway': 'osm', |
||||
'admin0': 'qs', |
||||
'admin1': 'qs', |
||||
'admin2': 'qs', |
||||
'neighborhood': 'qs', |
||||
'locality': 'qs', |
||||
'local_admin': 'qs', |
||||
'osmaddress': 'osm', |
||||
'openaddresses': 'oa' |
||||
}; |
||||
|
||||
/* |
||||
* This doesn't include alias layers such as coarse |
||||
*/ |
||||
var TYPE_TO_LAYER = { |
||||
'geoname': 'venue', |
||||
'osmnode': 'venue', |
||||
'osmway': 'venue', |
||||
'admin0': 'country', |
||||
'admin1': 'region', |
||||
'admin2': 'county', |
||||
'neighborhood': 'neighbourhood', |
||||
'locality': 'locality', |
||||
'local_admin': 'localadmin', |
||||
'osmaddress': 'address', |
||||
'openaddresses': 'address' |
||||
}; |
||||
|
||||
var SOURCE_TO_TYPE = { |
||||
'gn' : ['geoname'], |
||||
'geonames' : ['geoname'], |
||||
'oa' : ['openaddresses'], |
||||
'openaddresses' : ['openaddresses'], |
||||
'qs' : ['admin0', 'admin1', 'admin2', 'neighborhood', 'locality', 'local_admin'], |
||||
'quattroshapes' : ['admin0', 'admin1', 'admin2', 'neighborhood', 'locality', 'local_admin'], |
||||
'osm' : ['osmaddress', 'osmnode', 'osmway'], |
||||
'openstreetmap' : ['osmaddress', 'osmnode', 'osmway'] |
||||
}; |
||||
|
||||
/** |
||||
* This does not included alias layers, those are built separately |
||||
*/ |
||||
var LAYER_TO_TYPE = { |
||||
'venue': ['geoname','osmnode','osmway'], |
||||
'address': ['osmaddress','openaddresses', 'geoname'], |
||||
'country': ['admin0', 'geoname'], |
||||
'region': ['admin1', 'geoname'], |
||||
'county': ['admin2', 'geoname'], |
||||
'locality': ['locality', 'geoname'], |
||||
'localadmin': ['local_admin'], |
||||
'neighbourhood': ['neighborhood', 'geoname'] |
||||
}; |
||||
|
||||
var LAYER_ALIASES = { |
||||
'coarse': ['admin0','admin1','admin2','neighborhood','locality','local_admin'] |
||||
}; |
||||
|
||||
var LAYER_WITH_ALIASES_TO_TYPE = extend({}, LAYER_ALIASES, LAYER_TO_TYPE); |
||||
|
||||
/* |
||||
* derive the list of types, sources, and layers from above mappings |
||||
*/ |
||||
var TYPES = Object.keys(TYPE_TO_SOURCE); |
||||
var SOURCES = Object.keys(SOURCE_TO_TYPE); |
||||
var LAYERS = Object.keys(LAYER_TO_TYPE); |
||||
|
||||
var sourceAndLayerToType = function sourceAndLayerToType(source, layer) { |
||||
return _.intersection(SOURCE_TO_TYPE[source], LAYER_WITH_ALIASES_TO_TYPE[layer]); |
||||
}; |
||||
|
||||
module.exports = { |
||||
types: TYPES, |
||||
sources: SOURCES, |
||||
layers: LAYERS, |
||||
type_to_source: TYPE_TO_SOURCE, |
||||
type_to_layer: TYPE_TO_LAYER, |
||||
source_to_type: SOURCE_TO_TYPE, |
||||
layer_to_type: LAYER_TO_TYPE, |
||||
layer_with_aliases_to_type: LAYER_WITH_ALIASES_TO_TYPE, |
||||
source_and_layer_to_type: sourceAndLayerToType |
||||
}; |
@ -1,15 +0,0 @@
|
||||
/* |
||||
* Mapping from data layers to type values |
||||
*/ |
||||
|
||||
module.exports = { |
||||
'venue': ['geoname','osmnode','osmway'], |
||||
'address': ['osmaddress','openaddresses'], |
||||
'country': ['admin0'], |
||||
'region': ['admin1'], |
||||
'county': ['admin2'], |
||||
'locality': ['locality'], |
||||
'localadmin': ['local_admin'], |
||||
'neighbourhood': ['neighborhood'], |
||||
'coarse': ['admin0','admin1','admin2','neighborhood','locality','local_admin'], |
||||
}; |
@ -1,14 +0,0 @@
|
||||
/* |
||||
* Mapping from data sources to type values |
||||
*/ |
||||
|
||||
module.exports = { |
||||
'gn' : ['geoname'], |
||||
'geonames' : ['geoname'], |
||||
'oa' : ['openaddresses'], |
||||
'openaddresses' : ['openaddresses'], |
||||
'qs' : ['admin0', 'admin1', 'admin2', 'neighborhood', 'locality', 'local_admin'], |
||||
'quattroshapes' : ['admin0', 'admin1', 'admin2', 'neighborhood', 'locality', 'local_admin'], |
||||
'osm' : ['osmaddress', 'osmnode', 'osmway'], |
||||
'openstreetmap' : ['osmaddress', 'osmnode', 'osmway'] |
||||
}; |
@ -1,16 +0,0 @@
|
||||
|
||||
// querable types
|
||||
|
||||
module.exports = [ |
||||
'geoname', |
||||
'osmnode', |
||||
'osmway', |
||||
'admin0', |
||||
'admin1', |
||||
'admin2', |
||||
'neighborhood', |
||||
'locality', |
||||
'local_admin', |
||||
'osmaddress', |
||||
'openaddresses' |
||||
]; |
@ -0,0 +1,23 @@
|
||||
|
||||
var _ = require('lodash'), |
||||
check = require('check-types'); |
||||
|
||||
// validate inputs
|
||||
function sanitize( raw, clean ){ |
||||
// error & warning messages
|
||||
var messages = { errors: [], warnings: [] }; |
||||
|
||||
Object.keys(raw).forEach(function(key) { |
||||
if (_.isArray(raw[key])) { |
||||
messages.errors.push('\'' + key + '\' parameter can only have one value'); |
||||
} else if (_.isObject(raw[key])) { |
||||
messages.errors.push('\'' + key + '\' parameter must be a scalar'); |
||||
} |
||||
|
||||
}); |
||||
|
||||
return messages; |
||||
} |
||||
|
||||
// export function
|
||||
module.exports = sanitize; |
@ -0,0 +1,30 @@
|
||||
|
||||
#> set size |
||||
path: '/v1/reverse?point.lat=1&point.lon=1¶m=value1¶m=value2' |
||||
|
||||
#? 200 ok |
||||
response.statusCode.should.be.equal 200 |
||||
response.should.have.header 'charset', 'utf8' |
||||
response.should.have.header 'content-type', 'application/json; charset=utf-8' |
||||
|
||||
#? valid geocoding block |
||||
should.exist json.geocoding |
||||
should.exist json.geocoding.version |
||||
should.exist json.geocoding.attribution |
||||
should.exist json.geocoding.query |
||||
should.exist json.geocoding.engine |
||||
should.exist json.geocoding.engine.name |
||||
should.exist json.geocoding.engine.author |
||||
should.exist json.geocoding.engine.version |
||||
should.exist json.geocoding.timestamp |
||||
|
||||
#? valid geojson |
||||
json.type.should.be.equal 'FeatureCollection' |
||||
json.features.should.be.instanceof Array |
||||
|
||||
#? expected warnings |
||||
should.not.exist json.geocoding.warnings |
||||
|
||||
#? expected errors |
||||
should.exist json.geocoding.errors |
||||
json.geocoding.errors.should.eql [ '\'param\' parameter can only have one value' ] |
@ -0,0 +1,30 @@
|
||||
|
||||
#> set size |
||||
path: '/v1/reverse?point.lat=1&point.lon=1¶meter[idx]=value' |
||||
|
||||
#? 200 ok |
||||
response.statusCode.should.be.equal 200 |
||||
response.should.have.header 'charset', 'utf8' |
||||
response.should.have.header 'content-type', 'application/json; charset=utf-8' |
||||
|
||||
#? valid geocoding block |
||||
should.exist json.geocoding |
||||
should.exist json.geocoding.version |
||||
should.exist json.geocoding.attribution |
||||
should.exist json.geocoding.query |
||||
should.exist json.geocoding.engine |
||||
should.exist json.geocoding.engine.name |
||||
should.exist json.geocoding.engine.author |
||||
should.exist json.geocoding.engine.version |
||||
should.exist json.geocoding.timestamp |
||||
|
||||
#? valid geojson |
||||
json.type.should.be.equal 'FeatureCollection' |
||||
json.features.should.be.instanceof Array |
||||
|
||||
#? expected warnings |
||||
should.not.exist json.geocoding.warnings |
||||
|
||||
#? expected errors |
||||
should.exist json.geocoding.errors |
||||
json.geocoding.errors.should.eql [ '\'parameter\' parameter must be a scalar' ] |
@ -0,0 +1,52 @@
|
||||
var check = require('check-types'); |
||||
var type_mapping = require('../../../helper/type_mapping'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.interfaces = function(test, common) { |
||||
test('types list', function(t) { |
||||
t.ok(check.array(type_mapping.types), 'is array'); |
||||
t.ok(check.hasLength(type_mapping.types, 11), 'has correct number of elements'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('type to source mapping', function(t) { |
||||
t.ok(check.object(type_mapping.type_to_source), 'is object'); |
||||
t.ok(check.hasLength(Object.keys(type_mapping.type_to_source), 11), 'has correct number of elements'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('type to layer mapping', function(t) { |
||||
t.ok(check.object(type_mapping.type_to_layer), 'is object'); |
||||
t.ok(check.hasLength(Object.keys(type_mapping.type_to_layer), 11), 'has correct number of elements'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('source to type mapping', function(t) { |
||||
t.ok(check.object(type_mapping.source_to_type), 'is object'); |
||||
t.ok(check.hasLength(Object.keys(type_mapping.source_to_type), 8), 'has correct number of elements'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('layer to type mapping', function(t) { |
||||
t.ok(check.object(type_mapping.layer_to_type), 'is object'); |
||||
t.equal(Object.keys(type_mapping.layer_to_type).length, 8, 'has correct number of elements'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('layer to type mapping (with aliases)', function(t) { |
||||
t.ok(check.object(type_mapping.layer_with_aliases_to_type), 'is object'); |
||||
t.ok(check.hasLength(Object.keys(type_mapping.layer_with_aliases_to_type), 9), 'has correct number of elements'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('type_mapping: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -1,23 +0,0 @@
|
||||
|
||||
var types = require('../../../query/types'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.interface = function(test, common) { |
||||
test('valid interface', function(t) { |
||||
t.true(Array.isArray(types), 'valid array'); |
||||
t.equal(types.length, 11, 'valid array'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
|
||||
function test(name, testFunction) { |
||||
return tape('types ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,60 @@
|
||||
var sanitize = require('../../../sanitiser/_single_scalar_parameters'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.single_scalar_parameters = function(test, common) { |
||||
test('all duplicate parameters should have error messages returned', function(t) { |
||||
var raw = { |
||||
arrayParameter1: ['value1', 'value2'], |
||||
scalarParameter: 'value', |
||||
arrayParameter2: ['value3'] |
||||
}; |
||||
var clean = {}; |
||||
var errorsAndWarnings = sanitize(raw, clean); |
||||
t.deepEquals(errorsAndWarnings, { |
||||
errors: [ |
||||
'\'arrayParameter1\' parameter can only have one value', |
||||
'\'arrayParameter2\' parameter can only have one value', |
||||
], |
||||
warnings: [] |
||||
}); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('object parameters should have error messages returned', function(t) { |
||||
var raw = { |
||||
objectParameter1: { key1: 'value1', key2: 'value2'}, |
||||
scalarParameter: 'value', |
||||
objectParameter2: { } |
||||
}; |
||||
var clean = {}; |
||||
var errorsAndWarnings = sanitize(raw, clean); |
||||
t.deepEquals(errorsAndWarnings, { |
||||
errors: [ |
||||
'\'objectParameter1\' parameter must be a scalar', |
||||
'\'objectParameter2\' parameter must be a scalar' |
||||
], |
||||
warnings: [] |
||||
}); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('request with all scalar parameters should return empty errors', function(t) { |
||||
var raw = { scalarParameter1: 'value1', scalarParameter2: 2, scalarParameter3: true }; |
||||
var clean = {}; |
||||
var errorsAndWarnings = sanitize(raw, clean); |
||||
t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }); |
||||
t.end(); |
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('SANTIZE _single_scalar_parameters ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -1,127 +0,0 @@
|
||||
var sanitize = require( '../../../sanitiser/_source' ); |
||||
|
||||
var success_response = { error: false }; |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.no_sources = function(test, common) { |
||||
test('source is not set', function(t) { |
||||
var req = { |
||||
query: { }, |
||||
clean: { } |
||||
}; |
||||
|
||||
var response = sanitize(req.query, req.clean); |
||||
|
||||
t.deepEqual(req.clean.types, {}, 'clean.types should be empty object'); |
||||
t.deepEqual(response.errors, [], 'no error returned'); |
||||
t.deepEqual(response.warnings, [], 'no warnings returned'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('source is empty string', function(t) { |
||||
var req = { |
||||
query: { |
||||
source: '' |
||||
}, |
||||
clean: { } |
||||
}; |
||||
|
||||
var response = sanitize(req.query, req.clean); |
||||
|
||||
t.deepEqual(req.clean.types, {}, 'clean.types should be empty object'); |
||||
t.deepEqual(response.errors, [], 'no error returned'); |
||||
t.deepEqual(response.warnings, [], 'no warnings returned'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.tests.valid_sources = function(test, common) { |
||||
test('geonames source', function(t) { |
||||
var req = { |
||||
query: { |
||||
source: 'geonames' |
||||
}, |
||||
clean: { } |
||||
}; |
||||
|
||||
var response = sanitize(req.query, req.clean); |
||||
|
||||
t.deepEqual(req.clean.types, { from_source: ['geoname'] }, 'clean.types should contain from_source entry with geonames'); |
||||
t.deepEqual(response.errors, [], 'no error returned'); |
||||
t.deepEqual(response.warnings, [], 'no warnings returned'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('openstreetmap source', function(t) { |
||||
var req = { |
||||
query: { |
||||
source: 'openstreetmap' |
||||
}, |
||||
clean: { } |
||||
}; |
||||
var expected_types = { |
||||
from_source: ['osmaddress', 'osmnode', 'osmway'] |
||||
}; |
||||
|
||||
var response = sanitize(req.query, req.clean); |
||||
|
||||
t.deepEqual(req.clean.types, expected_types, 'clean.types should contain from_source entry with multiple entries for openstreetmap'); |
||||
t.deepEqual(response.errors, [], 'no error returned'); |
||||
t.deepEqual(response.warnings, [], 'no warnings returned'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('multiple sources', function(t) { |
||||
var req = { |
||||
query: { |
||||
source: 'openstreetmap,openaddresses' |
||||
}, |
||||
clean: { } |
||||
}; |
||||
var expected_types = { |
||||
from_source: ['osmaddress', 'osmnode', 'osmway', 'openaddresses'] |
||||
}; |
||||
|
||||
var response = sanitize(req.query, req.clean); |
||||
|
||||
t.deepEqual(req.clean.types, expected_types, |
||||
'clean.types should contain from_source entry with multiple entries for openstreetmap and openadresses'); |
||||
t.deepEqual(response.errors, [], 'no error returned'); |
||||
t.deepEqual(response.warnings, [], 'no warnings returned'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.tests.invalid_sources = function(test, common) { |
||||
test('geonames source', function(t) { |
||||
var req = { |
||||
query: { |
||||
source: 'notasource' |
||||
}, |
||||
clean: { } |
||||
}; |
||||
var expected_response = { |
||||
errors: [ |
||||
'\'notasource\' is an invalid source parameter. Valid options: geonames,openaddresses,quattroshapes,openstreetmap' |
||||
], |
||||
warnings: [] |
||||
}; |
||||
|
||||
var response = sanitize(req.query, req.clean); |
||||
|
||||
t.deepEqual(response, expected_response, 'error with message returned'); |
||||
t.deepEqual(req.clean.types, { }, 'clean.types should remain empty'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('SANTIZE _source ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
Loading…
Reference in new issue