UNPKG

@dstanesc/o-o-o-o-o-o-o

Version:

O-O-O-O-O-O-O is a collection of content addressed persistent data structures

360 lines 15.3 kB
import { VertexEncoder, VertexDecoder, EdgeEncoder, EdgeDecoder, PropEncoder, PropDecoder, RootEncoder, OFFSET_INCREMENTS, IndexDecoder, IndexEncoder, PropValueEncoder, PropValueDecoder, } from './serde'; import { chunkyStore } from '@dstanesc/store-chunky-bytes'; import { graphPackerFactory } from './graph-packer'; const { create, read, append, update, bulk, remove, readIndex } = chunkyStore(); const graphStore = ({ chunk, linkCodec, valueCodec, blockStore, }) => { const { encode: linkEncode, decode: linkDecode } = linkCodec; const { encode: valueEncode, decode: valueDecode } = valueCodec; const { put: blockPut, get: blockGet } = blockStore; const vertexGet = async ({ root, index }, offset) => { const { vertexRoot, vertexIndex } = index; const bytes = await read(offset, OFFSET_INCREMENTS.VERTEX_INCREMENT, { root: vertexRoot, index: vertexIndex, decode: linkDecode, get: blockGet, }); return new VertexDecoder(bytes).readVertex(); }; const vertexRange = async ({ root, index }, offset, vertexCount) => { const { vertexRoot, vertexIndex } = index; const bytes = await read(offset, vertexCount * OFFSET_INCREMENTS.VERTEX_INCREMENT, { root: vertexRoot, index: vertexIndex, decode: linkDecode, get: blockGet, }); return new VertexDecoder(bytes).read(); }; const edgeGet = async ({ root, index }, offset) => { const { edgeRoot, edgeIndex } = index; const bytes = await read(offset, OFFSET_INCREMENTS.EDGE_INCREMENT, { root: edgeRoot, index: edgeIndex, decode: linkDecode, get: blockGet, }); return new EdgeDecoder(bytes).readEdge(); }; const edgeRange = async ({ root, index }, offset, edgeCount) => { const { edgeRoot, edgeIndex } = index; const bytes = await read(offset, edgeCount * OFFSET_INCREMENTS.EDGE_INCREMENT, { root: edgeRoot, index: edgeIndex, decode: linkDecode, get: blockGet, }); return new EdgeDecoder(bytes).read(); }; const propGet = async ({ root, index }, offset) => { const { propRoot, propIndex } = index; const bytes = await read(offset, OFFSET_INCREMENTS.PROP_INCREMENT, { root: propRoot, index: propIndex, decode: linkDecode, get: blockGet, }); return new PropDecoder(bytes, (ref) => valueGet({ root, index }, ref)).readProp(); }; const propRange = async ({ root, index }, offset, propCount) => { const { propRoot, propIndex } = index; const bytes = await read(offset, propCount * OFFSET_INCREMENTS.PROP_INCREMENT, { root: propRoot, index: propIndex, decode: linkDecode, get: blockGet, }); return new PropDecoder(bytes, (ref) => valueGet({ root, index }, ref)).read(); }; const valueGet = async ({ root, index }, { propRef, ref, length }) => { const { valueRoot, valueIndex } = index; const bytes = await read(ref, length, { root: valueRoot, index: valueIndex, decode: linkDecode, get: blockGet, }); return new PropValueDecoder(bytes, valueDecode).readValue({ propRef, ref, length, }); }; const indexGet = async ({ root, index }, offset) => { const { indexRoot, indexIndex } = index; const bytes = await read(offset, OFFSET_INCREMENTS.INDEX_INCREMENT, { root: indexRoot, index: indexIndex, decode: linkDecode, get: blockGet, }); return new IndexDecoder(bytes, linkDecode).readIndex(); }; const verticesAll = async ({ root, index, }) => { const { vertexRoot, vertexOffset, vertexIndex } = index; // TODO Read chunks for scalability const bytes = await read(0, vertexOffset, { root: vertexRoot, index: vertexIndex, decode: linkDecode, get: blockGet, }); return new VertexDecoder(bytes).read(); }; const edgesAll = async ({ root, index, }) => { const { edgeRoot, edgeOffset, edgeIndex } = index; // TODO Read chunks for scalability const bytes = await read(0, edgeOffset, { root: edgeRoot, index: edgeIndex, decode: linkDecode, get: blockGet, }); return new EdgeDecoder(bytes).read(); }; const propsAll = async ({ root, index, }) => { const { propRoot, propOffset, propIndex } = index; // TODO Read chunks for scalability const bytes = await read(0, propOffset, { root: propRoot, index: propIndex, decode: linkDecode, get: blockGet, }); return new PropDecoder(bytes, (ref) => valueGet({ root, index }, ref)).read(); }; const offsetsGet = async ({ root, index, }) => { const { vertexOffset, edgeOffset, propOffset, indexOffset } = index; return { vertexOffset, edgeOffset, propOffset, indexOffset }; }; const verticesCreate = async (vertices) => { const array = Array.from(vertices.values()); const buf = new VertexEncoder(array).write(); const { root, index, blocks } = await create({ buf, chunk, encode: linkEncode, }); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const verticesBulk = async ({ root: rootOrig, index: indexOrig }, { added, updated, }) => { const appendBuffer = new VertexEncoder(Array.from(added.values())).write(); const updateRequests = []; for (const [offset, vertex] of updated) { const updateBuffer = new VertexEncoder([vertex]).write(); updateRequests.push({ updateBuffer, updateStartOffset: offset }); } const { root, index, blocks } = await bulk({ root: rootOrig, decode: linkDecode, get: blockGet, put: blockPut, }, { chunk, encode: linkEncode }, appendBuffer, updateRequests); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const edgesCreate = async (edges) => { const array = Array.from(edges.values()); const buf = new EdgeEncoder(array).write(); const { root, index, blocks } = await create({ buf, chunk, encode: linkEncode, }); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const edgesBulk = async ({ root: rootOrig, index: indexOrig }, { added, updated, }) => { const appendBuffer = new EdgeEncoder(Array.from(added.values())).write(); const updateRequests = []; for (const [offset, edge] of updated) { const updateBuffer = new EdgeEncoder([edge]).write(); updateRequests.push({ updateBuffer, updateStartOffset: offset }); } const { root, index, blocks } = await bulk({ root: rootOrig, decode: linkDecode, get: blockGet, put: blockPut, }, { chunk, encode: linkEncode }, appendBuffer, updateRequests); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const propsCreate = async (props, refs) => { const array = Array.from(props.values()); const buf = await new PropEncoder(array, refs).write(); const { root, index, blocks } = await create({ buf, chunk, encode: linkEncode, }); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const propsBulk = async ({ root: rootOrig, index: indexOrig }, { added, updated, }, refs) => { const appendBuffer = await new PropEncoder(Array.from(added.values()), refs).write(); const updateRequests = []; for (const [offset, prop] of updated) { const updateBuffer = await new PropEncoder([prop], refs).write(); updateRequests.push({ updateBuffer, updateStartOffset: offset }); } const { root, index, blocks } = await bulk({ root: rootOrig, decode: linkDecode, get: blockGet, put: blockPut, }, { chunk, encode: linkEncode }, appendBuffer, updateRequests); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const propsValueCreate = async (props) => { const array = Array.from(props.values()); const { buf, refs } = new PropValueEncoder(0, array, valueCodec.encode).write(); const { root, index, blocks } = await create({ buf, chunk, encode: linkEncode, }); for (const block of blocks) await blockPut(block); return { root, index, blocks, refs }; }; const propsValueAppend = async ({ root: rootOrig, index: indexOrig }, { added, updated, }) => { if (updated.size > 0) throw new Error('property value update not implemented'); const lastOffset = indexOrig.indexStruct.byteArraySize; const { buf, refs } = new PropValueEncoder(lastOffset, Array.from(added.values()), valueCodec.encode).write(); const { root, index, blocks } = await append({ root: rootOrig, index: indexOrig, decode: linkDecode, get: blockGet, }, { buf, chunk, encode: linkEncode }); for (const block of blocks) await blockPut(block); return { root, index, blocks, refs }; }; const indicesCreate = async (indices) => { const array = Array.from(indices.values()); const buf = await new IndexEncoder(array).write(); const { root, index, blocks } = await create({ buf, chunk, encode: linkEncode, }); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const indicesBulk = async ({ root: rootOrig, index: indexOrig }, { added, updated, }) => { const appendBuffer = await new IndexEncoder(Array.from(added.values())).write(); const updateRequests = []; for (const [offset, index] of updated) { const updateBuffer = await new IndexEncoder([index]).write(); updateRequests.push({ updateBuffer, updateStartOffset: offset }); } const { root, index, blocks } = await bulk({ root: rootOrig, decode: linkDecode, get: blockGet, put: blockPut, }, { chunk, encode: linkEncode }, appendBuffer, updateRequests); for (const block of blocks) await blockPut(block); return { root, index, blocks }; }; const commit = async ({ root: rootOrig, index: indexOrig }, { vertices, edges, props, indices, }) => { const { root: vertexRootLink, index: vertexIndex, blocks: vertexBlocks, } = rootOrig === undefined ? await verticesCreate(vertices.added) : await verticesBulk({ root: indexOrig.vertexRoot, index: indexOrig.vertexIndex }, vertices); const { root: edgeRootLink, index: edgeIndex, blocks: edgeBlocks, } = rootOrig === undefined ? await edgesCreate(edges.added) : await edgesBulk({ root: indexOrig.edgeRoot, index: indexOrig.edgeIndex }, edges); const { root: valueRootLink, index: valueIndex, blocks: valueBlocks, refs: valueRefs, } = rootOrig === undefined ? await propsValueCreate(props.added) : await propsValueAppend({ root: indexOrig.valueRoot, index: indexOrig.valueIndex, }, props); const { root: propRootLink, index: propIndex, blocks: propBlocks, } = rootOrig === undefined ? await propsCreate(props.added, valueRefs) : await propsBulk({ root: indexOrig.propRoot, index: indexOrig.propIndex }, props, valueRefs); const { root: indexRootLink, index: indexIndex, blocks: indexBlocks, } = rootOrig === undefined ? await indicesCreate(indices.added) : await indicesBulk({ root: indexOrig.indexRoot, index: indexOrig.indexIndex }, indices); const blocks = []; const rootStruct = { vertexRoot: vertexRootLink, vertexOffset: vertexIndex.indexStruct.byteArraySize, edgeRoot: edgeRootLink, edgeOffset: edgeIndex.indexStruct.byteArraySize, propRoot: propRootLink, propOffset: propIndex.indexStruct.byteArraySize, valueRoot: valueRootLink, valueOffset: valueIndex.indexStruct.byteArraySize, indexRoot: indexRootLink, indexOffset: indexIndex.indexStruct.byteArraySize, }; const rootBytes = new RootEncoder(rootStruct).write().content(); const rootAfter = await linkEncode(rootBytes); const rootAfterBlock = { cid: rootAfter, bytes: rootBytes }; await blockPut(rootAfterBlock); blocks.push(...vertexBlocks); blocks.push(...edgeBlocks); blocks.push(...propBlocks); blocks.push(...valueBlocks); blocks.push(...indexBlocks); blocks.push(rootAfterBlock); const indexAfter = { vertexRoot: vertexRootLink, vertexOffset: vertexIndex.indexStruct.byteArraySize, vertexIndex, edgeRoot: edgeRootLink, edgeOffset: edgeIndex.indexStruct.byteArraySize, edgeIndex, propRoot: propRootLink, propOffset: propIndex.indexStruct.byteArraySize, propIndex, valueRoot: valueRootLink, valueOffset: valueIndex.indexStruct.byteArraySize, valueIndex, indexRoot: indexRootLink, indexOffset: indexIndex.indexStruct.byteArraySize, indexIndex, }; return { root: rootAfter, index: indexAfter, blocks }; }; const packGraph = async (versionRoot) => { const { packGraph } = graphPackerFactory(linkCodec); return await packGraph(versionRoot, blockStore); }; const packComputed = async (versionRoot, vertexOffsetStart, vertexCount, graphDepth) => { const { packComputed: pack } = graphPackerFactory(linkCodec); return pack(versionRoot, vertexOffsetStart, vertexCount, graphDepth, blockStore, chunk, valueCodec); }; return { commit, vertexGet, vertexRange, edgeGet, edgeRange, propGet, propRange, indexGet, offsetsGet, verticesAll, edgesAll, propsAll, packGraph, packComputed, }; }; export { graphStore, graphStore as graphStoreFactory }; //# sourceMappingURL=graph-store.js.map