mirror of https://github.com/pelias/api.git
Julian Simioni
6 years ago
committed by
GitHub
35 changed files with 863 additions and 422 deletions
@ -0,0 +1,16 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
const Debug = require('../../helper/debug'); |
||||||
|
const debugLog = new Debug('controller:predicates:is_request_sources_includes_whosonfirst'); |
||||||
|
const stackTraceLine = require('../../helper/stackTraceLine'); |
||||||
|
|
||||||
|
// returns true IFF 'whosonfirst' is included in the requested sources
|
||||||
|
module.exports = (req, res) => { |
||||||
|
const is_request_sources_includes_whosonfirst = _.get(req, 'clean.sources', []).includes( |
||||||
|
'whosonfirst' |
||||||
|
); |
||||||
|
debugLog.push(req, () => ({ |
||||||
|
reply: is_request_sources_includes_whosonfirst, |
||||||
|
stack_trace: stackTraceLine() |
||||||
|
})); |
||||||
|
return is_request_sources_includes_whosonfirst; |
||||||
|
}; |
@ -0,0 +1,16 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
const Debug = require('../../helper/debug'); |
||||||
|
const debugLog = new Debug('controller:predicates:is_request_sources_undefined'); |
||||||
|
const stackTraceLine = require('../../helper/stackTraceLine'); |
||||||
|
|
||||||
|
// returns true IFF there are no requested sources
|
||||||
|
module.exports = (req, res) => { |
||||||
|
const is_request_sources_undefined = _.isEmpty( |
||||||
|
_.get(req, 'clean.sources') |
||||||
|
); |
||||||
|
debugLog.push(req, () => ({ |
||||||
|
reply: is_request_sources_undefined, |
||||||
|
stack_trace: stackTraceLine() |
||||||
|
})); |
||||||
|
return is_request_sources_undefined; |
||||||
|
}; |
@ -0,0 +1,146 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
const elasticsearch = require('elasticsearch'); |
||||||
|
|
||||||
|
var TypeMapping = function(){ |
||||||
|
|
||||||
|
// A list of all sources
|
||||||
|
this.sources = []; |
||||||
|
|
||||||
|
// A list of alternate names for sources, mostly used to save typing
|
||||||
|
this.source_aliases = {}; |
||||||
|
|
||||||
|
// A list of all layers
|
||||||
|
this.layers = []; |
||||||
|
|
||||||
|
/* |
||||||
|
* A list of all layers in each source. This is used for convenience elswhere |
||||||
|
* and to determine when a combination of source and layer parameters is |
||||||
|
* not going to match any records and will return no results. |
||||||
|
*/ |
||||||
|
this.layers_by_source = {}; |
||||||
|
|
||||||
|
/* |
||||||
|
* A list of layer aliases that can be used to support specific use cases |
||||||
|
* (like coarse geocoding) * or work around the fact that different sources |
||||||
|
* may have layers that mean the same thing but have a different name |
||||||
|
*/ |
||||||
|
this.layer_aliases = {}; |
||||||
|
|
||||||
|
/* |
||||||
|
* An object that contains all sources or aliases. The key is the source or alias, |
||||||
|
* the value is either that source, or the canonical name for that alias if it's an alias. |
||||||
|
*/ |
||||||
|
this.source_mapping = {}; |
||||||
|
|
||||||
|
/* |
||||||
|
* An object that has a key for each possible layer or alias, |
||||||
|
* and returns either that layer, or gall the layers in the alias |
||||||
|
*/ |
||||||
|
this.layer_mapping = {}; |
||||||
|
}; |
||||||
|
|
||||||
|
TypeMapping.addStandardTargetsToAliases = function(standard, aliases) { |
||||||
|
var combined = _.extend({}, aliases); |
||||||
|
standard.forEach(function(target) { |
||||||
|
if (combined[target] === undefined) { |
||||||
|
combined[target] = [target]; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
return combined; |
||||||
|
}; |
||||||
|
|
||||||
|
// source alias setter
|
||||||
|
TypeMapping.prototype.setSourceAliases = function( aliases ){ |
||||||
|
this.source_aliases = aliases; |
||||||
|
}; |
||||||
|
|
||||||
|
// layers-by-source alias setter
|
||||||
|
TypeMapping.prototype.setLayersBySource = function( lbs ){ |
||||||
|
this.layers_by_source = lbs; |
||||||
|
}; |
||||||
|
|
||||||
|
// layer alias setter
|
||||||
|
TypeMapping.prototype.setLayerAliases = function( aliases ){ |
||||||
|
this.layer_aliases = aliases; |
||||||
|
}; |
||||||
|
|
||||||
|
// generate mappings after setters have been run
|
||||||
|
TypeMapping.prototype.generateMappings = function(){ |
||||||
|
this.sources = Object.keys( this.layers_by_source ); |
||||||
|
this.source_mapping = TypeMapping.addStandardTargetsToAliases(this.sources, this.source_aliases); |
||||||
|
this.layers = _.uniq(Object.keys(this.layers_by_source).reduce(function(acc, key) { |
||||||
|
return acc.concat(this.layers_by_source[key]); |
||||||
|
}.bind(this), [])); |
||||||
|
this.layer_mapping = TypeMapping.addStandardTargetsToAliases(this.layers, this.layer_aliases); |
||||||
|
}; |
||||||
|
|
||||||
|
// load values from targets block
|
||||||
|
TypeMapping.prototype.loadTargets = function( targetsBlock ){ |
||||||
|
|
||||||
|
if( !_.isObject(targetsBlock) ){ return; } |
||||||
|
|
||||||
|
// set values from targets block
|
||||||
|
this.setSourceAliases( targetsBlock.source_aliases || {} ); |
||||||
|
this.setLayersBySource( targetsBlock.layers_by_source || {} ); |
||||||
|
this.setLayerAliases( targetsBlock.layer_aliases || {} ); |
||||||
|
|
||||||
|
// generate the mappings
|
||||||
|
this.generateMappings(); |
||||||
|
}; |
||||||
|
|
||||||
|
// load values from either pelias config file or from elasticsearch
|
||||||
|
TypeMapping.prototype.load = function( done ){ |
||||||
|
|
||||||
|
// load pelias config
|
||||||
|
const peliasConfigTargets = _.get( |
||||||
|
require('pelias-config').generate(require('../schema')), |
||||||
|
'api.targets', {} |
||||||
|
); |
||||||
|
|
||||||
|
// load targets from config file
|
||||||
|
this.loadTargets( peliasConfigTargets ); |
||||||
|
|
||||||
|
// do not load values from elasticsearch
|
||||||
|
if( true !== peliasConfigTargets.auto_discover ){ |
||||||
|
if( 'function' === typeof done ){ done(); } |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if( 'function' === typeof done ){ done(); } |
||||||
|
return; |
||||||
|
|
||||||
|
// load values from elasticsearch
|
||||||
|
|
||||||
|
// create connection to elasticsearch
|
||||||
|
// const esclient = elasticsearch.Client(peliasConfig.esclient);
|
||||||
|
|
||||||
|
// const query = {
|
||||||
|
// requestCache: true,
|
||||||
|
// preference: '_replica_first',
|
||||||
|
// timeout: '10s',
|
||||||
|
// body: {
|
||||||
|
// aggs: {
|
||||||
|
// sources: {
|
||||||
|
// terms: {
|
||||||
|
// field: 'source',
|
||||||
|
// size: 100
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// layers: {
|
||||||
|
// terms: {
|
||||||
|
// field: 'layer',
|
||||||
|
// size: 100
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// size: 0
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// esclient.search( query, ( err, res ) => {
|
||||||
|
// console.error( err, res );
|
||||||
|
// });
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports = TypeMapping; |
@ -1,86 +1,8 @@ |
|||||||
const _ = require('lodash'); |
const TypeMapping = require('./TypeMapping'); |
||||||
|
|
||||||
function addStandardTargetsToAliases(standard, aliases) { |
// instantiate a new type mapping
|
||||||
var combined = _.extend({}, aliases); |
var tm = new TypeMapping(); |
||||||
standard.forEach(function(target) { |
tm.load(); |
||||||
if (combined[target] === undefined) { |
|
||||||
combined[target] = [target]; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
return combined; |
// export singleton
|
||||||
} |
module.exports = tm; |
||||||
|
|
||||||
/* |
|
||||||
* Sources |
|
||||||
*/ |
|
||||||
|
|
||||||
// a list of all sources
|
|
||||||
var SOURCES = ['openstreetmap', 'openaddresses', 'geonames', 'whosonfirst']; |
|
||||||
|
|
||||||
/* |
|
||||||
* A list of alternate names for sources, mostly used to save typing |
|
||||||
*/ |
|
||||||
var SOURCE_ALIASES = { |
|
||||||
'osm': ['openstreetmap'], |
|
||||||
'oa': ['openaddresses'], |
|
||||||
'gn': ['geonames'], |
|
||||||
'wof': ['whosonfirst'] |
|
||||||
}; |
|
||||||
|
|
||||||
/* |
|
||||||
* Create an object that contains all sources or aliases. The key is the source or alias, |
|
||||||
* the value is either that source, or the canonical name for that alias if it's an alias. |
|
||||||
*/ |
|
||||||
var SOURCE_MAPPING = addStandardTargetsToAliases(SOURCES, SOURCE_ALIASES); |
|
||||||
|
|
||||||
/* |
|
||||||
* Layers |
|
||||||
*/ |
|
||||||
|
|
||||||
/* |
|
||||||
* A list of all layers in each source. This is used for convenience elswhere |
|
||||||
* and to determine when a combination of source and layer parameters is |
|
||||||
* not going to match any records and will return no results. |
|
||||||
*/ |
|
||||||
var LAYERS_BY_SOURCE = { |
|
||||||
openstreetmap: [ 'address', 'venue', 'street' ], |
|
||||||
openaddresses: [ 'address' ], |
|
||||||
geonames: [ 'country','macroregion', 'region', 'county','localadmin', |
|
||||||
'locality','borough', 'neighbourhood', 'venue' ], |
|
||||||
whosonfirst: [ 'continent', 'empire', 'country', 'dependency', 'macroregion', 'region', |
|
||||||
'locality', 'localadmin', 'macrocounty', 'county', 'macrohood', 'borough', |
|
||||||
'neighbourhood', 'microhood', 'disputed', 'venue', 'postalcode', |
|
||||||
'continent', 'ocean', 'marinearea'] |
|
||||||
}; |
|
||||||
|
|
||||||
/* |
|
||||||
* A list of layer aliases that can be used to support specific use cases |
|
||||||
* (like coarse geocoding) * or work around the fact that different sources |
|
||||||
* may have layers that mean the same thing but have a different name |
|
||||||
*/ |
|
||||||
var LAYER_ALIASES = { |
|
||||||
'coarse': [ 'continent', 'empire', 'country', 'dependency', 'macroregion', |
|
||||||
'region', 'locality', 'localadmin', 'macrocounty', 'county', 'macrohood', |
|
||||||
'borough', 'neighbourhood', 'microhood', 'disputed', 'postalcode', |
|
||||||
'continent', 'ocean', 'marinearea'] |
|
||||||
}; |
|
||||||
|
|
||||||
// create a list of all layers by combining each entry from LAYERS_BY_SOURCE
|
|
||||||
var LAYERS = _.uniq(Object.keys(LAYERS_BY_SOURCE).reduce(function(acc, key) { |
|
||||||
return acc.concat(LAYERS_BY_SOURCE[key]); |
|
||||||
}, [])); |
|
||||||
|
|
||||||
/* |
|
||||||
* Create the an object that has a key for each possible layer or alias, |
|
||||||
* and returns either that layer, or all the layers in the alias |
|
||||||
*/ |
|
||||||
var LAYER_MAPPING = addStandardTargetsToAliases(LAYERS, LAYER_ALIASES); |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
sources: SOURCES, |
|
||||||
layers: LAYERS, |
|
||||||
source_mapping: SOURCE_MAPPING, |
|
||||||
layer_mapping: LAYER_MAPPING, |
|
||||||
layers_by_source: LAYERS_BY_SOURCE |
|
||||||
}; |
|
@ -1,7 +1,7 @@ |
|||||||
## Attribution |
## Attribution |
||||||
* Geocoding by [Pelias](https://pelias.io). |
* Geocoding by [Pelias](https://pelias.io). |
||||||
* Data from |
* Data from |
||||||
* [OpenStreetMap](http://www.openstreetmap.org/copyright) © OpenStreetMap contributors under [ODbL](http://opendatacommons.org/licenses/odbl/) |
* [OpenStreetMap](http://www.openstreetmap.org/copyright) © OpenStreetMap contributors under [ODbL](http://opendatacommons.org/licenses/odbl/). Also see the [OSM Geocoding Guidelines](https://wiki.osmfoundation.org/wiki/Licence/Community_Guidelines/Geocoding_-_Guideline) for acceptable use. |
||||||
* [OpenAddresses](http://openaddresses.io) under a [Creative Commons Zero](https://github.com/openaddresses/openaddresses/blob/master/sources/LICENSE) public domain designation |
* [OpenAddresses](http://openaddresses.io) under [various public-domain and share-alike licenses](http://results.openaddresses.io/) |
||||||
* [GeoNames](http://www.geonames.org/) under [CC-BY-3.0](https://creativecommons.org/licenses/by/2.0/) |
* [GeoNames](http://www.geonames.org/) under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) |
||||||
* [WhosOnFirst](https://www.whosonfirst.org/) under [various licenses](https://github.com/whosonfirst/whosonfirst-data/blob/master/LICENSE.md) |
* [WhosOnFirst](https://www.whosonfirst.org/) under [various CC-BY or CC-0 equivalent licenses](https://whosonfirst.org/docs/licenses/) |
||||||
|
@ -1,38 +0,0 @@ |
|||||||
var peliasQuery = require('pelias-query'); |
|
||||||
|
|
||||||
/** |
|
||||||
This view is the same as `peliasQuery.view.focus` with one exception: |
|
||||||
|
|
||||||
if the view is generated successfully, we add a 'filter' clause which |
|
||||||
restricts the targeted '_type' to be in the list specified below. |
|
||||||
|
|
||||||
documents which are not in the '_type' list below will simply score 0 for |
|
||||||
this section of the query. |
|
||||||
**/ |
|
||||||
|
|
||||||
module.exports = function( subview ){ |
|
||||||
return function( vs ){ |
|
||||||
|
|
||||||
// don't perform this query on single character inputs
|
|
||||||
// as its too unperformant to sort a large part of the index.
|
|
||||||
if( vs.var('input:name').get().length < 2 ){ |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
if( !subview ){ return null; } // subview validation failed
|
|
||||||
var macroView = peliasQuery.view.focus( subview ); |
|
||||||
if( !macroView ){ return null; } // macroView validation failed
|
|
||||||
var view = macroView( vs ); |
|
||||||
|
|
||||||
if( view && view.hasOwnProperty('function_score') ){ |
|
||||||
view.function_score.filter = { |
|
||||||
'or': [ |
|
||||||
{ 'term': { 'layer': 'venue' } }, |
|
||||||
{ 'term': { 'layer': 'address' } } |
|
||||||
] |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
return view; |
|
||||||
}; |
|
||||||
}; |
|
@ -1,43 +0,0 @@ |
|||||||
var _ = require('lodash'); |
|
||||||
|
|
||||||
/** |
|
||||||
In the process of phasing out the 'quattroshapes' source in favour of 'whosonfirst' |
|
||||||
we will emit a warning to users so they can begin upgrading their clients. |
|
||||||
|
|
||||||
In the interim we will automatically rewrite all requests for quattroshapes to whosonfirst. |
|
||||||
|
|
||||||
@todo: this is only temporary |
|
||||||
@see: https://github.com/pelias/api/issues/442
|
|
||||||
**/ |
|
||||||
|
|
||||||
function _sanitize( raw, clean, opts ) { |
|
||||||
// error & warning messages
|
|
||||||
var messages = { errors: [], warnings: [] }; |
|
||||||
|
|
||||||
// only applicably when 'sources' param is privided
|
|
||||||
if( raw.hasOwnProperty('sources') ){ |
|
||||||
|
|
||||||
var sources = raw.sources.split(','); |
|
||||||
if (_.includes(sources, 'quattroshapes') || _.includes(sources, 'qs')) { |
|
||||||
|
|
||||||
// emit a warning message so users can transition.
|
|
||||||
messages.warnings.push('You are using Quattroshapes as a data source in this query. ' + |
|
||||||
'Quattroshapes has been disabled as a data source for Mapzen Search, and has been' + |
|
||||||
'replaced by Who\'s on First, an actively maintained data project based on Quattroshapes' + |
|
||||||
'Your existing queries WILL CONTINUE TO WORK for the foreseeable future, but results will ' + |
|
||||||
'be coming from Who\'s on First and `sources=quattroshapes` will be interpreted as ' + |
|
||||||
'`sources=whosonfirst`. If you have any questions, please email pelias.team@gmail.com.'); |
|
||||||
|
|
||||||
// user requested 'quattroshapes', we will give them 'whosonfirst' instead.
|
|
||||||
sources = _.without(sources, 'quattroshapes', 'qs'); |
|
||||||
sources.push('whosonfirst'); |
|
||||||
raw.sources = sources.join(','); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return messages; |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = () => ({ |
|
||||||
sanitize: _sanitize |
|
||||||
}); |
|
@ -1,34 +0,0 @@ |
|||||||
|
|
||||||
#> quattroshapes is being phased out and so should emit a warning message |
|
||||||
path: '/v1/reverse?point.lat=1&point.lon=2&sources=qs' |
|
||||||
|
|
||||||
#? 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 errors |
|
||||||
should.not.exist json.geocoding.errors |
|
||||||
|
|
||||||
#? expected warnings |
|
||||||
should.exist json.geocoding.warnings |
|
||||||
json.geocoding.warnings.should.eql ['You are using Quattroshapes as a data source in this query. Quattroshapes has been disabled as a data source for Mapzen Search, and has beenreplaced by Who\'s on First, an actively maintained data project based on QuattroshapesYour existing queries WILL CONTINUE TO WORK for the foreseeable future, but results will be coming from Who\'s on First and `sources=quattroshapes` will be interpreted as `sources=whosonfirst`. If you have any questions, please email pelias.team@gmail.com.' ] |
|
||||||
|
|
||||||
#? inputs |
|
||||||
json.geocoding.query['size'].should.eql 10 |
|
||||||
json.geocoding.query.sources.should.eql ['whosonfirst'] # should use 'whosonfirst' instead of 'quattroshapes' |
|
@ -1,35 +0,0 @@ |
|||||||
|
|
||||||
#> quattroshapes is being phased out and so should emit a warning message |
|
||||||
path: '/v1/search?sources=qs&text=a' |
|
||||||
|
|
||||||
#? 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 errors |
|
||||||
should.not.exist json.geocoding.errors |
|
||||||
|
|
||||||
#? expected warnings |
|
||||||
should.exist json.geocoding.warnings |
|
||||||
json.geocoding.warnings.should.eql ['You are using Quattroshapes as a data source in this query. Quattroshapes has been disabled as a data source for Mapzen Search, and has beenreplaced by Who\'s on First, an actively maintained data project based on QuattroshapesYour existing queries WILL CONTINUE TO WORK for the foreseeable future, but results will be coming from Who\'s on First and `sources=quattroshapes` will be interpreted as `sources=whosonfirst`. If you have any questions, please email pelias.team@gmail.com.' ] |
|
||||||
|
|
||||||
#? inputs |
|
||||||
json.geocoding.query['size'].should.eql 10 |
|
||||||
json.geocoding.query['text'].should.eql 'a' |
|
||||||
json.geocoding.query.sources.should.eql ['whosonfirst'] # should use 'whosonfirst' instead of 'quattroshapes' |
|
@ -0,0 +1,90 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
const is_request_sources_includes_whosonfirst = require('../../../../controller/predicates/is_request_sources_includes_whosonfirst'); |
||||||
|
|
||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
module.exports.tests.interface = (test, common) => { |
||||||
|
test('valid interface', (t) => { |
||||||
|
t.ok(_.isFunction(is_request_sources_includes_whosonfirst), 'is_request_sources_includes_whosonfirst is a function'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.true_conditions = (test, common) => { |
||||||
|
test('sources includes \'whosonfirst\' should return true', (t) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
sources: [ |
||||||
|
'whosonfirst', |
||||||
|
'not whosonfirst' |
||||||
|
] |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
t.ok(is_request_sources_includes_whosonfirst(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('empty req.clean.sources should return false', (t) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
sources: [] |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
t.notOk(is_request_sources_includes_whosonfirst(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.false_conditions = (test, common) => { |
||||||
|
test('undefined req should return false', (t) => { |
||||||
|
t.notOk(is_request_sources_includes_whosonfirst(undefined)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('undefined req.clean should return false', (t) => { |
||||||
|
const req = {}; |
||||||
|
|
||||||
|
t.notOk(is_request_sources_includes_whosonfirst(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('undefined req.clean.sources should return false', (t) => { |
||||||
|
const req = { |
||||||
|
clean: {} |
||||||
|
}; |
||||||
|
|
||||||
|
t.notOk(is_request_sources_includes_whosonfirst(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('sources not \'whosonfirst\' should return false', (t) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
sources: [ |
||||||
|
'not whosonfirst' |
||||||
|
] |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
t.notOk(is_request_sources_includes_whosonfirst(req)); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = (tape, common) => { |
||||||
|
function test(name, testFunction) { |
||||||
|
return tape(`GET /is_request_sources_includes_whosonfirst ${name}`, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( const testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,78 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
const is_request_sources_undefined = require('../../../../controller/predicates/is_request_sources_undefined'); |
||||||
|
|
||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
module.exports.tests.interface = (test, common) => { |
||||||
|
test('valid interface', (t) => { |
||||||
|
t.ok(_.isFunction(is_request_sources_undefined), 'is_request_sources_undefined is a function'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.true_conditions = (test, common) => { |
||||||
|
test('undefined req should return true', (t) => { |
||||||
|
|
||||||
|
t.ok(is_request_sources_undefined(undefined)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('undefined req.clean should return true', (t) => { |
||||||
|
const req = {}; |
||||||
|
|
||||||
|
t.ok(is_request_sources_undefined(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('undefined req.clean.sources should return true', (t) => { |
||||||
|
const req = { |
||||||
|
clean: {} |
||||||
|
}; |
||||||
|
|
||||||
|
t.ok(is_request_sources_undefined(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
test('empty req.clean.sources should return true', (t) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
sources: [] |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
t.ok(is_request_sources_undefined(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.false_conditions = (test, common) => { |
||||||
|
test('sources not empty should return false', (t) => { |
||||||
|
const req = { |
||||||
|
clean: { |
||||||
|
sources: [ |
||||||
|
'not empty' |
||||||
|
] |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
t.notOk(is_request_sources_undefined(req)); |
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = (tape, common) => { |
||||||
|
function test(name, testFunction) { |
||||||
|
return tape(`GET /is_request_sources_undefined ${name}`, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( const testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,208 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
const TypeMapping = require('../../../helper/TypeMapping'); |
||||||
|
|
||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
module.exports.tests.interface = function(test) { |
||||||
|
test('valid interface', function(t) { |
||||||
|
t.equal(typeof TypeMapping, 'function', 'TypeMapping is a function'); |
||||||
|
|
||||||
|
t.equal(typeof TypeMapping.addStandardTargetsToAliases, 'function', 'addStandardTargetsToAliases() is a function'); |
||||||
|
t.equal(typeof TypeMapping.prototype.setSourceAliases, 'function', 'setSourceAliases() is a function'); |
||||||
|
|
||||||
|
t.equal(typeof TypeMapping.prototype.setLayersBySource, 'function', 'setLayersBySource() is a function'); |
||||||
|
t.equal(typeof TypeMapping.prototype.setLayerAliases, 'function', 'setLayerAliases() is a function'); |
||||||
|
|
||||||
|
t.equal(typeof TypeMapping.prototype.generateMappings, 'function', 'generateMappings() is a function'); |
||||||
|
|
||||||
|
t.equal(typeof TypeMapping.prototype.loadTargets, 'function', 'loadTargets() is a function'); |
||||||
|
t.equal(typeof TypeMapping.prototype.load, 'function', 'load() is a function'); |
||||||
|
|
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.constructor = function(test) { |
||||||
|
test('constructor', function(t) { |
||||||
|
|
||||||
|
var doc = new TypeMapping(); |
||||||
|
|
||||||
|
// initial values
|
||||||
|
t.deepEqual(doc.sources, [], 'initial value'); |
||||||
|
t.deepEqual(doc.source_aliases, {}, 'initial value'); |
||||||
|
t.deepEqual(doc.layers, [], 'initial value'); |
||||||
|
t.deepEqual(doc.layers_by_source, {}, 'initial value'); |
||||||
|
t.deepEqual(doc.layer_aliases, {}, 'initial value'); |
||||||
|
t.deepEqual(doc.source_mapping, {}, 'initial value'); |
||||||
|
t.deepEqual(doc.layer_mapping, {}, 'initial value'); |
||||||
|
|
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.addStandardTargetsToAliases = function(test) { |
||||||
|
test('static method addStandardTargetsToAliases', function(t) { |
||||||
|
|
||||||
|
var aliases = { test: ['test2'] }; |
||||||
|
|
||||||
|
t.deepEqual( |
||||||
|
TypeMapping.addStandardTargetsToAliases([], aliases), |
||||||
|
{ test: ['test2'] } |
||||||
|
); |
||||||
|
t.deepEqual(aliases, aliases, 'aliases object not mutated'); |
||||||
|
|
||||||
|
t.deepEqual( |
||||||
|
TypeMapping.addStandardTargetsToAliases(['test'], aliases), |
||||||
|
{ test: ['test2'] }, |
||||||
|
'not modified' |
||||||
|
); |
||||||
|
t.deepEqual(aliases, aliases, 'aliases object not mutated'); |
||||||
|
|
||||||
|
t.deepEqual( |
||||||
|
TypeMapping.addStandardTargetsToAliases(['baz'], aliases), |
||||||
|
{ test: ['test2'], baz: ['baz'] } |
||||||
|
); |
||||||
|
t.deepEqual(aliases, aliases, 'aliases object not mutated'); |
||||||
|
|
||||||
|
t.deepEqual( |
||||||
|
TypeMapping.addStandardTargetsToAliases(['baz','boo'], aliases), |
||||||
|
{ test: ['test2'], baz: ['baz'], boo: ['boo'] } |
||||||
|
); |
||||||
|
t.deepEqual(aliases, aliases, 'aliases object not mutated'); |
||||||
|
|
||||||
|
t.end(); |
||||||
|
|
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.setSourceAliases = function(test) { |
||||||
|
test('setter setSourceAliases', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
t.deepEqual(tm.source_aliases, {}); |
||||||
|
tm.setSourceAliases({ foo: ['foo', 'bar'] }); |
||||||
|
t.deepEqual(tm.source_aliases, { foo: ['foo', 'bar'] }); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.setLayersBySource = function(test) { |
||||||
|
test('setter setLayersBySource', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
t.deepEqual(tm.layers_by_source, {}); |
||||||
|
tm.setLayersBySource({ foo: ['foo', 'bar'] }); |
||||||
|
t.deepEqual(tm.layers_by_source, { foo: ['foo', 'bar'] }); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.setLayerAliases = function(test) { |
||||||
|
test('setter setLayerAliases', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
t.deepEqual(tm.layer_aliases, {}); |
||||||
|
tm.setLayerAliases({ foo: ['foo', 'bar'] }); |
||||||
|
t.deepEqual(tm.layer_aliases, { foo: ['foo', 'bar'] }); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.generateMappings = function(test) { |
||||||
|
test('generateMappings - no-op', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
t.deepEqual(tm.sources, []); |
||||||
|
t.deepEqual(tm.source_mapping, {}); |
||||||
|
t.deepEqual(tm.layers, []); |
||||||
|
t.deepEqual(tm.layer_mapping, {}); |
||||||
|
tm.generateMappings(); |
||||||
|
t.deepEqual(tm.sources, []); |
||||||
|
t.deepEqual(tm.source_mapping, {}); |
||||||
|
t.deepEqual(tm.layers, []); |
||||||
|
t.deepEqual(tm.layer_mapping, {}); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
test('generateMappings - sources', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
tm.layers_by_source = { foo: ['foo'], faz: ['faz'] }; |
||||||
|
tm.generateMappings(); |
||||||
|
t.deepEqual(tm.sources, ['foo', 'faz']); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
test('generateMappings - source_mapping', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
tm.layers_by_source = { foo: ['foo'], faz: ['faz'] }; |
||||||
|
tm.source_aliases = { foo: ['foo','f'], bar: ['bar', 'b'], baz: ['baz'] }; |
||||||
|
tm.generateMappings(); |
||||||
|
t.deepEqual(tm.source_mapping, { foo: ['foo', 'f'], bar: ['bar', 'b'], baz: ['baz'], faz: ['faz'] }); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
test('generateMappings - layers', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
tm.layers_by_source = { foo: ['foo'], faz: ['faz'] }; |
||||||
|
tm.generateMappings(); |
||||||
|
t.deepEqual(tm.layers, ['foo','faz']); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
test('generateMappings - layer_mapping', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
tm.layers_by_source = { foo: ['foo'], faz: ['faz'] }; |
||||||
|
tm.layer_aliases = { foo: ['foo','f'], bar: ['bar', 'b'], baz: ['baz'] }; |
||||||
|
tm.generateMappings(); |
||||||
|
t.deepEqual(tm.layer_mapping, { foo: ['foo', 'f'], bar: ['bar', 'b'], baz: ['baz'], faz: ['faz'] }); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.loadTargets = function(test) { |
||||||
|
test('loadTargets - undefined', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
tm.loadTargets(); |
||||||
|
t.deepEqual(tm.sources, []); |
||||||
|
t.deepEqual(tm.source_mapping, {}); |
||||||
|
t.deepEqual(tm.layers, []); |
||||||
|
t.deepEqual(tm.layer_mapping, {}); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
test('loadTargets', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
tm.loadTargets({ |
||||||
|
source_aliases: { source1: ['s1', 's2'], source2: ['s3', 's4'] }, |
||||||
|
layers_by_source: { source1: ['layer1', 'layer3'], source2: ['layer2'] }, |
||||||
|
layer_aliases: { layer1: ['l1', 'l2'], layer2: ['l3', 'l4'] }, |
||||||
|
}); |
||||||
|
t.deepEqual(tm.sources, [ 'source1', 'source2' ]); |
||||||
|
t.deepEqual(tm.source_mapping, { source1: [ 's1', 's2' ], source2: [ 's3', 's4' ] }); |
||||||
|
t.deepEqual(tm.layers, [ 'layer1', 'layer3', 'layer2' ]); |
||||||
|
t.deepEqual(tm.layer_mapping, { layer1: [ 'l1', 'l2' ], layer2: [ 'l3', 'l4' ], layer3: [ 'layer3' ] }); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.load = function(test) { |
||||||
|
test('load from pelias config', function(t) { |
||||||
|
var tm = new TypeMapping(); |
||||||
|
tm.load(() => { |
||||||
|
|
||||||
|
// load pelias config
|
||||||
|
const expected = _.get( |
||||||
|
require('pelias-config').generate(require('../../../schema')), |
||||||
|
'api.targets', {} |
||||||
|
); |
||||||
|
|
||||||
|
// values copied from config
|
||||||
|
t.deepEqual(tm.layers_by_source, expected.layers_by_source || {}); |
||||||
|
t.deepEqual(tm.source_aliases, expected.source_aliases || {}); |
||||||
|
t.deepEqual(tm.layer_aliases, expected.layer_aliases || {}); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = function (tape, common) { |
||||||
|
|
||||||
|
function test(name, testFunction) { |
||||||
|
return tape('TypeMapping: ' + name, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( var testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
@ -1,65 +0,0 @@ |
|||||||
var sanitizer = require('../../../sanitizer/_deprecate_quattroshapes')(); |
|
||||||
|
|
||||||
module.exports.tests = {}; |
|
||||||
|
|
||||||
module.exports.tests.warning_message_1 = function(test, common) { |
|
||||||
test('[qs] should emit a deprecation warning', function(t) { |
|
||||||
var raw = { sources: 'qs' }; |
|
||||||
var clean = {}; |
|
||||||
|
|
||||||
var messages = sanitizer.sanitize(raw, clean); |
|
||||||
t.deepEquals(messages, { |
|
||||||
errors: [], |
|
||||||
warnings: ['You are using Quattroshapes as a data source in this query. ' + |
|
||||||
'Quattroshapes has been disabled as a data source for Mapzen Search, and has been' + |
|
||||||
'replaced by Who\'s on First, an actively maintained data project based on Quattroshapes' + |
|
||||||
'Your existing queries WILL CONTINUE TO WORK for the foreseeable future, but results will ' + |
|
||||||
'be coming from Who\'s on First and `sources=quattroshapes` will be interpreted as ' + |
|
||||||
'`sources=whosonfirst`. If you have any questions, please email pelias.team@gmail.com.'] |
|
||||||
}, 'warning emitted'); |
|
||||||
|
|
||||||
t.end(); |
|
||||||
}); |
|
||||||
}; |
|
||||||
|
|
||||||
module.exports.tests.warning_message_2 = function(test, common) { |
|
||||||
test('[quattroshapes] should emit a deprecation warning', function(t) { |
|
||||||
var raw = { sources: 'quattroshapes' }; |
|
||||||
var clean = {}; |
|
||||||
|
|
||||||
var messages = sanitizer.sanitize(raw, clean); |
|
||||||
t.deepEquals(messages, { |
|
||||||
errors: [], |
|
||||||
warnings: ['You are using Quattroshapes as a data source in this query. ' + |
|
||||||
'Quattroshapes has been disabled as a data source for Mapzen Search, and has been' + |
|
||||||
'replaced by Who\'s on First, an actively maintained data project based on Quattroshapes' + |
|
||||||
'Your existing queries WILL CONTINUE TO WORK for the foreseeable future, but results will ' + |
|
||||||
'be coming from Who\'s on First and `sources=quattroshapes` will be interpreted as ' + |
|
||||||
'`sources=whosonfirst`. If you have any questions, please email pelias.team@gmail.com.'] |
|
||||||
}, 'warning emitted'); |
|
||||||
|
|
||||||
t.end(); |
|
||||||
}); |
|
||||||
}; |
|
||||||
|
|
||||||
module.exports.tests.rewrite = function(test, common) { |
|
||||||
test('should rewrite qs and quattroshapes to whosonfirst', function(t) { |
|
||||||
var raw = { sources: 'qs,quattroshapes,qs,quattroshapes,osm' }; |
|
||||||
var clean = {}; |
|
||||||
|
|
||||||
sanitizer.sanitize(raw, clean); |
|
||||||
t.equals(raw.sources,'osm,whosonfirst','use wof instead of qs'); |
|
||||||
|
|
||||||
t.end(); |
|
||||||
}); |
|
||||||
}; |
|
||||||
|
|
||||||
module.exports.all = function (tape, common) { |
|
||||||
function test(name, testFunction) { |
|
||||||
return tape('SANITIZE _deprecate_quattroshapes ' + name, testFunction); |
|
||||||
} |
|
||||||
|
|
||||||
for( var testCase in module.exports.tests ){ |
|
||||||
module.exports.tests[testCase](test, common); |
|
||||||
} |
|
||||||
}; |
|
Loading…
Reference in new issue