fact-streams
Version:
An event-sourcing toolkit for Node and MongoDB
347 lines (340 loc) • 12.5 kB
JavaScript
;
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
});