UNPKG

@orbitdb/ordered-keyvalue-db

Version:

Ordered keyvalue database type for orbit-db.

138 lines 4.42 kB
import { Database, } from "@orbitdb/core"; import itAll from "it-all"; import { getScalePosition } from "./utils.js"; const type = "ordered-keyvalue"; const OrderedKeyValue = () => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, }) => { const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, }); const { put, set, del, move, get, iterator, all } = OrderedKeyValueApi({ database, }); return { ...database, type, put, set, del, move, get, iterator, all, }; }; OrderedKeyValue.type = type; export const OrderedKeyValueApi = ({ database, }) => { const put = async (key, value, position) => { // Somewhat inefficient, I suppose, but we need to know which entries are already present. const entries = await itAll(iterator()); // Avoid overwriting existing position; default to end of list (findIndex gives -1) let scaledPosition = undefined; if (position === undefined) { scaledPosition = entries.find((e) => e.key === key)?.position; } if (scaledPosition === undefined) { scaledPosition = await getScalePosition({ entries, key, position: position ?? -1, }); } const entryValue = { value, position: scaledPosition, }; return database.addOperation({ op: "PUT", key, value: entryValue }); }; const move = async (key, position) => { // Somewhat inefficient, I suppose, but we need to know which entries are already present. const entries = await itAll(iterator()); position = await getScalePosition({ entries, key, position }); await database.addOperation({ op: "MOVE", key, value: position }); }; const del = async (key) => { return database.addOperation({ op: "DEL", key, value: null }); }; const get = async (key) => { for await (const entry of database.log.traverse()) { const { op, key: k, value } = entry.payload; if (op === "PUT" && k === key) { return value.value; } else if (op === "DEL" && k === key) { return undefined; } } return undefined; }; const iterator = async function* ({ amount, } = {}) { let count = 0; // `true` indicates a `PUT` operation; `number` indicates a `MOVE` operation const keys = {}; for await (const entry of database.log.traverse()) { const { op, key, value } = entry.payload; if (typeof key !== "string") continue; if (op === "PUT" && keys[key] !== true) { const hash = entry.hash; const putValue = value; const position = typeof keys[key] === "number" ? keys[key] : putValue.position; keys[key] = true; count++; yield { key, value: putValue.value, position, hash, }; } else if (op === "MOVE" && !keys[key]) { keys[key] = value; } else if (op === "DEL") { keys[key] = true; } if (amount !== undefined && count >= amount) { break; } } }; const all = async () => { const entries = []; for await (const entry of iterator()) { entries.push(entry); } return entries .sort((a, b) => a.position - b.position) .map((e) => ({ key: e.key, value: e.value, hash: e.hash, })); }; return { get, set: put, // Alias for put() put, move, del, iterator, all, }; }; export default OrderedKeyValue; //# sourceMappingURL=ordered-keyvalue.js.map