@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
229 lines (225 loc) • 11.9 kB
JavaScript
'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