UNPKG

rich-domain

Version:

This package provide utils file and interfaces to assistant build a complex application with domain driving design

149 lines 5.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TsEvents = void 0; /** * @description TsEvents manages a collection of events for a given aggregate. * It allows adding, removing, and dispatching events, as well as retrieving event-related metrics. */ class TsEvents { aggregate; _metrics; _events; totalDispatched; /** * @description Creates an instance of TsEvents associated with a given aggregate. * @param aggregate The aggregate instance to which these events belong. */ constructor(aggregate) { this.aggregate = aggregate; this._events = []; this.totalDispatched = 0; this._metrics = { totalDispatched: () => this.totalDispatched, totalEvents: () => this._events.length, }; } /** * @description Provides metrics related to the currently managed events, such as the total number of * dispatched events and the total number of events pending. * @returns {Metrics} An object containing functions to retrieve event metrics. */ get metrics() { return this._metrics; } /** * @description Determines a priority value based on the number of currently stored events. * If there is one or zero events, the priority is set to 2. Otherwise, it equals the total number of events. * @returns The computed priority value. * @private */ getPriority() { const totalEvents = this._events.length; if (totalEvents <= 1) return 2; return totalEvents; } /** * @description Dispatches a single event by its name. If the event is found, it is executed and then removed. * If the event does not exist, this method does nothing. * @param eventName The name of the event to dispatch. * @param args Additional arguments to pass to the event's handler function. * @returns A void or Promise<void> depending on whether the event handler returns a promise. */ dispatchEvent(eventName, ...args) { const _event = this._events.find((evt) => evt.eventName === eventName); if (!_event) return; this.totalDispatched = this.totalDispatched + 1; _event.handler(this.aggregate, [_event, ...args]); this.removeEvent(eventName); } /** * @description Returns default options for an event if none are provided. * This typically sets the event priority based on the current number of events. * @returns The default event options. * @private */ getDefaultOptions() { const priority = this.getPriority(); return { priority, }; } /** * @description Adds a new event to the manager. If an event with the same name already exists, * the old event is removed before adding the new one. * @param eventName The name of the event to add. * @param handler The function to handle the event when dispatched. * @param options Optional configuration for the event, such as priority. * * @throws Will throw an error if `eventName` is invalid (not a string or too short) or if `handler` is not a function. */ addEvent(eventName, handler, options) { const defaultOptions = this.getDefaultOptions(); const opt = options ? options : defaultOptions; this.validateEventName(eventName); this.validateHandler(handler, eventName); this.removeEvent(eventName); this._events.push({ eventName, handler, options: opt }); } /** * @description Validates that the handler is a function. If not, it throws an error. * @param handler The event handler to validate. * @param eventName The name of the event associated with this handler. * @private */ validateHandler(handler, eventName) { if (typeof handler !== "function") { const message = `addEvent: handler for ${eventName} is not a function`; throw new Error(message); } } /** * @description Validates the event name. It must be a string and have at least 3 characters. * @param eventName The event name to validate. * @throws Will throw an error if the event name is invalid. * @private */ validateEventName(eventName) { if (typeof eventName !== "string" || String(eventName).length < 3) { const message = `addEvent: invalid event name ${eventName}`; throw new Error(message); } } /** * @description Removes all currently registered events. */ clearEvents() { this._events = []; } /** * @description Removes a specific event by its name. * @param eventName The name of the event to remove. */ removeEvent(eventName) { this._events = this._events.filter((event) => event.eventName !== eventName); } /** * @description Dispatches all currently stored events in order of their priority (lowest priority number first). * Once dispatched, events are removed from the collection. * @returns A Promise that resolves once all promise-based event handlers have been completed. * In case of errors during promise resolution, they are logged to the console. */ async dispatchEvents() { const promisesEvents = []; const sorted = this._events.sort((a, b) => a.options.priority - b.options.priority); sorted.forEach((_event) => { this.totalDispatched = this.totalDispatched + 1; const fn = _event.handler(this.aggregate, [_event]); if (fn instanceof Promise) { promisesEvents.push(fn); } }); await Promise.all(promisesEvents).catch(console.error); this.clearEvents(); } } exports.TsEvents = TsEvents; exports.default = TsEvents; //# sourceMappingURL=events.js.map