@x5e/gink
Version:
an eventually consistent database
361 lines • 15.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const test_utils_1 = require("./test_utils");
const implementation_1 = require("../implementation");
const utils_1 = require("../implementation/utils");
it("push to a queue and peek", async function () {
// set up the objects
for (const store of [
new implementation_1.IndexedDbStore("list-test1", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const queue = await implementation_1.Sequence.create(instance);
await queue.push("dummy");
const muid = await queue.push("Hello, World!");
(0, utils_1.ensure)(muid.timestamp > 0);
const val = await queue.at(-1);
(0, utils_1.ensure)(val === "Hello, World!");
await store.close();
}
});
it("push and pop", async function () {
// set up the objects
for (const store of [
new implementation_1.IndexedDbStore("list-test2", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const list = await implementation_1.Sequence.create(instance);
await list.push("A");
await list.push("B");
await list.push("C");
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(), ["A", "B", "C"]));
const popped = await list.pop();
(0, utils_1.ensure)(popped === "C");
/*
for (const entry of await store.getAllEntries()) {
console.log(entry);
}
for (const exit of await store.getAllExits()) {
console.log(exit);
}
*/
const have = JSON.stringify(await list.toArray());
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(), ["A", "B"]), have);
const shifted = await list.shift();
(0, utils_1.ensure)(shifted === "A");
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(), ["B"]));
const dMuid = await list.push("D");
await list.push("E");
const poppedByMuid = await list.pop(dMuid);
(0, utils_1.ensure)(poppedByMuid === "D");
await list.push("F");
await list.push("G");
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(), ["B", "E", "F", "G"]));
const poppedByIndex = await list.pop(2);
(0, utils_1.ensure)(poppedByIndex === "F");
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(), ["B", "E", "G"]));
}
});
it("size and at", async function () {
// set up the objects
for (const store of [
new implementation_1.IndexedDbStore("list-test3", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const list = await implementation_1.Sequence.create(instance);
await list.push("A");
await list.push("B");
await list.push("C");
const size = await list.size();
(0, utils_1.ensure)(size === 3);
const atEnd = await list.at(-1);
(0, utils_1.ensure)(atEnd === "C");
const beginning = await list.at(0);
(0, utils_1.ensure)(beginning === "A");
const offEnd = await list.at(-4);
(0, utils_1.ensure)(offEnd === undefined);
const nearEnd = await list.at(-3);
(0, utils_1.ensure)(nearEnd === "A");
await list.pop();
const size2 = await list.size();
(0, utils_1.ensure)(size2 === 2);
const second = await list.at(1);
(0, utils_1.ensure)(second === "B");
const third = await list.at(3);
(0, utils_1.ensure)(third === undefined);
}
});
it("entries", async function () {
// set up the objects
for (const store of [
new implementation_1.IndexedDbStore("list-test4", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const list = await implementation_1.Sequence.create(instance);
await list.push("A");
await list.push("B");
await list.push("C");
const buffer = [];
for await (const [muid, contents] of list.entries()) {
const val = await list.pop(muid);
(0, utils_1.ensure)(val === contents, `val=${val}, contents=${contents}`);
buffer.push(contents);
}
(0, utils_1.ensure)((0, utils_1.matches)(buffer, ["A", "B", "C"]));
}
});
it("list-changeset", async function () {
for (const store of [
new implementation_1.IndexedDbStore("list-test5", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
let bundler = await instance.startBundle();
const list = await implementation_1.Sequence.create(instance, { bundler });
await list.push("A", { bundler });
await list.push("B", { bundler });
await list.push("C", { bundler });
const info = await bundler.commit();
(0, utils_1.ensure)(info.timestamp !== undefined && info.timestamp > 0);
(0, utils_1.ensure)(list.address.timestamp === info.timestamp);
for await (const [muid, _] of list.entries()) {
(0, utils_1.ensure)(muid.timestamp === info.timestamp);
}
bundler = await instance.startBundle();
await list.shift(false, { bundler });
await list.push("D", { bundler });
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(), ["A", "B", "C"]));
await bundler.commit();
const result = await list.toArray();
(0, utils_1.ensure)((0, utils_1.matches)(result, ["B", "C", "D"]));
}
});
it("List.toJSON", async function () {
// set up the objects
for (const store of [
new implementation_1.IndexedDbStore("list-toJSON", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const list = await implementation_1.Sequence.create(instance);
await list.push("A");
await list.push(true);
await list.push(false);
const subList = await implementation_1.Sequence.create(instance);
await subList.push(33);
await list.push(subList);
const subDir = await implementation_1.Directory.create(instance);
await subDir.set("cheese", "fries");
await list.push(subDir);
const bytes = new Uint8Array(3);
bytes[0] = 255;
bytes[1] = 94;
bytes[2] = 32;
await list.push(bytes);
const asJson = await list.toJson();
(0, utils_1.ensure)(asJson === `["A",true,false,[33],{"cheese":"fries"},"FF5E20"]`, asJson);
}
});
it("List.asOf", async function () {
// set up the objects
for (const store of [
new implementation_1.IndexedDbStore("list-asOf", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const list = await implementation_1.Sequence.create(instance);
const time0 = Date.now() * 1000;
await (0, test_utils_1.sleep)(10);
await list.push("A");
await (0, test_utils_1.sleep)(10);
const time1 = Date.now() * 1000;
await (0, test_utils_1.sleep)(10);
await list.push(true);
await (0, test_utils_1.sleep)(10);
const time2 = Date.now() * 1000;
await (0, test_utils_1.sleep)(10);
await list.push(false);
await (0, test_utils_1.sleep)(10);
const time3 = Date.now() * 1000;
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(Infinity, time3), ["A", true, false]));
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(Infinity, time2), ["A", true]));
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(Infinity, time1), ["A"]));
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(Infinity, time0), []));
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(Infinity, -1), ["A", true]));
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(Infinity, -2), ["A"]));
(0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(Infinity, -3), []));
}
});
it("List.clear", async function () {
for (const store of [
new implementation_1.IndexedDbStore("list-clear", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const list = await implementation_1.Sequence.create(instance);
await list.push("hello");
await list.push("world");
let size = await list.size();
(0, utils_1.ensure)(size === 2);
const clearMuid = await list.clear();
size = await list.size();
(0, utils_1.ensure)(size === 0);
await list.push("goodbye");
size = await list.size();
(0, utils_1.ensure)(size === 1);
size = await list.size(clearMuid.timestamp);
(0, utils_1.ensure)(size === 2);
await list.clear(true);
size = await list.size(clearMuid.timestamp);
(0, utils_1.ensure)(size === 0, `size=${size}`);
}
});
it("List.purge_pop", async function () {
for (const store of [
new implementation_1.IndexedDbStore("list-purgePop", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const seq = await implementation_1.Sequence.create(instance);
await seq.push("foo");
await seq.push("bar");
const beforeFirstPop = (0, utils_1.generateTimestamp)();
const popped = await seq.pop();
(0, utils_1.ensure)(popped === "bar", `popped=${popped}`);
(0, utils_1.ensure)((0, utils_1.matches)(["foo"], await seq.toArray()), (await seq.toArray()).toString());
const previous = await seq.toArray(Infinity, beforeFirstPop);
(0, utils_1.ensure)((0, utils_1.matches)(["foo", "bar"], previous), "previous=" + previous.toString());
const shifted = await seq.shift(true);
(0, utils_1.ensure)(shifted === "foo");
(0, utils_1.ensure)((0, utils_1.matches)(["bar"], await seq.toArray(Infinity, beforeFirstPop)));
}
});
it("List.move", async function () {
for (const store of [
new implementation_1.IndexedDbStore("list-move", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const seq = await implementation_1.Sequence.create(instance);
await seq.push("A");
await (0, test_utils_1.sleep)(100);
await seq.push("B");
await (0, test_utils_1.sleep)(100);
const cMuid = await seq.push("C");
await seq.push("D");
await (0, test_utils_1.sleep)(100);
(0, utils_1.ensure)((await seq.toArray()).toString() === "A,B,C,D");
await seq.move(0, -1);
(0, utils_1.ensure)((await seq.toArray()).toString() === "B,C,D,A", (await seq.toArray()).toString());
await seq.move(2, 0);
(0, utils_1.ensure)((await seq.toArray()).toString() === "D,B,C,A", (await seq.toArray()).toString());
await seq.move(cMuid, 1);
(0, utils_1.ensure)((await seq.toArray()).toString() === "D,C,B,A", (await seq.toArray()).toString());
}
});
it("extend", async function () {
for (const store of [
new implementation_1.IndexedDbStore("list-extend", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const seq = await implementation_1.Sequence.create(instance);
const array = [0, 1, 2, 3, 4, 5, 6];
await seq.extend(array);
(0, utils_1.ensure)((await seq.at(0)) === 0);
(0, utils_1.ensure)((await seq.at(6)) === 6);
const bundler = await instance.startBundle();
const array2 = [7, 8, 9, 10];
await seq.extend(array2, { bundler });
await bundler.commit();
(0, utils_1.ensure)((await seq.at(7)) === 7);
(0, utils_1.ensure)((await seq.at(10)) === 10);
}
});
it("List.reset", async function () {
for (const store of [
new implementation_1.IndexedDbStore("list-reset", true),
new implementation_1.MemoryStore(true),
]) {
const instance = new implementation_1.Database({ store });
await instance.ready;
const seq = await implementation_1.Sequence.create(instance);
const array = [0, 1, 2, 3, 4, 5, 6];
await seq.extend(array);
(0, utils_1.ensure)((await seq.at(0)) === 0);
(0, utils_1.ensure)((await seq.at(6)) === 6);
const afterExtend = (0, utils_1.generateTimestamp)();
const array2 = [7, 8, 9];
await seq.extend(array2);
(0, utils_1.ensure)((await seq.size()) === 10);
const afterSecond = (0, utils_1.generateTimestamp)();
await seq.reset(afterExtend);
(0, utils_1.ensure)((await seq.size()) === 7);
(0, utils_1.ensure)((await seq.at(0)) === 0);
(0, utils_1.ensure)((await seq.at(6)) === 6);
await seq.reset();
(0, utils_1.ensure)((await seq.size()) === 0);
await seq.reset(afterSecond);
(0, utils_1.ensure)((await seq.size()) === 10, (await seq.size()).toString());
(0, utils_1.ensure)((await seq.at(0)) === 0);
(0, utils_1.ensure)((await seq.at(9)) === 9);
await seq.push(10);
await seq.push(11);
await seq.move(10, 0);
await seq.reset(afterSecond);
(0, utils_1.ensure)((await seq.size()) === 10);
(0, utils_1.ensure)((await seq.at(0)) === 0);
(0, utils_1.ensure)((await seq.at(9)) === 9);
await seq.pop(0);
(0, utils_1.ensure)((await seq.size()) === 9);
await seq.reset(afterSecond);
(0, utils_1.ensure)((await seq.size()) === 10);
(0, utils_1.ensure)((await seq.at(0)) === 0);
(0, utils_1.ensure)((await seq.at(9)) === 9);
// Test recursive reset
await seq.clear();
const box = await implementation_1.Box.create(instance);
const dir = await implementation_1.Directory.create(instance);
await box.set(dir);
await dir.set("foo", "bar");
await seq.push(box);
const afterBox = (0, utils_1.generateTimestamp)();
await dir.set("foo", "baz");
await box.set("changed!");
await seq.push(1);
const beforeReset = (0, utils_1.generateTimestamp)();
await seq.reset(afterBox, true);
(0, utils_1.ensure)((await seq.size()) === 1);
(0, utils_1.ensure)((await box.get()) instanceof implementation_1.Directory);
(0, utils_1.ensure)((await dir.get("foo")) === "bar");
// Reset back
await seq.reset(beforeReset, true);
(0, utils_1.ensure)((await seq.size()) === 2);
(0, utils_1.ensure)((await seq.at(1)) === 1);
(0, utils_1.ensure)((await box.get()) === "changed!");
// This will not have been reset, since the directory was not held
// in the box at the time of the reset
(0, utils_1.ensure)((await dir.get("foo")) === "bar");
await seq.shift(); // Remove the box
await seq.reset(beforeReset, true);
(0, utils_1.ensure)((await seq.size()) === 2);
(0, utils_1.ensure)((await seq.at(1)) === 1);
(0, utils_1.ensure)((await box.get()) === "changed!");
}
});
//# sourceMappingURL=Sequence.test.js.map