mirror of https://github.com/pelias/api.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
4.8 KiB
182 lines
4.8 KiB
var _ = require('lodash'); |
|
var placeTypes = require('./placeTypes'); |
|
|
|
/** |
|
* Compare the layer properties if they exist. |
|
* Returns false if the objects are the same, and throws |
|
* an exception with the message 'different' if not. |
|
* |
|
* @param {object} item1 |
|
* @param {object} item2 |
|
* @returns {boolean} |
|
* @throws {Error} |
|
*/ |
|
function assertLayerMatch(item1, item2) { |
|
if (item1.layer === item2.layer) { |
|
return false; |
|
} |
|
|
|
throw new Error('different'); |
|
} |
|
|
|
/** |
|
* Compare the parent.*_id properties if they exist. |
|
* Returns false if the objects are the same, and throws |
|
* an exception with the message 'different' if not. |
|
* |
|
* @param {object} item1 |
|
* @param {object} item2 |
|
* @returns {boolean} |
|
* @throws {Error} |
|
*/ |
|
function assertParentHierarchyMatch(item1, item2) { |
|
// if neither object has parent, assume same |
|
if (!item1.hasOwnProperty('parent') && !item2.hasOwnProperty('parent')) { |
|
return false; |
|
} |
|
|
|
// if both have parent, do the rest of the checking |
|
if (item1.hasOwnProperty('parent') && item2.hasOwnProperty('parent')) { |
|
placeTypes.forEach(function (placeType) { |
|
// don't consider its own id |
|
if (placeType === item1.layer) { |
|
return; |
|
} |
|
propMatch(item1.parent, item2.parent, placeType + '_id'); |
|
}); |
|
return false; |
|
} |
|
|
|
// if one has parent and the other doesn't consider different |
|
throw new Error('different'); |
|
} |
|
|
|
/** |
|
* Compare the name.* properties if they exist. |
|
* Returns false if the objects are the same, and throws |
|
* an exception with the message 'different' if not. |
|
* |
|
* @param {object} item1 |
|
* @param {object} item2 |
|
* @returns {boolean} |
|
* @throws {Error} |
|
*/ |
|
function assertNameMatch(item1, item2) { |
|
if (item1.hasOwnProperty('name') && item2.hasOwnProperty('name')) { |
|
for (var lang in item1.name) { |
|
if(item2.name.hasOwnProperty(lang) || lang === 'default') { |
|
// do not consider absence of an additional name as a difference |
|
propMatch(item1.name, item2.name, lang); |
|
} |
|
} |
|
} |
|
else { |
|
propMatch(item1, item2, 'name'); |
|
} |
|
} |
|
|
|
/** |
|
* Compare the address_parts properties if they exist. |
|
* Returns false if the objects are the same, and throws |
|
* an exception with the message 'different' if not. |
|
* |
|
* @param {object} item1 |
|
* @param {object} item2 |
|
* @returns {boolean} |
|
* @throws {Error} |
|
*/ |
|
function assertAddressMatch(item1, item2) { |
|
// if neither record has address, assume same |
|
if (!item1.hasOwnProperty('address_parts') && !item2.hasOwnProperty('address_parts')) { |
|
return false; |
|
} |
|
|
|
// if both have address, check parts |
|
if (item1.hasOwnProperty('address_parts') && item2.hasOwnProperty('address_parts')) { |
|
propMatch(item1.address_parts, item2.address_parts, 'number'); |
|
propMatch(item1.address_parts, item2.address_parts, 'street'); |
|
|
|
// only compare zip if both records have it, otherwise just ignore and assume it's the same |
|
// since by this time we've already compared parent hierarchies |
|
if (item1.address_parts.hasOwnProperty('zip') && item2.address_parts.hasOwnProperty('zip')) { |
|
propMatch(item1.address_parts, item2.address_parts, 'zip'); |
|
} |
|
|
|
// only compare unit if both records have it, otherwise just ignore and assume it's the same |
|
if (item1.address_parts.hasOwnProperty('unit') && item2.address_parts.hasOwnProperty('unit')) { |
|
propMatch(item1.address_parts, item2.address_parts, 'unit'); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// one has address and the other doesn't, different! |
|
throw new Error('different'); |
|
} |
|
|
|
/** |
|
* Compare the two records and return true if they differ and false if same. |
|
* |
|
* @param {object} item1 |
|
* @param {object} item2 |
|
* @returns {boolean} |
|
* @throws {Error} |
|
*/ |
|
function isDifferent(item1, item2) { |
|
try { |
|
assertLayerMatch(item1, item2); |
|
assertParentHierarchyMatch(item1, item2); |
|
assertNameMatch(item1, item2); |
|
assertAddressMatch(item1, item2); |
|
} |
|
catch (err) { |
|
if (err.message === 'different') { |
|
return true; |
|
} |
|
throw err; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
/** |
|
* Throw exception if properties are different |
|
* |
|
* @param {object} item1 |
|
* @param {object} item2 |
|
* @param {string} prop |
|
* @throws {Error} |
|
*/ |
|
function propMatch(item1, item2, prop) { |
|
var prop1 = item1[prop]; |
|
var prop2 = item2[prop]; |
|
|
|
// in the case the property is an array (currently only in parent schema) |
|
// simply take the 1st item. this will change in the near future to support multiple hierarchies |
|
if (_.isArray(prop1)) { prop1 = prop1[0]; } |
|
if (_.isArray(prop2)) { prop2 = prop2[0]; } |
|
|
|
if (normalizeString(prop1) !== normalizeString(prop2)) { |
|
throw new Error('different'); |
|
} |
|
} |
|
|
|
/** |
|
* Remove punctuation and lowercase |
|
* |
|
* @param {string} str |
|
* @returns {string} |
|
*/ |
|
function normalizeString(str) { |
|
if (!_.isString(str)) { |
|
return str; |
|
} |
|
|
|
if (_.isEmpty(str)) { |
|
return ''; |
|
} |
|
|
|
return str.toLowerCase().split(/[ ,-]+/).join(' '); |
|
} |
|
|
|
module.exports.isDifferent = isDifferent; |