osm-p2p-server
Version:
Peer-to-peer OpenStreetMap API v0.6 Server
115 lines (103 loc) • 2.92 kB
JavaScript
var collect = require('collect-stream')
var pumpify = require('pumpify')
var mapStream = require('through2-map')
var collectTransform = require('collect-transform-stream')
var defork = require('osm-p2p-defork')
var through = require('through2')
var checkRefExist = require('../lib/check_ref_ex.js')
module.exports = function (osm) {
return function getMap (bbox, opts, cb) {
if (typeof opts === 'function') {
cb = opts
opts = {}
}
opts.observations = true
opts.forks = opts.forks || false
opts.order = 'type'
// For now, filter deletions (until downstream can handle them).
//
// This also involves removing references to deleted nodes from ways (iD
// handles this poorly). This relies on the reordering step.
var nodesSeen = {}
var deletionFilter = through.obj(function (chunk, enc, next) {
if (!chunk.deleted) {
if (chunk && chunk.type === 'node') {
nodesSeen[chunk.id] = true
} else if (chunk && chunk.type === 'way') {
chunk.refs = (chunk.refs || []).filter(function (id) {
return !!nodesSeen[id]
})
}
}
if (!chunk.deleted) next(null, chunk)
else next()
})
var pipeline = [
osm.queryStream ? osm.queryStream(bbox, opts) : osm.query(bbox, opts),
orderByType(),
deletionFilter,
checkRefExist(osm),
mapStream.obj(refs2nodes)
]
// If forks ought to be filtered out, add another step to the pipeline that
// does so.
if (!opts.forks) {
pipeline.push(deforkStream())
}
var queryStreamJson = pumpify.obj.apply(this, pipeline)
if (cb) {
collect(queryStreamJson, function (err, elements) {
if (err) return cb(err)
cb(null, elements)
})
} else {
return queryStreamJson
}
}
}
function deforkStream () {
return collectTransform(function (res) {
return defork(res).sort(cmpType)
})
}
var typeOrder = { node: 0, way: 1, relation: 2 }
function cmpType (a, b) {
return typeOrder[a.type] - typeOrder[b.type]
}
function orderByType () {
var queue = { ways: [], relations: [] }
return through.obj(write, end)
function write (chunk, enc, next) {
if (chunk && chunk && chunk.type === 'way') {
queue.ways.push(chunk)
next()
} else if (chunk && chunk.type === 'relation') {
queue.relations.push(chunk)
next()
} else {
next(null, chunk)
}
}
function end (next) {
var self = this
queue.ways.forEach(function (way) {
self.push(way)
})
queue.relations.forEach(function (rel) {
self.push(rel)
})
next()
}
}
function refs2nodes (doc) {
var element = { id: doc.id }
for (var prop in doc) {
if (!doc.hasOwnProperty(prop)) continue
if (prop === 'refs') {
element.nodes = doc.refs
} else {
element[prop] = doc[prop]
}
}
return element
}