Browse Source

Rename `source` to `sources`

... with a dash of refactoring thrown in for good measure
pull/250/head
Diana Shkolnikov 9 years ago
parent
commit
67e034f5f2
  1. 20
      helper/types.js
  2. 30
      middleware/_types.js
  3. 8
      query/sources.js
  4. 44
      sanitiser/_source.js
  5. 44
      sanitiser/_sources.js
  6. 2
      sanitiser/reverse.js
  7. 2
      sanitiser/search.js
  8. 32
      test/unit/helper/types.js
  9. 2
      test/unit/run.js
  10. 31
      test/unit/sanitiser/_sources.js

20
helper/types.js

@ -9,23 +9,29 @@ var intersection = function intersection(set1, set2) {
}); });
}; };
/**
* Combine all types and determine the unique subset
*
* @param {Array} clean_types
* @returns {Array}
*/
module.exports = function calculate_types(clean_types) { module.exports = function calculate_types(clean_types) {
if (!clean_types) { if (!clean_types || !(clean_types.from_layers || clean_types.from_sources || clean_types.from_address_parser)) {
return undefined; throw new Error('clean_types should not be null or undefined');
} }
/* the layers and source parameters are cumulative: /* the layers and source parameters are cumulative:
* perform a set insersection of their specified types * perform a set intersection of their specified types
*/ */
if (clean_types.from_layers || clean_types.from_source) { if (clean_types.from_layers || clean_types.from_sources) {
var types = valid_types; var types = valid_types;
if (clean_types.from_layers) { if (clean_types.from_layers) {
types = intersection(types, clean_types.from_layers); types = intersection(types, clean_types.from_layers);
} }
if (clean_types.from_source) { if (clean_types.from_sources) {
types = intersection(types, clean_types.from_source); types = intersection(types, clean_types.from_sources);
} }
return types; return types;
@ -38,4 +44,6 @@ module.exports = function calculate_types(clean_types) {
if (clean_types.from_address_parser) { if (clean_types.from_address_parser) {
return clean_types.from_address_parser; return clean_types.from_address_parser;
} }
throw new Error('no types specified');
}; };

30
middleware/_types.js

@ -8,17 +8,27 @@ var types_helper = require( '../helper/types' );
* message instead of searching at all. * message instead of searching at all.
*/ */
function middleware(req, res, next) { function middleware(req, res, next) {
var types = types_helper(req.clean.types); req.clean = req.clean || {};
if (types !== undefined && types.length !== undefined) { if (req.clean.hasOwnProperty('types') === false) {
if (types.length === 0) { return next();
var err = 'You have specified both the `source` and `layers` ' + }
'parameters in a combination that will return no results.';
res.status(400); // 400 Bad Request try {
return next(err); var types = types_helper(req.clean.types);
} else {
req.clean.type = types; if ((types instanceof Array) && types.length === 0) {
} var err = 'You have specified both the `sources` and `layers` ' +
'parameters in a combination that will return no results.';
res.status(400); // 400 Bad Request
return next(err);
}
req.clean.type = types;
}
catch (err) {
// this means there were no types specified
delete req.clean.types;
} }
next(); next();

8
query/sources.js

@ -3,8 +3,12 @@
*/ */
module.exports = { module.exports = {
'geonames': ['geoname'], 'gn' : ['geoname'],
'geonames' : ['geoname'],
'oa' : ['openaddresses'],
'openaddresses' : ['openaddresses'], 'openaddresses' : ['openaddresses'],
'quattroshapes': ['admin0', 'admin1', 'admin2', 'neighborhood', 'locality', 'local_admin'], 'qs' : ['admin0', 'admin1', 'admin2', 'neighborhood', 'locality', 'local_admin'],
'quattroshapes' : ['admin0', 'admin1', 'admin2', 'neighborhood', 'locality', 'local_admin'],
'osm' : ['osmaddress', 'osmnode', 'osmway'],
'openstreetmap' : ['osmaddress', 'osmnode', 'osmway'] 'openstreetmap' : ['osmaddress', 'osmnode', 'osmway']
}; };

44
sanitiser/_source.js

@ -1,44 +0,0 @@
var isObject = require('is-object');
var sources_map = require( '../query/sources' );
var all_sources = Object.keys(sources_map);
function sanitize( req ) {
req.clean = req.clean || {};
var params = req.query;
req.clean.types = req.clean.types || {};
// ensure the input params are a valid object
if( !isObject( params ) ){
params = {};
}
// default case (no layers specified in GET params)
// don't even set the from_layers key in this case
if('string' !== typeof params.source || !params.source.length){
return { error: false };
}
var sources = params.source.split(',');
var invalid_sources = sources.filter(function(source) {
return all_sources.indexOf(source) === -1;
});
if (invalid_sources.length > 0) {
return {
error: true,
msg: '`' + invalid_sources[0] + '` is an invalid source parameter. Valid options: ' + all_sources.join(', ')
};
}
var types = sources.reduce(function(acc, source) {
return acc.concat(sources_map[source]);
}, []);
req.clean.types.from_source = types;
return { error: false };
}
module.exports = sanitize;

44
sanitiser/_sources.js

@ -0,0 +1,44 @@
var isObject = require('is-object');
var sources_map = require( '../query/sources' );
function sanitize( req ) {
var params = req.query || {};
req.clean = req.clean || {};
req.clean.types = req.clean.types || {};
// default case (no sources specified in GET params)
if (params.hasOwnProperty('sources') === false) {
return { error: false };
}
params.sources = params.sources.trim();
if (params.sources.trim().length === 0) {
return {
error: true,
message: '`sources` parameter cannot be an empty string. Valid options: ' + Object.keys(sources_map).join(', ')
};
}
var sources = params.sources.split(',');
var invalid_sources = sources.filter(function(source) {
return sources_map.hasOwnProperty(source) === false;
});
if (invalid_sources.length > 0) {
return {
error: true,
message: '`' + invalid_sources[0] + '` is an invalid source parameter. Valid options: ' + Object.keys(sources_map).join(', ')
};
}
req.clean.types.from_sources = sources.reduce(function(acc, source) {
return acc.concat(sources_map[source]);
}, []);
return { error: false };
}
module.exports = sanitize;

2
sanitiser/reverse.js

@ -2,7 +2,7 @@ var _sanitize = require('../sanitiser/_sanitize'),
sanitiser = { sanitiser = {
latlonzoom: require('../sanitiser/_geo_reverse'), latlonzoom: require('../sanitiser/_geo_reverse'),
layers: require('../sanitiser/_layers'), layers: require('../sanitiser/_layers'),
suorce: require('../sanitiser/_source'), suorce: require('../sanitiser/_sources'),
details: require('../sanitiser/_details'), details: require('../sanitiser/_details'),
size: require('../sanitiser/_size'), size: require('../sanitiser/_size'),
categories: function ( req ) { categories: function ( req ) {

2
sanitiser/search.js

@ -4,7 +4,7 @@ var _sanitize = require('../sanitiser/_sanitize'),
text: require('../sanitiser/_text'), text: require('../sanitiser/_text'),
size: require('../sanitiser/_size'), size: require('../sanitiser/_size'),
layers: require('../sanitiser/_layers'), layers: require('../sanitiser/_layers'),
source: require('../sanitiser/_source'), source: require('../sanitiser/_sources'),
details: require('../sanitiser/_details'), details: require('../sanitiser/_details'),
latlonzoom: require('../sanitiser/_geo_search') latlonzoom: require('../sanitiser/_geo_search')
}; };

32
test/unit/helper/types.js

@ -1,20 +1,32 @@
var types = require('../../../helper/types'); var types = require('../../../helper/types');
var valid_types = require( '../../../query/types' );
module.exports.tests = {}; module.exports.tests = {};
module.exports.tests.no_cleaned_types = function(test, common) { module.exports.tests.no_cleaned_types = function(test, common) {
test('no cleaned types', function(t) { test('no cleaned types', function(t) {
var actual = types(undefined); try {
t.equal(actual, undefined, 'all valid types returned for empty input'); types();
t.end(); t.fail('exception should be thrown');
}
catch (err) {
t.equal(err.message, 'clean_types should not be null or undefined', 'no input should result in exception');
}
finally {
t.end();
}
}); });
test('no cleaned types', function(t) { test('no cleaned types', function(t) {
var cleaned_types = {}; try {
var actual = types(cleaned_types); types({});
t.equal(actual, undefined, 'all valid types returned for empty input'); t.fail('exception should be thrown');
t.end(); }
catch (err) {
t.equal(err.message, 'clean_types should not be null or undefined', 'no input should result in exception');
}
finally {
t.end();
}
}); });
}; };
@ -58,7 +70,7 @@ module.exports.tests.layers_parameter_and_address_parser = function(test, common
module.exports.tests.source_parameter = function(test, common) { module.exports.tests.source_parameter = function(test, common) {
test('source parameter specified', function(t) { test('source parameter specified', function(t) {
var cleaned_types = { var cleaned_types = {
from_source: ['openaddresses'] from_sources: ['openaddresses']
}; };
var actual = types(cleaned_types); var actual = types(cleaned_types);
@ -72,7 +84,7 @@ module.exports.tests.source_parameter = function(test, common) {
module.exports.tests.source_and_layers_parameters = function(test, common) { module.exports.tests.source_and_layers_parameters = function(test, common) {
test('source and layers parameter both specified', function(t) { test('source and layers parameter both specified', function(t) {
var cleaned_types = { var cleaned_types = {
from_source: ['openaddresses'], from_sources: ['openaddresses'],
from_layers: ['osmaddress', 'openaddresses'] from_layers: ['osmaddress', 'openaddresses']
}; };

2
test/unit/run.js

@ -8,7 +8,7 @@ var tests = [
require('./controller/search'), require('./controller/search'),
require('./service/mget'), require('./service/mget'),
require('./service/search'), require('./service/search'),
require('./sanitiser/_source'), require('./sanitiser/_sources'),
require('./sanitiser/search'), require('./sanitiser/search'),
require('./sanitiser/reverse'), require('./sanitiser/reverse'),
require('./sanitiser/place'), require('./sanitiser/place'),

31
test/unit/sanitiser/_source.js → test/unit/sanitiser/_sources.js

@ -1,11 +1,11 @@
var sanitize = require( '../../../sanitiser/_source' ); var sanitize = require( '../../../sanitiser/_sources' );
var success_response = { error: false }; var success_response = { error: false };
module.exports.tests = {}; module.exports.tests = {};
module.exports.tests.no_sources = function(test, common) { module.exports.tests.no_sources = function(test, common) {
test('source is not set', function(t) { test('sources is not set', function(t) {
var req = { var req = {
query: { } query: { }
}; };
@ -20,14 +20,20 @@ module.exports.tests.no_sources = function(test, common) {
test('source is empty string', function(t) { test('source is empty string', function(t) {
var req = { var req = {
query: { query: {
source: '' sources: ''
} }
}; };
var expected_response = {
error: true,
message: '`sources` parameter cannot be an empty string. ' +
'Valid options: gn, geonames, oa, openaddresses, qs, quattroshapes, osm, openstreetmap'
};
var response = sanitize(req); var response = sanitize(req);
t.deepEqual(req.clean.types, {}, 'clean.types should be empty object'); t.deepEqual(req.clean.types, {}, 'clean.types should be empty object');
t.deepEqual(response, success_response, 'no error returned'); t.deepEqual(response, expected_response, 'no error returned');
t.end(); t.end();
}); });
}; };
@ -36,13 +42,13 @@ module.exports.tests.valid_sources = function(test, common) {
test('geonames source', function(t) { test('geonames source', function(t) {
var req = { var req = {
query: { query: {
source: 'geonames' sources: 'geonames'
} }
}; };
var response = sanitize(req); var response = sanitize(req);
t.deepEqual(req.clean.types, { from_source: ['geoname'] }, 'clean.types should contain from_source entry with geonames'); t.deepEqual(req.clean.types, { from_sources: ['geoname'] }, 'clean.types should contain from_source entry with geonames');
t.deepEqual(response, success_response, 'no error returned'); t.deepEqual(response, success_response, 'no error returned');
t.end(); t.end();
}); });
@ -50,11 +56,11 @@ module.exports.tests.valid_sources = function(test, common) {
test('openstreetmap source', function(t) { test('openstreetmap source', function(t) {
var req = { var req = {
query: { query: {
source: 'openstreetmap' sources: 'openstreetmap'
} }
}; };
var expected_types = { var expected_types = {
from_source: ['osmaddress', 'osmnode', 'osmway'] from_sources: ['osmaddress', 'osmnode', 'osmway']
}; };
var response = sanitize(req); var response = sanitize(req);
@ -67,11 +73,11 @@ module.exports.tests.valid_sources = function(test, common) {
test('multiple sources', function(t) { test('multiple sources', function(t) {
var req = { var req = {
query: { query: {
source: 'openstreetmap,openaddresses' sources: 'openstreetmap,openaddresses'
} }
}; };
var expected_types = { var expected_types = {
from_source: ['osmaddress', 'osmnode', 'osmway', 'openaddresses'] from_sources: ['osmaddress', 'osmnode', 'osmway', 'openaddresses']
}; };
var response = sanitize(req); var response = sanitize(req);
@ -87,12 +93,13 @@ module.exports.tests.invalid_sources = function(test, common) {
test('geonames source', function(t) { test('geonames source', function(t) {
var req = { var req = {
query: { query: {
source: 'notasource' sources: 'notasource'
} }
}; };
var expected_response = { var expected_response = {
error: true, error: true,
msg: '`notasource` is an invalid source parameter. Valid options: geonames, openaddresses, quattroshapes, openstreetmap' message: '`notasource` is an invalid source parameter. ' +
'Valid options: gn, geonames, oa, openaddresses, qs, quattroshapes, osm, openstreetmap'
}; };
var response = sanitize(req); var response = sanitize(req);
Loading…
Cancel
Save