UNPKG

@x5e/gink

Version:

an eventually consistent database

418 lines 18.5 kB
"use strict"; var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; 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 instance.createSequence(); 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 instance.createSequence(); 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 instance.createSequence(); 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 () { var _a, e_1, _b, _c; // 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 instance.createSequence(); await list.push("A"); await list.push("B"); await list.push("C"); const buffer = []; try { for (var _d = true, _e = (e_1 = void 0, __asyncValues(list.entries())), _f; _f = await _e.next(), _a = _f.done, !_a;) { _c = _f.value; _d = false; try { const [muid, contents] = _c; const val = await list.pop(muid); (0, utils_1.ensure)(val === contents, `val=${val}, contents=${contents}`); buffer.push(contents); } finally { _d = true; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_d && !_a && (_b = _e.return)) await _b.call(_e); } finally { if (e_1) throw e_1.error; } } (0, utils_1.ensure)((0, utils_1.matches)(buffer, ["A", "B", "C"])); } }); it("list-changeset", async function () { var _a, e_2, _b, _c; 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; const bundler = new implementation_1.Bundler(); const list = await instance.createSequence(bundler); await list.push("A", bundler); await list.push("B", bundler); await list.push("C", bundler); await instance.addBundler(bundler); (0, utils_1.ensure)(bundler.timestamp !== undefined && bundler.timestamp > 0); (0, utils_1.ensure)(list.address.timestamp === bundler.timestamp); try { for (var _d = true, _e = (e_2 = void 0, __asyncValues(list.entries())), _f; _f = await _e.next(), _a = _f.done, !_a;) { _c = _f.value; _d = false; try { const [muid, _] = _c; (0, utils_1.ensure)(muid.timestamp === bundler.timestamp); } finally { _d = true; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (!_d && !_a && (_b = _e.return)) await _b.call(_e); } finally { if (e_2) throw e_2.error; } } const bundler2 = new implementation_1.Bundler(); await list.shift(false, bundler2); await list.push("D", bundler2); (0, utils_1.ensure)((0, utils_1.matches)(await list.toArray(), ["A", "B", "C"])); await instance.addBundler(bundler2); 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 instance.createSequence(); await list.push("A"); await list.push(true); await list.push(false); const subList = await instance.createSequence(); await subList.push(33); await list.push(subList); const subDir = await instance.createDirectory(); 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 instance.createSequence(); 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 instance.createSequence(); 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 instance.createSequence(); 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 instance.createSequence(); 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 instance.createSequence(); 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 = new implementation_1.Bundler(); const array2 = [7, 8, 9, 10]; await seq.extend(array2, bundler); await instance.addBundler(bundler); (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 instance.createSequence(); const prop1 = await instance.createProperty(); const prop2 = await instance.createProperty(); await prop1.set(seq, "foo"); await prop2.set(seq, "bar"); 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); await prop1.set(seq, "foo2"); await prop2.set(seq, "bar2"); (0, utils_1.ensure)((await seq.size()) === 10); const afterSecond = (0, utils_1.generateTimestamp)(); await seq.reset({ toTime: 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); (0, utils_1.ensure)((await prop1.get(seq)) === "foo"); (0, utils_1.ensure)((await prop2.get(seq)) === "bar"); await seq.reset(); (0, utils_1.ensure)((await seq.size()) === 0); (0, utils_1.ensure)((await prop1.get(seq)) === undefined); (0, utils_1.ensure)((await prop2.get(seq)) === undefined); await seq.reset({ toTime: afterSecond, skipProperties: true }); (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); (0, utils_1.ensure)((await prop1.get(seq)) === undefined); (0, utils_1.ensure)((await prop2.get(seq)) === undefined); await seq.push(10); await seq.push(11); await seq.move(10, 0); await seq.reset({ toTime: afterSecond, skipProperties: true }); (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); (0, utils_1.ensure)((await prop1.get(seq)) === undefined); (0, utils_1.ensure)((await prop2.get(seq)) === undefined); await seq.pop(0); (0, utils_1.ensure)((await seq.size()) === 9); await seq.reset({ toTime: afterSecond, skipProperties: true }); (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 instance.createBox(); const dir = await instance.createDirectory(); 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({ toTime: afterBox, recurse: 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({ toTime: beforeReset, recurse: 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({ toTime: beforeReset, recurse: 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