UNPKG

@elsikora/nestjs-crud-automator

Version:

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

223 lines (220 loc) 12.1 kB
import { TRANSFORMER_VALUE_DTO_CONSTANT } from '../../../constant/dto/transformer-value.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 { EApiControllerRequestTarget } from '../../../enum/decorator/api/controller/request/target.enum.js'; import { EApiControllerRequestTransformerType } from '../../../enum/decorator/api/controller/request/transformer-type.enum.js'; import { EApiControllerResponseTarget } from '../../../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 '../../../enum/decorator/api/function/transaction/mode.enum.js'; import '../../../enum/decorator/api/function/transaction/outcome.enum.js'; import '../../../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 { EErrorStringAction } from '../../../enum/utility/error-string/action.enum.js'; import '../../../enum/utility/error-string/composite-action.enum.js'; import '../../../enum/utility/exception-details-type.enum.js'; import '../../../enum/utility/get-default-string-format-properties-bigint-string-sign.enum.js'; import '../../../enum/utility/manual-dto-property-metadata-decorator.enum.js'; import { InternalServerErrorException } from '@nestjs/common'; import { ErrorString } from '../../error/string.utility.js'; /** * Transforms data between request/response objects and entity objects. * Handles both static and dynamic transformations for body, query, parameters, and response data. * @template E - The entity type. * @param {object | undefined} targets - Target-specific transformer configuration. * @param {IApiControllerProperties<E>} properties - Controller configuration properties * @param {TApiControllerTransformDataObjectToTransform<E>} objectToTransform - The object to apply transformations to * @param {TApiControllerTransformDataData} data - Data sources to use for transformations including headers, IP address, and authentication * @returns {void} */ function ApiControllerTransformData(targets, properties, objectToTransform, data) { if (!targets) return; if (EApiControllerRequestTarget.BODY in targets && targets[EApiControllerRequestTarget.BODY]?.transformers) { for (const transformer of targets[EApiControllerRequestTarget.BODY].transformers) { if (objectToTransform.body) processTransformer(transformer, objectToTransform.body, properties, data); } } if (EApiControllerRequestTarget.QUERY in targets && targets[EApiControllerRequestTarget.QUERY]?.transformers) { for (const transformer of targets[EApiControllerRequestTarget.QUERY].transformers) { if (objectToTransform.query) processTransformer(transformer, objectToTransform.query, properties, data); } } if (EApiControllerRequestTarget.PARAMETERS in targets && targets[EApiControllerRequestTarget.PARAMETERS]?.transformers) { for (const transformer of targets[EApiControllerRequestTarget.PARAMETERS].transformers) { if (objectToTransform.parameters) processTransformer(transformer, objectToTransform.parameters, properties, data); } } if (EApiControllerResponseTarget.RESPONSE in targets && targets[EApiControllerResponseTarget.RESPONSE]?.transformers) { for (const transformer of targets[EApiControllerResponseTarget.RESPONSE].transformers) { if (objectToTransform.response) processTransformer(transformer, objectToTransform.response, properties, data); } } } /** * Handles transformation of object properties, setting values with appropriate type handling. * @param {TApiTransformDataIsValidationProperties<E>} object - The object to transform * @param {keyof E | keyof IApiGetListResponseResult<E> | keyof TApiControllerGetListQuery<E>} key - The property key * @param {unknown} value - The value to set * @param {IApiBaseEntity} entity - The entity metadata * @param {boolean} [shouldSetValueEvenIfMissing] - Whether to set the value even if the key is missing * @returns {void} * @throws {InternalServerErrorException} When key not found in object and not forced * @private */ function handleTransformation(object, key, value, entity, shouldSetValueEvenIfMissing = false) { if (isApiGetListResponseResult(object)) { if (key in object) { object[key] = value; } } else if (isApiFunctionGetListProperties(object)) { if (key in object) { object[key] = value; } } else if (isPartialE(object) && key in object) { object[key] = value; } else if (shouldSetValueEvenIfMissing) { object[key] = value; } else { throw new InternalServerErrorException(ErrorString({ entity, type: EErrorStringAction.KEY_FOR_TRANSFORM_NOT_IN_OBJECT, })); } } /** * Checks if an object is a get list query properties instance. * @param {TApiTransformDataIsValidationProperties<E>} object - The object to check * @returns {boolean} True if the object is a get list query object * @private */ function isApiFunctionGetListProperties(object) { return "limit" in object && "page" in object; } /** * Checks if an object is a get list response result instance. * @param {TApiTransformDataIsValidationProperties<E>} object - The object to check * @returns {boolean} True if the object is a get list response result * @private */ function isApiGetListResponseResult(object) { return "items" in object && "totalCount" in object; } /** * Checks if an object is a partial entity instance. * @param {TApiTransformDataIsValidationProperties<E>} object - The object to check * @returns {boolean} True if the object is a partial entity * @private */ function isPartialE(object) { return !isApiGetListResponseResult(object) && !isApiFunctionGetListProperties(object); } /** * Processes a single transformer, applying the transformation to the object. * Handles both static and dynamic transformations including special values like user, IP, and headers. * @param {TApiRequestTransformer<E>} transformer - The transformer configuration * @param {TApiTransformDataIsValidationProperties<E>} objectToTransform - The object to transform * @param {IApiControllerProperties<E>} properties - Controller configuration properties * @param {TApiControllerTransformDataData} data - The data sources for transformation * @returns {void} * @throws {InternalServerErrorException} When required data for transformation is missing * @private */ function processTransformer(transformer, objectToTransform, properties, data) { switch (transformer.type) { case EApiControllerRequestTransformerType.DYNAMIC: { if (Object.values(TRANSFORMER_VALUE_DTO_CONSTANT).includes(transformer.value)) { switch (transformer.value) { case TRANSFORMER_VALUE_DTO_CONSTANT.AUTHORIZED_ENTITY: { if (!data.authenticationRequest) { throw new InternalServerErrorException(ErrorString({ entity: properties.entity, type: EErrorStringAction.AUTHORIZED_ENTITY_NOT_FOUND, })); } handleTransformation(objectToTransform, transformer.key, data.authenticationRequest.user, properties.entity, transformer.shouldSetValueEvenIfMissing); break; } case TRANSFORMER_VALUE_DTO_CONSTANT.REQUEST_IP: { handleTransformation(objectToTransform, transformer.key, data.ip, properties.entity, transformer.shouldSetValueEvenIfMissing); break; } case TRANSFORMER_VALUE_DTO_CONSTANT.REQUEST_SIGNATURE: { if (!data.headers["x-signature"]) { throw new InternalServerErrorException(ErrorString({ entity: properties.entity, type: EErrorStringAction.REQUEST_SIGNATURE_NOT_FOUND, })); } handleTransformation(objectToTransform, transformer.key, data.headers["x-signature"], properties.entity, transformer.shouldSetValueEvenIfMissing); break; } case TRANSFORMER_VALUE_DTO_CONSTANT.REQUEST_TIMESTAMP: { if (!data.headers["x-timestamp"]) { throw new InternalServerErrorException(ErrorString({ entity: properties.entity, type: EErrorStringAction.REQUEST_TIMESTAMP_NOT_FOUND, })); } handleTransformation(objectToTransform, transformer.key, data.headers["x-timestamp"], properties.entity, transformer.shouldSetValueEvenIfMissing); break; } case TRANSFORMER_VALUE_DTO_CONSTANT.REQUEST_USER_AGENT: { if (!data.headers["user-agent"]) { throw new InternalServerErrorException(ErrorString({ entity: properties.entity, type: EErrorStringAction.REQUEST_USER_AGENT_NOT_FOUND, })); } handleTransformation(objectToTransform, transformer.key, data.headers["user-agent"], properties.entity, transformer.shouldSetValueEvenIfMissing); break; } default: { throw new InternalServerErrorException(ErrorString({ entity: properties.entity, type: EErrorStringAction.INVALID_DYNAMIC_VALUE_SPECIFIED, })); } } } else { throw new InternalServerErrorException(ErrorString({ entity: properties.entity, type: EErrorStringAction.INVALID_DYNAMIC_VALUE_SPECIFIED, })); } break; } case EApiControllerRequestTransformerType.STATIC: { const staticValue = transformer.value; handleTransformation(objectToTransform, transformer.key, staticValue, properties.entity, transformer.shouldSetValueEvenIfMissing); break; } } } export { ApiControllerTransformData }; //# sourceMappingURL=transform-data.utility.js.map