UNPKG

@ssb-graphql/whakapapa

Version:

GraphQL types and resolvers for the ssb-whakapapa plugin

102 lines (84 loc) 3.29 kB
const pull = require('pull-stream') const paraMap = require('pull-paramap') const { promisify: p } = require('util') module.exports = function GetLinks (sbot, cache) { return function getLinks ({ type, parentId, childId, getter }, cb) { if (cb === undefined) return p(getLinks)({ type, parentId, childId, getter }) if (!type) return cb(new Error(`get-links expects a type, got ${type}`)) if ((!parentId && !childId)) { return cb(new Error('get-links expects either a parentId, childId or both')) } else if (parentId && childId && (parentId !== childId)) { return cb(new Error('get-links expects parentId and childId to be equal when they are both given')) } if (getter && typeof getter !== 'function') return cb(new Error('the getter provided was not a function')) readLinks(type, parentId, childId, (err, links) => { if (err) return cb(err) pull( pull.values(links), pull.filter(link => link.tombstone === null), pull.unique(link => link.id), getterMap(getter), pull.collect((err, links) => { if (err) return cb(err) cb(null, links) }) ) }) function getterMap (getter) { if (!getter) return null const outputIdToLink = {} // we assume that if parentId is included we want to find out about its children // and if childId is included, we want to know about the parents const types = getTypes(type) const outputType = parentId ? types.child : types.parent return pull( pull.map(link => { outputIdToLink[link.id] = link // keep a copy of this link return link.id // map links to id }), paraMap((key, cb) => { // use the getter to fetch the full object of the type (e.g. story, profile, artefact, etc...) getter(key, (err, output) => { if (err) { console.error(`Unable to get record ${key}, error:`) console.error(err) return cb(null, null) // HACK : don't kill all record getting if just one fails } cb(null, output) }) }, 4), pull.filter(Boolean), // filter out null values pull.filter(output => output.tombstone === null), // filter out tombstoned items pull.map(output => ({ ...outputIdToLink[output.id], linkId: outputIdToLink[output.id].linkId, [outputType]: output })) ) } } function readLinks (type, parent, child, cb) { const cached = cache.get(type, { parent, child }) if (cached) return cb(null, cached) // use either for the id const id = parent || child sbot.whakapapa.link.getLinksOfType(id, type, (err, links) => { if (err) return cb(err) if (parent) cache.setParent(type, parent, links.childLinks) if (child) cache.setChild(type, child, links.parentLinks) cb(null, cache.get(type, { parent, child })) }) } } function getTypes (type) { const types = type .replace(/^link\//, '') .replace(/\/.*$/, '') .split('-') if (types.length !== 2) throw new Error(`tried to resolve parent/child of ${type} but failed!`) return { parent: types[0], child: types[1] } }