p2p-db-osm
Version:
API for p2p-db adding OpenStreetMap data types and querying.
156 lines (128 loc) • 4.17 kB
JavaScript
module.exports = checkElement
// OsmElement -> [Error]
function checkElement (element) {
var res = checkNewElement(element)
switch (element.type) {
case 'node': return res.concat(checkNewNode(element))
case 'way': return res.concat(checkNewWay(element))
case 'relation': return res.concat(checkNewRelation(element))
case 'changeset': return res.concat(checkNewChangeset(element))
default: return res.concat([new Error('unknown value for "type" field')])
}
}
function checkNewElement (elm) {
var res = []
if (!elm.type) {
res.push(new Error('missing "type" field'))
}
if (typeof elm.type !== 'string') {
res.push(new Error('"type" field must be a string'))
}
if (elm.type !== 'changeset') {
if (!elm.changeset) {
res.push(new Error('missing "changeset" field'))
}
if (typeof elm.changeset !== 'string') {
res.push(new Error('"changeset" field must be a string'))
}
// TODO: check that ensures changeset exists
}
if (elm.timestamp && !/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\dZ$/.test(elm.timestamp)) {
res.push(new Error('"timestamp" must be in String.prototype.toUTCString format'))
}
return res
}
// OsmNode -> [Error]
function checkNewNode (node) {
var res = []
res = res.concat(checkNewElement(node))
if (!node.lat) {
res.push(new Error('missing "lat" field'))
}
if (typeof node.lat !== 'string') {
res.push(new Error('"lat" field must be string'))
}
if (Number(node.lat) < -90 || Number(node.lat) > 90) {
res.push(new Error('"lat" field must be between -90 and 90'))
}
if (node.tags && typeof node.tags !== 'object') {
res.push(new Error('"tags" field must be an object'))
}
if (!node.lon) {
res.push(new Error('missing "lon" field'))
}
if (typeof node.lon !== 'string') {
res.push(new Error('"lon" field must be string'))
}
if (Number(node.lon) < -180 || Number(node.lon) > 180) {
res.push(new Error('"lon" field must be between -180 and 180'))
}
return res
}
// OsmWay -> [Error]
function checkNewWay (way) {
var res = []
res = res.concat(checkNewElement(way))
if (!way.refs) {
res.push(new Error('missing "refs" field'))
}
if (!Array.isArray(way.refs)) {
res.push(new Error('"refs" field must be an array'))
}
if (way.refs && way.refs.length < 3) {
res.push(new Error('"refs" field must have > 2 nodes'))
}
// TODO: check that all refs exist in the db
return res
}
// OsmRelation -> [Error]
function checkNewRelation (rel) {
var res = []
res = res.concat(checkNewElement(rel))
if (!rel.tags) {
res.push(new Error('missing "tags" field'))
}
if (rel.tags && typeof rel.tags !== 'object') {
res.push(new Error('"tags" field must be an object'))
}
if (rel.tags && Object.keys(rel.tags).length < 1) {
res.push(new Error('"tags" field must have >= 1 members'))
}
if (!rel.members) {
res.push(new Error('missing "members" field'))
}
if (!Array.isArray(rel.members)) {
res.push(new Error('"members" field must be an array'))
}
if (rel.members && Array.isArray(rel.members)) {
rel.members.forEach(function (member, idx) {
if (!member.type) {
res.push(new Error('"members[' + idx + ']" missing "type" field'))
}
if (typeof member.type !== 'string') {
res.push(new Error('"members[' + idx + '].type" must be a string'))
}
if (!isValidRelationMemberType(member.type)) {
res.push(new Error('"members[' + idx + '].type" must be one of node, way, relation'))
}
if (!member.id) {
res.push(new Error('"members[' + idx + ']" missing "id" field'))
}
if (typeof member.id !== 'string') {
res.push(new Error('"members[' + idx + '].id" must be a string'))
}
// TODO(noffle): check for 'role'; if set it must be a string
})
}
// TODO: check that all members exist in the db
return res
}
// String -> Boolean
function isValidRelationMemberType (type) {
return ['node', 'way', 'relation'].indexOf(type) !== -1
}
// OsmChangeset -> [Error]
function checkNewChangeset (changes) {
var res = []
return res
}