UNPKG

@x5e/gink

Version:

an eventually consistent database

181 lines 7.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PairSet = void 0; const Database_1 = require("./Database"); const Container_1 = require("./Container"); const utils_1 = require("./utils"); const factories_1 = require("./factories"); const builders_1 = require("./builders"); class PairSet extends Container_1.Container { constructor(database, address) { super(database, address, builders_1.Behavior.PAIR_SET); } static get(database, muid) { database = database || Database_1.Database.recent; if (!muid) { muid = { timestamp: -1, medallion: -1, offset: builders_1.Behavior.PAIR_SET }; } return new PairSet(database, muid); } static async create(database, meta) { database = database || Database_1.Database.recent; const muid = await Container_1.Container.addContainer({ behavior: builders_1.Behavior.PAIR_SET, database, meta, }); return new PairSet(database, muid); } /** * Includes a pair of Muids or Containers in the pair set. * @param key a pair of either containers or Muids to include * @param change an optional bundler to put this change into * @returns a promise that resolves to the Muid for the inclusion */ async include(key, meta) { return await this.addEntry(key, Container_1.Container.INCLUSION, meta); } /** * Excludes a pair of Muids or Containers in the pair set. * @param key a pair of either containers or Muids to include * @param change an optional bundler to put this change into * @returns a promise that resolves to the Muid for the exclusion */ async exclude(key, meta) { return await this.addEntry(key, Container_1.Container.DELETION, meta); } /** * If the pair set has a key or not. * @param key array of 2 muids or containers * @param asOf optional timestamp to look back to * @returns a promise that resolves to a boolean, true if the key is included, false if not */ async contains(key, asOf) { const aKey = [ key[0] instanceof Container_1.Container ? key[0].address : key[0], key[1] instanceof Container_1.Container ? key[1].address : key[1], ]; const found = await this.database.store.getEntryByKey(this.address, aKey, asOf); if (found && found.deletion) return false; return Boolean(found); } async reset(toTime, recurse, meta) { const bundler = await this.database.startBundle(meta); if (!toTime) { // If no time is specified, we are resetting to epoch, which is just a clear this.clear(false, { bundler }); } else { const union = new Set(); const entriesThen = await this.database.store.getKeyedEntries(this.address, toTime); const entriesNow = await this.database.store.getKeyedEntries(this.address); for (const [key, entry] of entriesThen) { const storageKey = entry.storageKey; union.add(storageKey); } for (const [key, entry] of entriesNow) { const storageKey = entry.storageKey; union.add(storageKey); } for (const key of union) { const genericKey = (0, utils_1.fromStorageKey)(key); const thenEntry = await this.database.store.getEntryByKey(this.address, genericKey, toTime); const nowEntry = await this.database.store.getEntryByKey(this.address, genericKey); (0, utils_1.ensure)(nowEntry || thenEntry, "both then and now undefined?"); if (!nowEntry) { // This key was present then, but not now, so we need to add it back (0, utils_1.ensure)(thenEntry, "missing then entry?"); await this.addEntry(genericKey, thenEntry.value, { bundler, }); } else if (!thenEntry) { // This key is present now, but not then, so we need to delete it (0, utils_1.ensure)(nowEntry, "missing now entry?"); await this.addEntry(genericKey, Container_1.Container.DELETION, { bundler, }); } else if (nowEntry.deletion !== thenEntry.deletion) { if (nowEntry.deletion) { // Present then, deleted now. Need to revive. await this.addEntry(genericKey, Container_1.Container.INCLUSION, { bundler, }); } else if (thenEntry.deletion) { // Present now, deleted then. Need to delete. await this.addEntry(genericKey, Container_1.Container.DELETION, { bundler, }); } } else { (0, utils_1.ensure)(nowEntry.deletion === thenEntry.deletion, "last case should be same entry"); } } } if (!meta?.bundler) { await bundler.commit(); } } /** * The number of items in the pair set. * @param asOf optional timestamp to look back to * @returns a promise that resolves to the number of entries */ async size(asOf) { const entries = await this.database.store.getKeyedEntries(this.address, asOf); return entries.size; } /** * All of the pairs in the Pair Set as a set * @param asOf optional timestamp to look back to * @returns a promise that resolves to a set of pairs [Muid, Muid] */ async getPairs(asOf) { const entries = await this.database.store.getKeyedEntries(this.address, asOf); const toSet = new Set(); for (const [key, entry] of entries) { if (!entry.deletion) { toSet.add(entry.storageKey); } } return toSet; } /** * Generates a JSON representation of the data in the pair set. * Mostly intended for demo/debug purposes. * @param indent true to pretty print (not yet implemented) * @param asOf optional timestamp to look back to * @param seen (internal use only! This prevents cycles from breaking things) * @returns a JSON string */ async toJson(indent = false, asOf, seen) { //TODO(https://github.com/google/gink/issues/62): add indentation (0, utils_1.ensure)(indent === false, "indent not implemented"); if (seen === undefined) seen = new Set(); const mySig = (0, utils_1.muidToString)(this.address); if (seen.has(mySig)) return "null"; seen.add(mySig); const asSet = await this.getPairs(asOf); let returning = "["; let first = true; for (const key of asSet) { if (first) { first = false; } else { returning += ","; } returning += await (0, factories_1.toJson)(`[${(0, utils_1.muidToString)(key[0])}, ${(0, utils_1.muidToString)(key[1])}]`, indent === false ? false : +indent + 1, asOf, seen); } returning += "]"; return returning; } } exports.PairSet = PairSet; //# sourceMappingURL=PairSet.js.map