@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
189 lines (185 loc) • 12.4 kB
JavaScript
;
var contextStorage_class = require('../function/context-storage.class.js');
var registry_class = require('./registry.class.js');
var controller_constant = require('../../../constant/decorator/api/controller.constant.js');
var service_constant = require('../../../constant/decorator/api/service.constant.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');
var subscriberTransactionExpectation_enum = require('../../../enum/decorator/api/function/subscriber-transaction-expectation.enum.js');
require('../../../enum/decorator/api/function/transaction/event-status.enum.js');
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');
require('../../../enum/decorator/api/function/transaction/trace-type.enum.js');
var type_enum = require('../../../enum/decorator/api/function/type.enum.js');
var onType_enum = 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');
var camelCaseString_utility = require('../../../utility/camel-case-string.utility.js');
var exception_utility = require('../../../utility/error/exception.utility.js');
var logger_utility = require('../../../utility/logger.utility.js');
const subscriberLogger = logger_utility.LoggerUtility.getLogger("ApiSubscriberExecutor");
class ApiSubscriberExecutor {
static async executeFunctionBeforeSubscribers(constructor, entity, functionType, context, action) {
try {
const result = await ApiSubscriberExecutor.executeFunctionSubscribers(constructor, entity, functionType, onType_enum.EApiSubscriberOnType.BEFORE, context, action);
ApiSubscriberExecutor.assertFunctionSubscribersTransactionExpectation(constructor, entity, functionType, onType_enum.EApiSubscriberOnType.AFTER, context, action);
return result;
}
catch (error) {
const errorExecutionContext = {
action: context.action,
DATA: context.DATA,
ENTITY: context.ENTITY,
FUNCTION_TYPE: context.FUNCTION_TYPE,
};
await ApiSubscriberExecutor.executeFunctionErrorSubscribers(constructor, entity, functionType, onType_enum.EApiSubscriberOnType.BEFORE_ERROR, errorExecutionContext, error, action ?? context.action);
throw error;
}
}
static async executeFunctionErrorSubscribers(constructor, entity, functionType, onType, context, error, action) {
if (!Reflect.hasMetadata(service_constant.SERVICE_API_DECORATOR_CONSTANT.OBSERVABLE_METADATA_KEY, constructor)) {
return;
}
const entityName = ApiSubscriberExecutor.resolveEntityName(entity, context);
const subscribers = registry_class.apiSubscriberRegistry.getFunctionSubscribers(entityName, functionType, action ?? context.action);
await contextStorage_class.ApiFunctionContextStorage.runWithoutStepContext(async () => {
for (const subscriber of subscribers) {
const hookName = ApiSubscriberExecutor.resolveHookName(onType, functionType);
const hook = Reflect.get(subscriber, hookName);
if (typeof hook === "function") {
const properties = registry_class.apiSubscriberRegistry.getFunctionSubscriberProperties(subscriber);
ApiSubscriberExecutor.assertFunctionSubscriberTransactionExpectation(subscriber.constructor.name, properties, context);
subscriberLogger.verbose(`Executing function error hook ${hookName} from ${subscriber.constructor.name} for entity ${entityName}`);
await hook.call(subscriber, context, error);
}
}
});
}
static async executeFunctionSubscribers(constructor, entity, functionType, onType, context, action) {
if (!Reflect.hasMetadata(service_constant.SERVICE_API_DECORATOR_CONSTANT.OBSERVABLE_METADATA_KEY, constructor)) {
return context.result;
}
const entityName = ApiSubscriberExecutor.resolveEntityName(entity, context);
const subscribers = registry_class.apiSubscriberRegistry.getFunctionSubscribers(entityName, functionType, action ?? context.action);
let result = context.result;
await contextStorage_class.ApiFunctionContextStorage.runWithoutStepContext(async () => {
for (const subscriber of subscribers) {
const hookName = ApiSubscriberExecutor.resolveHookName(onType, functionType);
const hook = Reflect.get(subscriber, hookName);
if (typeof hook === "function") {
const properties = registry_class.apiSubscriberRegistry.getFunctionSubscriberProperties(subscriber);
ApiSubscriberExecutor.assertFunctionSubscriberTransactionExpectation(subscriber.constructor.name, properties, context);
subscriberLogger.verbose(`Executing function hook ${hookName} from ${subscriber.constructor.name} for entity ${entityName}`);
const hookResult = (await hook.call(subscriber, { ...context, result }));
if (hookResult !== undefined) {
result = hookResult;
}
}
}
});
return result;
}
static async executeRouteErrorSubscribers(constructor, entity, routeType, onType, context, error, action) {
if (!Reflect.hasMetadata(controller_constant.CONTROLLER_API_DECORATOR_CONSTANT.OBSERVABLE_METADATA_KEY, constructor)) {
return;
}
const entityName = ApiSubscriberExecutor.resolveEntityName(entity, context);
const subscribers = registry_class.apiSubscriberRegistry.getRouteSubscribers(entityName, constructor, routeType, action ?? context.action);
for (const subscriber of subscribers) {
const hookName = ApiSubscriberExecutor.resolveHookName(onType, routeType);
const hook = Reflect.get(subscriber, hookName);
if (typeof hook === "function") {
subscriberLogger.verbose(`Executing route error hook ${hookName} from ${subscriber.constructor.name} for entity ${entityName}`);
await hook.call(subscriber, context, error);
}
}
}
static async executeRouteSubscribers(constructor, entity, routeType, onType, context, action) {
if (!Reflect.hasMetadata(controller_constant.CONTROLLER_API_DECORATOR_CONSTANT.OBSERVABLE_METADATA_KEY, constructor)) {
return context.result;
}
const entityName = ApiSubscriberExecutor.resolveEntityName(entity, context);
const subscribers = registry_class.apiSubscriberRegistry.getRouteSubscribers(entityName, constructor, routeType, action ?? context.action);
let result = context.result;
for (const subscriber of subscribers) {
const hookName = ApiSubscriberExecutor.resolveHookName(onType, routeType);
const hook = Reflect.get(subscriber, hookName);
if (typeof hook === "function") {
subscriberLogger.verbose(`Executing route hook ${hookName} from ${subscriber.constructor.name} for entity ${entityName}`);
const hookResult = (await hook.call(subscriber, { ...context, result }));
if (hookResult !== undefined) {
result = hookResult;
}
}
}
return result;
}
static assertFunctionSubscribersTransactionExpectation(constructor, entity, functionType, onType, context, action) {
if (!Reflect.hasMetadata(service_constant.SERVICE_API_DECORATOR_CONSTANT.OBSERVABLE_METADATA_KEY, constructor)) {
return;
}
const entityName = ApiSubscriberExecutor.resolveEntityName(entity, context);
const subscribers = registry_class.apiSubscriberRegistry.getFunctionSubscribers(entityName, functionType, action ?? context.action);
for (const subscriber of subscribers) {
if (!ApiSubscriberExecutor.hasFunctionSubscriberHook(subscriber, onType, functionType)) {
continue;
}
const properties = registry_class.apiSubscriberRegistry.getFunctionSubscriberProperties(subscriber);
ApiSubscriberExecutor.assertFunctionSubscriberTransactionExpectation(subscriber.constructor.name, properties, context);
}
}
static assertFunctionSubscriberTransactionExpectation(subscriberName, properties, context) {
const transactionExpectation = properties?.transaction?.expectation;
if (transactionExpectation !== subscriberTransactionExpectation_enum.EApiFunctionSubscriberTransactionExpectation.MANDATORY && transactionExpectation !== subscriberTransactionExpectation_enum.EApiFunctionSubscriberTransactionExpectation.REQUIRED) {
return;
}
const eventManager = ApiSubscriberExecutor.resolveFunctionSubscriberEventManager(context);
if (eventManager === null || eventManager === undefined) {
throw exception_utility.ErrorException(`Function subscriber "${subscriberName}" declares transaction expectation "${transactionExpectation}" but no event manager was provided`);
}
}
static hasFunctionSubscriberHook(subscriber, onType, functionType) {
return typeof subscriber[ApiSubscriberExecutor.resolveHookName(onType, functionType)] === "function";
}
static resolveEntityName(entity, context) {
const data = context?.DATA;
const entityMetadataName = data && typeof data === "object" && "entityMetadata" in data ? data.entityMetadata?.name : undefined;
if (typeof entityMetadataName === "string" && entityMetadataName.length > 0) {
return entityMetadataName;
}
const propertyEntityName = data && typeof data === "object" && "properties" in data ? data.properties?.entity?.name : undefined;
if (typeof propertyEntityName === "string" && propertyEntityName.length > 0) {
return propertyEntityName;
}
const repositoryName = data && typeof data === "object" && "repository" in data ? (data.repository?.metadata?.name ?? data.repository?.target?.name) : undefined;
if (typeof repositoryName === "string" && repositoryName.length > 0) {
return repositoryName;
}
return entity.constructor.name;
}
static resolveFunctionSubscriberEventManager(context) {
const data = context.DATA;
return data && typeof data === "object" && "eventManager" in data ? data.eventManager : undefined;
}
static resolveHookName(onType, lifecycleType) {
return lifecycleType === undefined || lifecycleType === type_enum.EApiFunctionType.CUSTOM ? `on${onType}Custom` : `on${onType}${camelCaseString_utility.CamelCaseString(lifecycleType)}`;
}
}
exports.ApiSubscriberExecutor = ApiSubscriberExecutor;
//# sourceMappingURL=executor.class.js.map