UNPKG

@elsikora/nestjs-crud-automator

Version:

A library for automating the creation of CRUD operations in NestJS.

130 lines (127 loc) 7.26 kB
import { ApiFunctionContextStorage } from '../../class/api/function/context-storage.class.js'; import { ApiFunctionTransactionRuntime } from '../../class/api/function/transaction/runtime.class.js'; import { SERVICE_API_DECORATOR_CONSTANT } from '../../constant/decorator/api/service.constant.js'; import '../../enum/decorator/api/action.enum.js'; import '../../enum/decorator/api/authentication-type.enum.js'; import '../../enum/decorator/api/controller/get-list/query/filter/missing-behavior.enum.js'; import '../../enum/decorator/api/controller/get-list/query/unlisted-fields.enum.js'; import '../../enum/decorator/api/controller/relation-reference-shape.enum.js'; import '../../enum/decorator/api/controller/request/target.enum.js'; import '../../enum/decorator/api/controller/request/transformer-type.enum.js'; import '../../enum/decorator/api/controller/response-target.enum.js'; import '../../enum/decorator/api/dto-type.enum.js'; import '../../enum/decorator/api/function/context-storage-kind.enum.js'; import '../../enum/decorator/api/function/subscriber-transaction-expectation.enum.js'; import '../../enum/decorator/api/function/transaction/event-status.enum.js'; import '../../enum/decorator/api/function/transaction/failure-stage.enum.js'; import { EApiFunctionTransactionMode } from '../../enum/decorator/api/function/transaction/mode.enum.js'; import '../../enum/decorator/api/function/transaction/outcome.enum.js'; import { EApiFunctionTransactionOwnerKind } from '../../enum/decorator/api/function/transaction/owner-kind.enum.js'; import '../../enum/decorator/api/function/transaction/trace-type.enum.js'; import '../../enum/decorator/api/function/type.enum.js'; import '../../enum/decorator/api/on-type.enum.js'; import '../../enum/decorator/api/property/data-type.enum.js'; import '../../enum/decorator/api/property/date/identifier.enum.js'; import '../../enum/decorator/api/property/date/type.enum.js'; import '../../enum/decorator/api/property/desribe-type.enum.js'; import '../../enum/decorator/api/property/number-type.enum.js'; import '../../enum/decorator/api/property/string-type.enum.js'; import '../../enum/decorator/api/route/subscriber-authorization-expectation.enum.js'; import '../../enum/decorator/api/route/type.enum.js'; import { ErrorException } from '../error/exception.utility.js'; /** * Executes an ApiFunction callback according to its transaction mode. * @template E - Entity type owned by the function repository. * @template R - Callback result type. * @param {object} options - Transaction execution options. * @param {string} [options.action] - Custom function action used for subscriber matching. * @param {(eventManager: EntityManager | undefined) => Promise<R>} options.callback - Function body to run with the resolved transaction manager. * @param {new (...arguments_: Array<unknown>) => E} options.entity - Entity constructor associated with the function. * @param {TApiFunctionTransactionTraceType} options.functionType - Function trace type. * @param {string} [options.label] - Error message label for the decorated function primitive. * @param {string} options.methodName - Decorated service method name. * @param {EApiFunctionTransactionMode} options.mode - Transaction mode to enforce. * @param {(eventManager: EntityManager | undefined, error: Error) => Promise<void>} [options.onPreflightError] - Error hook for transaction mode conflicts before the function body starts. * @param {Repository<E>} [options.repository] - Repository used to open new transactions when required. * @param {new (...arguments_: Array<unknown>) => unknown} [options.serviceConstructor] - Observable service constructor used for subscriber matching. * @returns {Promise<R>} Callback result. */ async function ApiFunctionExecuteWithTransaction(options) { const activeRegistry = ApiFunctionContextStorage.getTransactionRegistry(); const activeEventManager = activeRegistry ? ApiFunctionContextStorage.getEventManager() : undefined; const label = options.label ?? "ApiFunction"; const isSubscriberObservable = Boolean(options.serviceConstructor && Reflect.hasMetadata(SERVICE_API_DECORATOR_CONSTANT.OBSERVABLE_METADATA_KEY, options.serviceConstructor)); const executeWithEventManager = async (eventManager) => { const registry = ApiFunctionContextStorage.getTransactionRegistry(); const sequence = registry?.beginEvent({ action: options.action, entityName: options.entity.name, functionType: options.functionType, isSubscriberObservable, methodName: options.methodName, }); try { const result = await options.callback(eventManager); if (sequence !== undefined) { registry?.succeedEvent(sequence); } return result; } catch (error) { if (sequence !== undefined) { registry?.failEvent(sequence, error); } throw error; } }; if (options.mode === EApiFunctionTransactionMode.NONE && activeEventManager) { const error = ErrorException(`${label} transaction mode NONE cannot run inside an active transaction`); const sequence = activeRegistry?.beginEvent({ action: options.action, entityName: options.entity.name, functionType: options.functionType, isSubscriberObservable, methodName: options.methodName, }); try { await options.onPreflightError?.(activeEventManager, error); } catch (preflightError) { if (sequence !== undefined) { activeRegistry?.failEvent(sequence, preflightError); } throw preflightError; } if (sequence !== undefined) { activeRegistry?.failEvent(sequence, error); } throw error; } if (options.mode === EApiFunctionTransactionMode.MANDATORY && !activeEventManager) { const error = ErrorException(`${label} transaction mode MANDATORY requires an active transaction`); await options.onPreflightError?.(undefined, error); throw error; } const eventManager = options.mode === EApiFunctionTransactionMode.NONE ? undefined : activeEventManager; if (options.mode === EApiFunctionTransactionMode.REQUIRED && !eventManager) { if (!options.repository) { const error = ErrorException("Repository is not available in this context"); await options.onPreflightError?.(undefined, error); throw error; } return await ApiFunctionTransactionRuntime.execute({ callback: executeWithEventManager, dataSource: options.repository.manager.connection, owner: { action: options.action, entityName: options.entity.name, functionType: options.functionType, kind: EApiFunctionTransactionOwnerKind.FUNCTION, methodName: options.methodName, }, }); } return await executeWithEventManager(eventManager); } export { ApiFunctionExecuteWithTransaction }; //# sourceMappingURL=function-transaction.utility.js.map