@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
JavaScript
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