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