UNPKG

@elsikora/nestjs-crud-automator

Version:

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

195 lines (191 loc) 11.6 kB
'use strict'; require('../../constant/decorator/api/function.constant.js'); var propertyDescribe_constant = require('../../constant/decorator/api/property-describe.constant.js'); var generate_constant = require('../../constant/utility/dto/generate.constant.js'); require('../../enum/decorator/api/action.enum.js'); require('../../enum/decorator/api/authentication-type.enum.js'); require('../../enum/decorator/api/controller/load-relations-strategy.enum.js'); require('../../enum/decorator/api/controller/request-transformer-type.enum.js'); var dtoType_enum = require('../../enum/decorator/api/dto-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'); var desribeType_enum = 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'); var routeType_enum = require('../../enum/decorator/api/route-type.enum.js'); var swagger = require('@nestjs/swagger'); var camelCaseString_utility = require('../camel-case-string.utility.js'); var buildDecorator_utility = require('./build-decorator.utility.js'); var generateCacheKey_utility = require('./generate-cache-key.utility.js'); var generateDynamic_utility = require('./generate-dynamic.utility.js'); var generateFilterDecorator_utility = require('./generate-filter-decorator.utility.js'); var generateGetListResponse_utility = require('./generate-get-list-response.utility.js'); var getGetListQueryBaseClass_utility = require('./get-get-list-query-base-class.utility.js'); var isPropertyShouldBeMarked_utility = require('./is-property-should-be-marked.utility.js'); var isShouldBeGenerated_utility = require('./is-should-be-generated.utility.js'); var errorException_utility = require('../error-exception.utility.js'); var hasPairedCustomSuffixesFields_validator = require('../../validator/has-paired-custom-suffixes-fields.validator.js'); var classValidator = require('class-validator'); const dtoGenerateCache = new Map(); /** * Core utility for DTO generation that determines which properties should be included in the DTO. * Builds decorators, handles special cases like filter queries, and generates the appropriate class * based on entity metadata, route type, and DTO type. * @param {ObjectLiteral} entity - The entity class or prototype * @param {IApiEntity<E>} entityMetadata - The entity metadata containing column information * @param {EApiRouteType} method - The API route type (CREATE, DELETE, GET, etc.) * @param {EApiDtoType} dtoType - The type of DTO (REQUEST, RESPONSE, etc.) * @param {IApiControllerPropertiesRouteAutoDtoConfig} [dtoConfig] - Optional configuration for automatic DTO generation * @param {Type<IAuthGuard>} [currentGuard] - Optional authentication guard for property visibility control * @returns {Type<unknown> | undefined} The generated DTO class or undefined if no DTO should be generated * @throws {Error} When primary key metadata is missing * @template E - The entity type */ function DtoGenerate(entity, entityMetadata, method, dtoType, dtoConfig, currentGuard) { if (!isShouldBeGenerated_utility.DtoIsShouldBeGenerated(method, dtoType)) { return undefined; } const cacheKey = generateCacheKey_utility.DtoGenerateCacheKey({ dtoConfig, dtoType, entityName: String(entityMetadata.name), guardName: currentGuard?.name, method, }); const cached = dtoGenerateCache.get(cacheKey); if (cached) { return cached; } if (!entityMetadata.primaryKey?.metadata?.[propertyDescribe_constant.PROPERTY_DESCRIBE_DECORATOR_API_CONSTANT.METADATA_KEY]) { throw errorException_utility.ErrorException(`Primary key for entity ${String(entityMetadata.name)} not found in metadata storage`); } // eslint-disable-next-line @elsikora/typescript/no-unsafe-function-type const extraModels = []; const markedProperties = []; for (const column of entityMetadata.columns) { if (column.metadata?.[propertyDescribe_constant.PROPERTY_DESCRIBE_DECORATOR_API_CONSTANT.METADATA_KEY] && isPropertyShouldBeMarked_utility.DtoIsPropertyShouldBeMarked(method, dtoType, column.name, column.metadata[propertyDescribe_constant.PROPERTY_DESCRIBE_DECORATOR_API_CONSTANT.METADATA_KEY], column.isPrimary, currentGuard)) { markedProperties.push({ isPrimary: column.isPrimary, metadata: column.metadata[propertyDescribe_constant.PROPERTY_DESCRIBE_DECORATOR_API_CONSTANT.METADATA_KEY], name: column.name, }); } } const BaseClass = method === routeType_enum.EApiRouteType.GET_LIST && dtoType === dtoType_enum.EApiDtoType.QUERY ? getGetListQueryBaseClass_utility.DtoGetGetListQueryBaseClass(entity, entityMetadata, method, dtoType) : class { }; class GeneratedDTO extends BaseClass { constructor() { super(); for (const property of markedProperties) { if (method === routeType_enum.EApiRouteType.GET_LIST && dtoType === dtoType_enum.EApiDtoType.QUERY) { Object.defineProperty(this, `${property.name}[value]`, { // eslint-disable-next-line @elsikora/typescript/naming-convention configurable: true, // eslint-disable-next-line @elsikora/typescript/naming-convention enumerable: true, value: undefined, // eslint-disable-next-line @elsikora/typescript/naming-convention writable: true, }); Object.defineProperty(this, `${property.name}[values]`, { // eslint-disable-next-line @elsikora/typescript/naming-convention configurable: true, // eslint-disable-next-line @elsikora/typescript/naming-convention enumerable: true, value: undefined, // eslint-disable-next-line @elsikora/typescript/naming-convention writable: true, }); Object.defineProperty(this, `${property.name}[operator]`, { // eslint-disable-next-line @elsikora/typescript/naming-convention configurable: true, // eslint-disable-next-line @elsikora/typescript/naming-convention enumerable: true, value: undefined, // eslint-disable-next-line @elsikora/typescript/naming-convention writable: true, }); } else { Object.defineProperty(this, property.name, { // eslint-disable-next-line @elsikora/typescript/naming-convention configurable: true, // eslint-disable-next-line @elsikora/typescript/naming-convention enumerable: true, value: undefined, // eslint-disable-next-line @elsikora/typescript/naming-convention writable: true, }); } } } } for (const property of markedProperties) { const generatedDTOs = generateDynamic_utility.DtoGenerateDynamic(method, property.metadata, entityMetadata, dtoType, property.name, currentGuard); const decorators = buildDecorator_utility.DtoBuildDecorator(method, property.metadata, entityMetadata, dtoType, property.name, currentGuard, generatedDTOs); if (decorators) { for (const [, decorator] of decorators.entries()) { if (method === routeType_enum.EApiRouteType.GET_LIST && dtoType === dtoType_enum.EApiDtoType.QUERY) { decorator(GeneratedDTO.prototype, `${property.name}[value]`); generateFilterDecorator_utility.DtoGenerateFilterDecorator(property.metadata, entityMetadata)(GeneratedDTO.prototype, `${property.name}[operator]`); } else { decorator(GeneratedDTO.prototype, property.name); } } } if (method === routeType_enum.EApiRouteType.GET_LIST && dtoType === dtoType_enum.EApiDtoType.QUERY) { // @ts-ignore const metadataArray = { ...property.metadata, isArray: true, isUniqueItems: false, maxItems: generate_constant.DTO_GENERATE_CONSTANT.MAXIMUM_FILTER_PROPERTIES, minItems: generate_constant.DTO_GENERATE_CONSTANT.MINIMUM_FILTER_PROPERTIES }; const decoratorsArray = buildDecorator_utility.DtoBuildDecorator(method, metadataArray, entityMetadata, dtoType, property.name, currentGuard); if (decoratorsArray) { for (const [, decorator] of decoratorsArray.entries()) { decorator(GeneratedDTO.prototype, `${property.name}[values]`); } } } if (property.metadata.type === desribeType_enum.EApiPropertyDescribeType.OBJECT && Array.isArray(property.metadata.dataType)) { // @ts-ignore extraModels.push(...property.metadata.dataType); } if (generatedDTOs) { for (const [, value] of Object.entries(generatedDTOs)) { extraModels.push(value); } } } if (dtoConfig?.validators) { for (const validator of dtoConfig.validators) { classValidator.Validate(validator.constraintClass, validator.options)(GeneratedDTO.prototype, "object"); } } if (method === routeType_enum.EApiRouteType.GET_LIST && dtoType === dtoType_enum.EApiDtoType.QUERY) { Object.defineProperty(GeneratedDTO.prototype, "object", { // eslint-disable-next-line @elsikora/typescript/naming-convention configurable: true, // eslint-disable-next-line @elsikora/typescript/naming-convention enumerable: true, value: function () { return this; }, // eslint-disable-next-line @elsikora/typescript/naming-convention writable: true, }); classValidator.Validate(hasPairedCustomSuffixesFields_validator.HasPairedCustomSuffixesFieldsValidator, ["operator", ["value", "values"]])(GeneratedDTO.prototype, "object"); } if (extraModels.length > 0) { swagger.ApiExtraModels(...extraModels)(GeneratedDTO); } Object.defineProperty(GeneratedDTO, "name", { value: `${entityMetadata.name ?? "UnknownResource"}${camelCaseString_utility.CamelCaseString(method)}${camelCaseString_utility.CamelCaseString(dtoType)}DTO`, }); // @ts-ignore const result = method === routeType_enum.EApiRouteType.GET_LIST && dtoType === dtoType_enum.EApiDtoType.RESPONSE ? generateGetListResponse_utility.DtoGenerateGetListResponse(entity, GeneratedDTO, `${entityMetadata.name ?? "UnknownResource"}${camelCaseString_utility.CamelCaseString(method)}${camelCaseString_utility.CamelCaseString(dtoType)}ItemsDTO`) : GeneratedDTO; dtoGenerateCache.set(cacheKey, result); return result; } exports.DtoGenerate = DtoGenerate; //# sourceMappingURL=generate.utility.js.map