@ssb-graphql/whakapapa
Version:
GraphQL types and resolvers for the ssb-whakapapa plugin
105 lines (86 loc) • 3.86 kB
JavaScript
const { isMsg } = require('ssb-ref')
const pull = require('pull-stream')
const paraMap = require('pull-paramap')
const { promisify: p } = require('util')
// NOTE 2021-04-21 mix
// this was extracted from getLinks as a specific case where you want to find a link record
// when you know it's two end points
// TODO 2021-11-23 cherese
// this code needs to be split up and refactored as its handling multiple things including:
// - getting parent-child links
// - getting partner links
module.exports = function GetWhakapapaLink (sbot, { getProfile }) {
if (typeof getProfile !== 'function') throw new Error('the getter provided was not a function')
function getLinks ({ parentId, childId, type }, cb) {
if (!parentId || !childId) {
return cb(new Error('get-whakapapa-link expects both a parentId AND childId'))
}
sbot.whakapapa.link.getLinksOfType(parentId, type, (err, links) => {
// NOTE link.id is (questionably) defind asthe end of the link that is NOT the parentId
// i.e. the childId
if (err) return cb(err)
const outputIdToLink = {}
pull(
pull.values(links.childLinks),
pull.filter(link => link.tombstone === null && link.id === childId),
pull.unique(link => link.id),
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...)
getProfile(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,
profile: output
// could include link author + recps here later
})),
pull.collect((err, links) => {
if (err) cb(err)
else cb(null, links)
})
)
})
}
return function getWhakapapaLink ({ parent, child, type, isExactLink = true }, cb) {
if (cb === undefined) return p(getWhakapapaLink)({ parent, child, type, isExactLink })
if (!isMsg(parent) || !isMsg(child)) {
return cb(new Error('parent or child query expected %msgId, got ' + parent))
}
getLinks({ parentId: parent, childId: child, type }, (err, links) => {
if (err) return cb(err)
const finalise = (links, parent, child) => links.map(link => {
delete link.id
delete link.profile
link.type = type
link.parent = parent
link.child = child
return link
})[0] // decide which link to return here...
if (links && links.length) return cb(null, finalise(links, parent, child))
// NOTE: if isExactLink = true, then it means the parent and child link is a direct query
// if isExactLink = false, means the link could be either { child: childId, parent: parentId } OR { child: parentId, parent: childId }
if (type !== 'link/profile-profile/partner' && isExactLink) return cb(null, null)
// if we are querying for partners and didnt find any, switch the parent/child and
// see if we can find a link that way
getLinks({ parentId: child, childId: parent, type }, (err, links) => {
if (err) return cb(err)
if (links && links.length === 0) return cb(null, null)
cb(null, finalise(links, child, parent))
})
})
}
}