@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
164 lines (155 loc) • 5.52 kB
text/typescript
import { RootDecoder } from './serde'
import { Link, RootIndex, BlockIndex, ContentDiff } from './types'
import { chunkyStore } from '@dstanesc/store-chunky-bytes'
import { LinkCodec } from './codecs'
import { BlockStore } from './block-store'
interface BlockIndexFactory {
buildRootIndex: (
root: Link
) => Promise<{ root: Link; index: RootIndex; indexBuffer: Uint8Array }>
buildChunkyIndex: (root: Link) => Promise<BlockIndex>
diffRootIndex: ({
currentRoot,
otherRoot,
}: {
currentRoot: Link
otherRoot: Link
}) => Promise<ContentDiff>
diffChunkyIndex: ({
currentIndex,
otherIndex,
}: {
currentIndex: BlockIndex
otherIndex: BlockIndex
}) => Promise<ContentDiff>
}
const blockIndexFactory = ({
linkCodec,
blockStore,
}: {
linkCodec: LinkCodec
blockStore: BlockStore
}): BlockIndexFactory => {
const {
encode: linkEncode,
decode: linkDecode,
encodeString: encodeLinkString,
parseString: parseLinkString,
}: LinkCodec = linkCodec
const { put: blockPut, get: blockGet } = blockStore
const { readIndex } = chunkyStore()
const buildChunkyIndex = async (root: Link): Promise<BlockIndex> => {
return await readIndex(root, blockGet, linkDecode)
}
const buildRootIndex = async (
root: Link
): Promise<{ root: Link; index: RootIndex; indexBuffer: Uint8Array }> => {
const bytes = await blockGet(root)
const rootStruct = new RootDecoder(bytes, linkDecode).read()
const vertexIndex = await buildChunkyIndex(rootStruct.vertexRoot)
const edgeIndex = await buildChunkyIndex(rootStruct.edgeRoot)
const propIndex = await buildChunkyIndex(rootStruct.propRoot)
const valueIndex = await buildChunkyIndex(rootStruct.valueRoot)
const indexIndex = await buildChunkyIndex(rootStruct.indexRoot)
const index = Object.assign(
{ vertexIndex, edgeIndex, propIndex, valueIndex, indexIndex },
rootStruct
)
return { root, index, indexBuffer: bytes }
}
const diffRootIndex = async ({
currentRoot,
otherRoot,
}: {
currentRoot: Link
otherRoot: Link
}): Promise<ContentDiff> => {
const currentRootIndex = await buildRootIndex(currentRoot)
const otherRootIndex = await buildRootIndex(otherRoot)
const addedLinks: Link[] = []
const removedLinks: Link[] = []
const {
vertexIndex: currentVertexIndex,
edgeIndex: currentEdgeIndex,
propIndex: currentPropIndex,
valueIndex: currentValueIndex,
indexIndex: currentIndexIndex,
} = currentRootIndex.index
const {
vertexIndex: otherVertexIndex,
edgeIndex: otherEdgeIndex,
propIndex: otherPropIndex,
valueIndex: otherValueIndex,
indexIndex: otherIndexIndex,
} = otherRootIndex.index
const vertexDiff = await diffChunkyIndex({
currentIndex: currentVertexIndex,
otherIndex: otherVertexIndex,
})
const edgeDiff = await diffChunkyIndex({
currentIndex: currentEdgeIndex,
otherIndex: otherEdgeIndex,
})
const propDiff = await diffChunkyIndex({
currentIndex: currentPropIndex,
otherIndex: otherPropIndex,
})
const valueDiff = await diffChunkyIndex({
currentIndex: currentValueIndex,
otherIndex: otherValueIndex,
})
const indexDiff = await diffChunkyIndex({
currentIndex: currentIndexIndex,
otherIndex: otherIndexIndex,
})
addedLinks.push(...vertexDiff.added)
addedLinks.push(...edgeDiff.added)
addedLinks.push(...propDiff.added)
addedLinks.push(...valueDiff.added)
addedLinks.push(...indexDiff.added)
removedLinks.push(...vertexDiff.removed)
removedLinks.push(...edgeDiff.removed)
removedLinks.push(...propDiff.removed)
removedLinks.push(...valueDiff.removed)
removedLinks.push(...indexDiff.removed)
return { added: addedLinks, removed: removedLinks }
}
const diffChunkyIndex = async ({
currentIndex,
otherIndex,
}: {
currentIndex: BlockIndex
otherIndex: BlockIndex
}): Promise<ContentDiff> => {
const addedLinks: Link[] = []
const removedLinks: Link[] = []
const currentLinks = new Set(
Array.from(currentIndex.indexStruct.startOffsets.values(), (cid) =>
linkCodec.encodeString(cid)
)
)
const otherLinks = new Set(
Array.from(otherIndex.indexStruct.startOffsets.values(), (cid) =>
linkCodec.encodeString(cid)
)
)
for (const cidString of otherLinks) {
if (!currentLinks.has(cidString)) {
addedLinks.push(linkCodec.parseString(cidString))
}
}
for (const cidString of currentLinks) {
if (!otherLinks.has(cidString)) {
removedLinks.push(linkCodec.parseString(cidString))
}
}
return { added: addedLinks, removed: removedLinks }
}
return {
buildRootIndex,
buildChunkyIndex,
diffRootIndex,
diffChunkyIndex,
}
}
export { blockIndexFactory, BlockIndexFactory }