const deepcopy = require('deepcopy')
const OPTS = Symbol('options')
const CID = require('cids')
module.exports = class Graph {
constructor (ipfsDag, opts = {format: 'dag-cbor', hashAlg: 'sha2-256'}) {
this._dag = ipfsDag
this._opts = opts
}
setOptions (obj, opts) {
obj[OPTS] = opts
}
getOptions (obj) {
return obj[OPTS] || this._opts
}
async set (root, path, value) {
path = path.split('/')
value = {
'/': value
}
const last = path.pop()
let {value: foundVal, remainderPath: remainder} = await this._get(root, path)
if (remainder) {
for (const elem of remainder) {
foundVal = foundVal[elem] = {}
}
}
foundVal[last] = value
}
async _get (root, path) {
let edge
while (path.length) {
const name = path.shift()
edge = root[name]
if (edge && typeof edge !== 'string') {
const link = edge['/']
if (typeof link === 'string' || Buffer.isBuffer(link)) {
root = edge['/'] = (await this._dag.get(new CID(link))).value
} else if (link) {
root = link
} else {
root = edge
}
} else {
path.unshift(name)
return {value: root, remainderPath: path}
}
}
return {value: root}
}
async get (root, path) {
path = path.split('/')
const last = path.pop()
const {value} = await this._get(root, path)
return value[last]
}
async flush (root, opts) {
const awaiting = []
for (const name in root) {
const edge = root[name]
const link = edge['/']
if (typeof link === 'object') {
awaiting.push(this.flush(link).then(cid => {
edge['/'] = cid.toBaseEncodedString()
}))
}
}
await Promise.all(awaiting)
opts = opts || this.getOptions(root)
delete root[OPTS]
return this._dag.put(root, opts)
}
clone (root) {
return deepcopy(root)
}
}
|