UNPKG

woltage

Version:

A CQRS and Event-Sourcing Framework

198 lines (197 loc) 13 kB
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var _Woltage_instances, _a, _Woltage_importModules, _Woltage_constructAggregateMap, _Woltage_constructProjectorMap, _Woltage_aggregateMap, _Woltage_projectorMap, _Woltage_readModelMap, _Woltage_store, _Woltage_getStore, _Woltage_projections, _Woltage_init, _Woltage_loadProjections, _Woltage_saveProjections, _Woltage_createProjection, _Woltage_execute; import fs from 'node:fs/promises'; import path from 'node:path'; import Aggregate from "./write/Aggregate.js"; import EventStore from "./EventStore.js"; import Event from "./Event.js"; import { registerEventClasses } from "./eventMap.js"; import Projector from "./read/Projector.js"; import { z } from 'zod/v4'; import { createStore, createStoreFactory } from "./StoreFactory.js"; import Projection from "./read/Projection.js"; import ConflictError from "./errors/ConflictError.js"; import ProjectionMap from "./ProjectionMap.js"; import ReadModel from "./read/ReadModel.js"; import NotFoundError from "./errors/NotFoundError.js"; import { executionStorage } from "./localStorages.js"; const projectionConfigSchema = { projections: { key: z.object({ id: z.string() }), schema: z.object({ map: z.record(z.string(), z.object({ activeVersion: z.int().optional(), versions: z.record(z.string(), z.object({ projectionId: z.string(), name: z.string(), version: z.int(), projectorName: z.string(), projectorVersion: z.int(), storeName: z.string(), })) })) }) } }; class Woltage { static async create(config) { const instance = new this(config); await __classPrivateFieldGet(instance, _Woltage_instances, "m", _Woltage_init).call(instance); if (config.autostart !== false) await instance.start(); return instance; } constructor(config) { _Woltage_instances.add(this); _Woltage_aggregateMap.set(this, {}); _Woltage_projectorMap.set(this, {}); _Woltage_readModelMap.set(this, {}); _Woltage_store.set(this, void 0); _Woltage_getStore.set(this, void 0); _Woltage_projections.set(this, void 0); this.config = config; __classPrivateFieldSet(this, _Woltage_store, createStore(this.config.internalStore, '_woltage_config'), "f"); __classPrivateFieldGet(this, _Woltage_store, "f").defineTables(projectionConfigSchema); __classPrivateFieldSet(this, _Woltage_getStore, createStoreFactory(this.config.stores ?? {}), "f"); __classPrivateFieldSet(this, _Woltage_projections, new ProjectionMap(), "f"); } async addProjection(projectionName, projectionVersion, projectorName, projectorVersion, storeName) { const projection = await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_createProjection).call(this, projectionName, projectionVersion, projectorName, projectorVersion, storeName); __classPrivateFieldGet(this, _Woltage_projections, "f").add(projection); await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_saveProjections).call(this); } async setProjectionActive(projectionName, projectionVersion, force = false) { __classPrivateFieldGet(this, _Woltage_projections, "f").setActive(projectionName, projectionVersion, force); await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_saveProjections).call(this); } getProjections() { return Object.fromEntries(__classPrivateFieldGet(this, _Woltage_projections, "f").idMap); } getProjection(projectionName, projectionVersion) { return __classPrivateFieldGet(this, _Woltage_projections, "f").get(projectionName, projectionVersion); } async removeProjection(projectionName, projectionVersion, force = false) { await __classPrivateFieldGet(this, _Woltage_projections, "f").remove(projectionName, projectionVersion, force); await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_saveProjections).call(this); } async executeCommand(aggregateName, aggregateId, commandName, payload, context) { const aggregate = __classPrivateFieldGet(this, _Woltage_aggregateMap, "f")[aggregateName]; if (!aggregate) throw new NotFoundError(`Aggregate '${aggregateName}' not found.`); await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_execute).call(this, () => aggregate.executeCommand(aggregateId, commandName, payload), context); } async executeQuery(readModelName, handlerName, query, context) { if (typeof readModelName !== 'string') readModelName = readModelName.toString(); const readModel = __classPrivateFieldGet(this, _Woltage_readModelMap, "f")[ReadModel.getName(readModelName)]; if (!readModel) throw new NotFoundError(`Read model '${readModelName}' not found.`); return await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_execute).call(this, () => readModel.call(handlerName, query), context); } async start() { await EventStore.init(new this.config.eventStore.adapter(...(this.config.eventStore.args ?? []))); await __classPrivateFieldGet(this, _Woltage_projections, "f").init(); } async stop() { await __classPrivateFieldGet(this, _Woltage_projections, "f").stop(); await EventStore.close(); } } _a = Woltage, _Woltage_aggregateMap = new WeakMap(), _Woltage_projectorMap = new WeakMap(), _Woltage_readModelMap = new WeakMap(), _Woltage_store = new WeakMap(), _Woltage_getStore = new WeakMap(), _Woltage_projections = new WeakMap(), _Woltage_instances = new WeakSet(), _Woltage_importModules = async function _Woltage_importModules(dirPath, filter) { const modules = []; await Promise.all((await fs.readdir(dirPath, { withFileTypes: true, recursive: true })) .filter(dirent => dirent.isFile() && ['ts', 'js'].includes(dirent.name.split('.').pop() ?? '')) .map(async (dirent) => { const { default: module } = await import(path.join(dirent.parentPath, dirent.name)); if (filter(module)) modules.push(module); })); return modules; }, _Woltage_constructAggregateMap = function _Woltage_constructAggregateMap(aggregates) { return aggregates.reduce((map, aggregate) => { if (map[aggregate.name]) throw new Error(`Duplicate aggregate found. Aggregate '${aggregate.name}' already exists.`); map[aggregate.name] = aggregate; return map; }, {}); }, _Woltage_constructProjectorMap = function _Woltage_constructProjectorMap(projectorClasses) { return projectorClasses.reduce((map, ProjectorClass) => { map[ProjectorClass.name] ??= {}; if (map[ProjectorClass.name][ProjectorClass.version]) throw new Error(`Duplicate projector class found. Projector '${ProjectorClass.name}@${ProjectorClass.version}' already exists.`); map[ProjectorClass.name][ProjectorClass.version] = ProjectorClass; return map; }, {}); }, _Woltage_init = async function _Woltage_init() { registerEventClasses(typeof this.config.eventClasses === 'string' ? await __classPrivateFieldGet(_a, _a, "m", _Woltage_importModules).call(_a, this.config.eventClasses, module => module.prototype instanceof Event) : this.config.eventClasses); __classPrivateFieldSet(this, _Woltage_aggregateMap, __classPrivateFieldGet(_a, _a, "m", _Woltage_constructAggregateMap).call(_a, typeof this.config.aggregates === 'string' ? await __classPrivateFieldGet(_a, _a, "m", _Woltage_importModules).call(_a, this.config.aggregates, module => module instanceof Aggregate) : this.config.aggregates), "f"); __classPrivateFieldSet(this, _Woltage_projectorMap, __classPrivateFieldGet(_a, _a, "m", _Woltage_constructProjectorMap).call(_a, typeof this.config.projectorClasses === 'string' ? await __classPrivateFieldGet(_a, _a, "m", _Woltage_importModules).call(_a, this.config.projectorClasses, module => module.prototype instanceof Projector) : this.config.projectorClasses), "f"); __classPrivateFieldSet(this, _Woltage_readModelMap, Object.fromEntries((typeof this.config.readModelClasses === 'string' ? await __classPrivateFieldGet(_a, _a, "m", _Woltage_importModules).call(_a, this.config.readModelClasses, module => module.prototype instanceof ReadModel) : this.config.readModelClasses ?? []) .map(ReadModelClass => [ReadModelClass.toString(), new ReadModelClass()])), "f"); await __classPrivateFieldGet(this, _Woltage_store, "f").connect(); await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_loadProjections).call(this); }, _Woltage_loadProjections = async function _Woltage_loadProjections() { const projectionMap = (await __classPrivateFieldGet(this, _Woltage_store, "f").tables.projections.get({ id: 'status' }))?.map ?? {}; await Promise.all(Object.entries(projectionMap) .map(async ([name, { activeVersion, versions }]) => { await Promise.all(Object.entries(versions) .map(async ([, { version, projectorName, projectorVersion, storeName }]) => __classPrivateFieldGet(this, _Woltage_projections, "f").add(await __classPrivateFieldGet(this, _Woltage_instances, "m", _Woltage_createProjection).call(this, name, version, projectorName, projectorVersion, storeName)))); if (activeVersion !== undefined) __classPrivateFieldGet(this, _Woltage_projections, "f").setActive(name, activeVersion, true); })); }, _Woltage_saveProjections = async function _Woltage_saveProjections() { const map = {}; for (const projection of __classPrivateFieldGet(this, _Woltage_projections, "f").idMap.values()) { map[projection.name] ??= { activeVersion: undefined, versions: {} }; map[projection.name].versions[projection.version] = { projectionId: projection.id, name: projection.name, version: projection.version, projectorName: projection.projector.constructor.name, projectorVersion: projection.projector.constructor.version, storeName: projection.storeName ?? '' }; } for (const projection of __classPrivateFieldGet(this, _Woltage_projections, "f").activeProjectionMap.values()) map[projection.name].activeVersion = projection.version; await __classPrivateFieldGet(this, _Woltage_store, "f").tables.projections.set({ id: 'status', map }); }, _Woltage_createProjection = async function _Woltage_createProjection(projectionName, projectionVersion, projectorName, projectorVersion, storeName) { const projectionId = Projection.getId(projectionName, projectionVersion); if (__classPrivateFieldGet(this, _Woltage_projections, "f").get(projectionId)) throw new ConflictError('Projection already exists'); const ProjectorClass = __classPrivateFieldGet(this, _Woltage_projectorMap, "f")[projectorName]?.[projectorVersion]; if (!ProjectorClass) throw new NotFoundError(`Projector '${projectorName}@${projectorVersion}' not found`); const store = __classPrivateFieldGet(this, _Woltage_getStore, "f").call(this, storeName, projectionId); const projection = new Projection(projectionName, projectionVersion, ProjectorClass, store); projection.storeName = storeName; await store.connect(); return projection; }, _Woltage_execute = async function _Woltage_execute(routine, context) { return await executionStorage.run({ readModelMap: __classPrivateFieldGet(this, _Woltage_readModelMap, "f"), projectionMap: new Map(__classPrivateFieldGet(this, _Woltage_projections, "f").activeProjectionMap), context }, routine); }; export default Woltage.create.bind(Woltage);