@orbitdb/ordered-keyvalue-db
Version:
Ordered keyvalue database type for orbit-db.
125 lines • 4.04 kB
JavaScript
import { Database, } from "@orbitdb/core";
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 { addOperation, log } = database;
const put = async (key, value, position) => {
const entryValue = {
value,
};
if (position !== undefined) {
entryValue.position = position;
}
return addOperation({ op: "PUT", key, value: entryValue });
};
const move = async (key, position) => {
return addOperation({ op: "MOVE", key, value: position });
};
const del = async (key) => {
return addOperation({ op: "DEL", key, value: null });
};
const get = async (key) => {
for await (const entry of log.traverse()) {
const { op, key: k, value } = entry.payload;
if (op === "PUT" && k === key) {
return value;
}
else if (op === "DEL" && k === key) {
return undefined;
}
}
return undefined;
};
const iterator = async function* ({ amount, } = {}) {
let count = 0;
const orderedLogEntries = [];
for await (const entry of log.traverse()) {
orderedLogEntries.unshift(entry);
}
let finalEntries = [];
for (const entry of orderedLogEntries) {
const { op, key, value } = entry.payload;
if (!key)
return;
if (op === "PUT") {
finalEntries = finalEntries.filter((e) => e.key !== key);
const putValue = value;
const hash = entry.hash;
const position = putValue.position !== undefined ? putValue.position : -1;
finalEntries.push({
key,
value: putValue.value,
position,
hash,
});
count++;
}
else if (op === "MOVE") {
const existingEntry = finalEntries.find((e) => e.key === key);
if (existingEntry) {
existingEntry.position = value;
finalEntries = [
...finalEntries.filter((e) => e.key !== key),
existingEntry,
];
}
}
else if (op === "DEL") {
finalEntries = finalEntries.filter((e) => e.key !== key);
}
if (amount !== undefined && count >= amount) {
break;
}
}
// This is memory inefficient, but I haven't been able to think of a more elegant solution
for (const entry of finalEntries) {
yield entry;
}
};
const all = async () => {
const entries = [];
for await (const entry of iterator()) {
entries.push(entry);
}
const values = [];
for (const entry of entries) {
const position = entry.position >= 0
? entry.position
: entries.length + entry.position + 1;
values.splice(position, 0, {
key: entry.key,
value: entry.value,
hash: entry.hash,
});
}
return values;
};
return {
...database,
type,
put,
set: put, // Alias for put()
del,
move,
get,
iterator,
all,
};
};
OrderedKeyValue.type = type;
export default OrderedKeyValue;
//# sourceMappingURL=ordered-keyvalue.js.map