UNPKG

@elsikora/nestjs-crud-automator

Version:

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

229 lines (225 loc) 11.9 kB
'use strict'; var commitUnknownOutcome_class = require('./exception/commit-unknown-outcome.class.js'); var postCommit_class = require('./exception/post-commit.class.js'); var rollback_class = require('./exception/rollback.class.js'); var registry_class = require('../../subscriber/registry.class.js'); require('../../../../enum/decorator/api/action.enum.js'); require('../../../../enum/decorator/api/authentication-type.enum.js'); require('../../../../enum/decorator/api/controller/get-list/query/filter/missing-behavior.enum.js'); require('../../../../enum/decorator/api/controller/get-list/query/unlisted-fields.enum.js'); require('../../../../enum/decorator/api/controller/relation-reference-shape.enum.js'); require('../../../../enum/decorator/api/controller/request/target.enum.js'); require('../../../../enum/decorator/api/controller/request/transformer-type.enum.js'); require('../../../../enum/decorator/api/controller/response-target.enum.js'); require('../../../../enum/decorator/api/dto-type.enum.js'); require('../../../../enum/decorator/api/function/context-storage-kind.enum.js'); require('../../../../enum/decorator/api/function/subscriber-transaction-expectation.enum.js'); require('../../../../enum/decorator/api/function/transaction/event-status.enum.js'); var failureStage_enum = require('../../../../enum/decorator/api/function/transaction/failure-stage.enum.js'); require('../../../../enum/decorator/api/function/transaction/mode.enum.js'); require('../../../../enum/decorator/api/function/transaction/outcome.enum.js'); require('../../../../enum/decorator/api/function/transaction/owner-kind.enum.js'); var traceType_enum = require('../../../../enum/decorator/api/function/transaction/trace-type.enum.js'); require('../../../../enum/decorator/api/function/type.enum.js'); require('../../../../enum/decorator/api/on-type.enum.js'); require('../../../../enum/decorator/api/property/data-type.enum.js'); require('../../../../enum/decorator/api/property/date/identifier.enum.js'); require('../../../../enum/decorator/api/property/date/type.enum.js'); require('../../../../enum/decorator/api/property/desribe-type.enum.js'); require('../../../../enum/decorator/api/property/number-type.enum.js'); require('../../../../enum/decorator/api/property/string-type.enum.js'); require('../../../../enum/decorator/api/route/subscriber-authorization-expectation.enum.js'); require('../../../../enum/decorator/api/route/type.enum.js'); class ApiFunctionTransactionLifecycle { static async executeAfterCommit(registry) { const subscribers = ApiFunctionTransactionLifecycle.getMatchingSubscribers(registry); const hookFailures = []; for (const { context, subscriber } of subscribers) { if (!subscriber.onAfterCommit) { continue; } try { await subscriber.onAfterCommit(context); } catch (error) { hookFailures.push(ApiFunctionTransactionLifecycle.createFailure(failureStage_enum.EApiFunctionTransactionFailureStage.AFTER_COMMIT, error, subscriber)); } } if (hookFailures.length === 0) { return; } const beforeErrorFailures = await ApiFunctionTransactionLifecycle.executeBeforeCommitErrorSubscribers(subscribers, hookFailures); const transaction = registry.getTransaction(); const provisionalError = new postCommit_class.ApiFunctionTransactionPostCommitException({ errorLifecycleFailures: beforeErrorFailures, hookFailures, owner: transaction.owner, transactionId: transaction.id, }); const afterErrorFailures = await ApiFunctionTransactionLifecycle.executeAfterCommitErrorSubscribers(subscribers, provisionalError); throw new postCommit_class.ApiFunctionTransactionPostCommitException({ errorLifecycleFailures: [...beforeErrorFailures, ...afterErrorFailures], hookFailures, owner: transaction.owner, transactionId: transaction.id, }); } static async executeAfterRollback(registry, operationError, rollbackFailure) { const subscribers = ApiFunctionTransactionLifecycle.getMatchingSubscribers(registry); const hookFailures = []; for (const { context, subscriber } of subscribers) { if (!subscriber.onAfterRollback) { continue; } try { await subscriber.onAfterRollback(context); } catch (error) { hookFailures.push(ApiFunctionTransactionLifecycle.createFailure(failureStage_enum.EApiFunctionTransactionFailureStage.AFTER_ROLLBACK, error, subscriber)); } } const rawFailures = rollbackFailure ? [rollbackFailure, ...hookFailures] : hookFailures; if (rawFailures.length === 0) { throw operationError; } const beforeErrorFailures = await ApiFunctionTransactionLifecycle.executeBeforeRollbackErrorSubscribers(subscribers, rawFailures); const transaction = registry.getTransaction(); const provisionalError = new rollback_class.ApiFunctionTransactionRollbackException({ errorLifecycleFailures: beforeErrorFailures, hookFailures, operationError, owner: transaction.owner, rollbackFailure, transactionId: transaction.id, }); const afterErrorFailures = await ApiFunctionTransactionLifecycle.executeAfterRollbackErrorSubscribers(subscribers, provisionalError); throw new rollback_class.ApiFunctionTransactionRollbackException({ errorLifecycleFailures: [...beforeErrorFailures, ...afterErrorFailures], hookFailures, operationError, owner: transaction.owner, rollbackFailure, transactionId: transaction.id, }); } static async executeCommitUnknown(registry, error, cleanupFailure) { const subscribers = ApiFunctionTransactionLifecycle.getMatchingSubscribers(registry); const commitFailure = ApiFunctionTransactionLifecycle.createFailure(failureStage_enum.EApiFunctionTransactionFailureStage.COMMIT, error); const rawFailures = cleanupFailure ? [commitFailure, cleanupFailure] : [commitFailure]; const beforeErrorFailures = await ApiFunctionTransactionLifecycle.executeBeforeCommitErrorSubscribers(subscribers, rawFailures); const transaction = registry.getTransaction(); const provisionalError = new commitUnknownOutcome_class.ApiFunctionTransactionCommitUnknownOutcomeException({ cleanupFailure, commitFailure, errorLifecycleFailures: beforeErrorFailures, owner: transaction.owner, transactionId: transaction.id, }); const afterErrorFailures = await ApiFunctionTransactionLifecycle.executeAfterCommitErrorSubscribers(subscribers, provisionalError); throw new commitUnknownOutcome_class.ApiFunctionTransactionCommitUnknownOutcomeException({ cleanupFailure, commitFailure, errorLifecycleFailures: [...beforeErrorFailures, ...afterErrorFailures], owner: transaction.owner, transactionId: transaction.id, }); } static createFailure(stage, error, subscriber) { return Object.freeze({ error, stage, subscriberName: subscriber?.constructor.name, }); } static async executeAfterCommitErrorSubscribers(subscribers, error) { const failures = []; for (const { context, subscriber } of subscribers) { if (!subscriber.onAfterErrorCommit) { continue; } try { await subscriber.onAfterErrorCommit(context, error); } catch (lifecycleError) { failures.push(ApiFunctionTransactionLifecycle.createFailure(failureStage_enum.EApiFunctionTransactionFailureStage.AFTER_ERROR_COMMIT, lifecycleError, subscriber)); } } return failures; } static async executeAfterRollbackErrorSubscribers(subscribers, error) { const failures = []; for (const { context, subscriber } of subscribers) { if (!subscriber.onAfterErrorRollback) { continue; } try { await subscriber.onAfterErrorRollback(context, error); } catch (lifecycleError) { failures.push(ApiFunctionTransactionLifecycle.createFailure(failureStage_enum.EApiFunctionTransactionFailureStage.AFTER_ERROR_ROLLBACK, lifecycleError, subscriber)); } } return failures; } static async executeBeforeCommitErrorSubscribers(subscribers, rawFailures) { const failures = []; const readonlyFailures = Object.freeze([...rawFailures]); for (const { context, subscriber } of subscribers) { if (!subscriber.onBeforeErrorCommit) { continue; } try { await subscriber.onBeforeErrorCommit(context, readonlyFailures); } catch (error) { failures.push(ApiFunctionTransactionLifecycle.createFailure(failureStage_enum.EApiFunctionTransactionFailureStage.BEFORE_ERROR_COMMIT, error, subscriber)); } } return failures; } static async executeBeforeRollbackErrorSubscribers(subscribers, rawFailures) { const failures = []; const readonlyFailures = Object.freeze([...rawFailures]); for (const { context, subscriber } of subscribers) { if (!subscriber.onBeforeErrorRollback) { continue; } try { await subscriber.onBeforeErrorRollback(context, readonlyFailures); } catch (error) { failures.push(ApiFunctionTransactionLifecycle.createFailure(failureStage_enum.EApiFunctionTransactionFailureStage.BEFORE_ERROR_ROLLBACK, error, subscriber)); } } return failures; } static getMatchingSubscribers(registry) { const matchedEvents = new Map(); for (const event of registry.getObservableEvents()) { if (event.functionType === traceType_enum.EApiFunctionTransactionTraceType.STEP) { continue; } const subscribers = registry_class.apiSubscriberRegistry.getFunctionSubscribers(event.entityName, event.functionType, event.action); for (const subscriber of subscribers) { const events = matchedEvents.get(subscriber) ?? []; events.push(event); matchedEvents.set(subscriber, events); } } return [...matchedEvents.entries()] .toSorted((leftEntry, rightEntry) => { const leftSubscriber = leftEntry[0]; const rightSubscriber = rightEntry[0]; const leftProperties = registry_class.apiSubscriberRegistry.getFunctionSubscriberProperties(leftSubscriber); const rightProperties = registry_class.apiSubscriberRegistry.getFunctionSubscriberProperties(rightSubscriber); const priorityDifference = (rightProperties?.priority ?? 0) - (leftProperties?.priority ?? 0); return priorityDifference === 0 ? registry_class.apiSubscriberRegistry.getFunctionSubscriberRegistrationOrder(leftSubscriber) - registry_class.apiSubscriberRegistry.getFunctionSubscriberRegistrationOrder(rightSubscriber) : priorityDifference; }) .map((entry) => ({ context: registry.createContext(entry[1]), subscriber: entry[0], })); } } exports.ApiFunctionTransactionLifecycle = ApiFunctionTransactionLifecycle; //# sourceMappingURL=lifecycle.class.js.map