UNPKG

fact-streams

Version:

An event-sourcing toolkit for Node and MongoDB

347 lines (340 loc) 12.5 kB
"use strict"; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __knownSymbol = (name, symbol) => { if (symbol = Symbol[name]) return symbol; throw Error("Symbol." + name + " is not defined"); }; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); setter ? setter.call(obj, value) : member.set(obj, value); return value; }; var __privateMethod = (obj, member, method) => { __accessCheck(obj, member, "access private method"); return method; }; var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it); // src/index.ts var src_exports = {}; __export(src_exports, { NEW: () => NEW, ObjectId: () => import_mongodb3.ObjectId, View: () => View, connect: () => connect, createFact: () => createFact }); module.exports = __toCommonJS(src_exports); var import_mongodb3 = require("mongodb"); // src/connect.ts var import_mongodb2 = require("mongodb"); // src/factStore.ts var import_mongodb = require("mongodb"); var NEW = new import_mongodb.ObjectId("000000000000000000000001"); function createFactStore(mongoDatabase, options) { return __async(this, null, function* () { const { name: factStoreName } = options; const onBeforeAppendListeners = []; const onAfterAppendListeners = []; try { yield mongoDatabase.createCollection(factStoreName); } catch (error) { if (error instanceof import_mongodb.MongoError && error.code === 48) { } else { throw error; } } yield mongoDatabase.collection(factStoreName).createIndex({ streamId: 1, revision: 1 }, { name: "streamId_revision", unique: true }); function append(fact) { return __async(this, null, function* () { var _a; let newStreamId; let newRevision; if (NEW.equals(fact.streamId)) { newStreamId = new import_mongodb.ObjectId(); newRevision = 1; } else { const lastFactInDb = yield mongoDatabase.collection(factStoreName).find({ streamId: fact.streamId }).sort({ revision: -1 }).limit(1).toArray(); newStreamId = fact.streamId; newRevision = lastFactInDb.length === 0 ? 1 : (((_a = lastFactInDb[0]) == null ? void 0 : _a.revision) || 0) + 1; } let factToSave = __spreadProps(__spreadValues({}, fact), { streamId: newStreamId, revision: newRevision, time: /* @__PURE__ */ new Date() }); try { for (var iter = __forAwait(onBeforeAppendListeners), more, temp, error; more = !(temp = yield iter.next()).done; more = false) { const callback = temp.value; factToSave = yield callback(factToSave); } } catch (temp) { error = [temp]; } finally { try { more && (temp = iter.return) && (yield temp.call(iter)); } finally { if (error) throw error[0]; } } yield mongoDatabase.collection(factStoreName).insertOne(factToSave); try { for (var iter2 = __forAwait(onAfterAppendListeners), more2, temp2, error2; more2 = !(temp2 = yield iter2.next()).done; more2 = false) { const callback = temp2.value; yield callback(factToSave); } } catch (temp2) { error2 = [temp2]; } finally { try { more2 && (temp2 = iter2.return) && (yield temp2.call(iter2)); } finally { if (error2) throw error2[0]; } } return factToSave; }); } function onAfterAppend(callback) { onAfterAppendListeners.push(callback); } function onBeforeAppend(callback) { onBeforeAppendListeners.push(callback); } function find(streamId) { return mongoDatabase.collection(factStoreName).find({ streamId: new import_mongodb.ObjectId(streamId) }); } function findAll() { return mongoDatabase.collection(factStoreName).find(); } return { append, onAfterAppend, onBeforeAppend, find, findAll, mongoDatabase }; }); } // src/connect.ts function connect(options) { return __async(this, null, function* () { const { uri, dbName } = options; const connection = yield import_mongodb2.MongoClient.connect(uri); const mongoDatabase = connection.db(dbName); return { createFactStore: (options2) => createFactStore(mongoDatabase, options2), mongoDatabase, close: () => connection.close() }; }); } // src/createFact.ts function createFact(streamId, type, data, metadata) { return { streamId, revision: -1, // It gets reset before append type, time: /* @__PURE__ */ new Date(), data, metadata }; } // src/View.ts var _factStore, _initialStateCallback, _factCallbacks, _unknownCallback, _doneCallback, _clone, clone_fn, _replayFacts, replayFacts_fn, _rebuild, rebuild_fn; var _View = class _View { constructor(factStore) { __privateAdd(this, _clone); __privateAdd(this, _replayFacts); __privateAdd(this, _rebuild); __privateAdd(this, _factStore, void 0); __privateAdd(this, _initialStateCallback, void 0); __privateAdd(this, _factCallbacks, void 0); // fact-type --> function __privateAdd(this, _unknownCallback, void 0); __privateAdd(this, _doneCallback, void 0); __privateSet(this, _factStore, factStore); __privateSet(this, _initialStateCallback, () => null); __privateSet(this, _factCallbacks, {}); __privateSet(this, _unknownCallback, (state, fact) => { throw new Error(`Unexpected fact type: "${fact == null ? void 0 : fact.type}"`); }); __privateSet(this, _doneCallback, (state) => state); } on(type, reducer) { const newInstance = __privateMethod(this, _clone, clone_fn).call(this); __privateGet(newInstance, _factCallbacks)[type] = reducer; return newInstance; } onUnknownFact(callback) { const newInstance = __privateMethod(this, _clone, clone_fn).call(this); __privateSet(newInstance, _unknownCallback, callback); return newInstance; } onDone(callback) { const newInstance = __privateMethod(this, _clone, clone_fn).call(this); __privateSet(newInstance, _doneCallback, callback); return newInstance; } createPersistent(collectionName) { return __async(this, null, function* () { const collection = __privateGet(this, _factStore).mongoDatabase.collection(collectionName); __privateGet(this, _factStore).onAfterAppend((fact) => __privateMethod(this, _rebuild, rebuild_fn).call(this, collection, fact.streamId)); return { aggregate: collection.aggregate.bind(collection), countDocuments: collection.countDocuments.bind(collection), distinct: collection.distinct.bind(collection), find: collection.find.bind(collection), findOne: collection.findOne.bind(collection), collection, replayFacts: (streamId) => __privateMethod(this, _replayFacts, replayFacts_fn).call(this, streamId), rebuild: (streamId) => __privateMethod(this, _rebuild, rebuild_fn).call(this, collection, streamId) }; }); } createTransient() { return __async(this, null, function* () { return (streamId) => __privateMethod(this, _replayFacts, replayFacts_fn).call(this, streamId); }); } }; _factStore = new WeakMap(); _initialStateCallback = new WeakMap(); _factCallbacks = new WeakMap(); _unknownCallback = new WeakMap(); _doneCallback = new WeakMap(); _clone = new WeakSet(); clone_fn = function() { const newInstance = new _View(__privateGet(this, _factStore)); __privateSet(newInstance, _initialStateCallback, __privateGet(this, _initialStateCallback)); __privateSet(newInstance, _factCallbacks, __spreadValues({}, __privateGet(this, _factCallbacks))); __privateSet(newInstance, _unknownCallback, __privateGet(this, _unknownCallback)); __privateSet(newInstance, _doneCallback, __privateGet(this, _doneCallback)); return newInstance; }; _replayFacts = new WeakSet(); replayFacts_fn = function(streamId) { return __async(this, null, function* () { const cursor = yield __privateGet(this, _factStore).find(streamId); let state = yield __privateGet(this, _initialStateCallback).call(this); try { for (var iter = __forAwait(cursor), more, temp, error; more = !(temp = yield iter.next()).done; more = false) { const fact = temp.value; const reducerForType = __privateGet(this, _factCallbacks)[fact.type]; if (reducerForType) { state = yield reducerForType(state, fact); } else { state = yield __privateGet(this, _unknownCallback).call(this, state, fact); } } } catch (temp) { error = [temp]; } finally { try { more && (temp = iter.return) && (yield temp.call(iter)); } finally { if (error) throw error[0]; } } state = yield __privateGet(this, _doneCallback).call(this, state); return state; }); }; _rebuild = new WeakSet(); rebuild_fn = function(collection, streamId) { return __async(this, null, function* () { const state = yield __privateMethod(this, _replayFacts, replayFacts_fn).call(this, streamId); if (state === null) { yield collection.deleteOne({ _id: streamId }); } else { yield collection.replaceOne( // @ts-ignore { _id: streamId }, state, { upsert: true } ); } }); }; var View = _View; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { NEW, ObjectId, View, connect, createFact });