diff --git a/src/space-model/dtos/subspaces-model-dtos/modify-subspace-model.dto.ts b/src/space-model/dtos/subspaces-model-dtos/modify-subspace-model.dto.ts index 9b5a2a5..cbf021c 100644 --- a/src/space-model/dtos/subspaces-model-dtos/modify-subspace-model.dto.ts +++ b/src/space-model/dtos/subspaces-model-dtos/modify-subspace-model.dto.ts @@ -1,15 +1,22 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; -import { IsString, IsOptional, IsArray, ValidateNested } from 'class-validator'; +import { + IsString, + IsOptional, + IsArray, + ValidateNested, + IsEnum, +} from 'class-validator'; import { ModifyTagModelDto } from '../tag-model-dtos'; +import { ModifyAction } from '@app/common/constants/modify-action.enum'; export class ModifySubspaceModelDto { @ApiProperty({ description: 'Action to perform: add, update, or delete', - example: 'add', + example: ModifyAction.ADD, }) - @IsString() - action: 'add' | 'update' | 'delete'; + @IsEnum(ModifyAction) + action: ModifyAction; @ApiPropertyOptional({ description: 'UUID of the subspace (required for update/delete)', diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts index 8e08ae3..23e5d51 100644 --- a/src/space-model/services/space-model.service.ts +++ b/src/space-model/services/space-model.service.ts @@ -171,7 +171,7 @@ export class SpaceModelService { async validateName(modelName: string, projectUuid: string): Promise { const isModelExist = await this.spaceModelRepository.findOne({ - where: { modelName, project: { uuid: projectUuid } }, + where: { modelName, project: { uuid: projectUuid }, disabled: false }, }); if (isModelExist) { @@ -186,6 +186,7 @@ export class SpaceModelService { const spaceModel = await this.spaceModelRepository.findOne({ where: { uuid, + disabled: true, }, }); if (!spaceModel) { diff --git a/src/space-model/services/subspace/subspace-model.service.ts b/src/space-model/services/subspace/subspace-model.service.ts index 4c57673..0f59a0d 100644 --- a/src/space-model/services/subspace/subspace-model.service.ts +++ b/src/space-model/services/subspace/subspace-model.service.ts @@ -19,6 +19,7 @@ import { ModifySubspaceModelDto, } from 'src/space-model/dtos/subspaces-model-dtos'; import { TagModelService } from '../tag-model.service'; +import { ModifyAction } from '@app/common/constants/modify-action.enum'; @Injectable() export class SubSpaceModelService { @@ -35,94 +36,223 @@ export class SubSpaceModelService { ): Promise { this.validateInputDtos(subSpaceModelDtos); - try { - const subspaces = subSpaceModelDtos.map((subspaceDto) => - queryRunner.manager.create(this.subspaceModelRepository.target, { - subspaceName: subspaceDto.subspaceName, - spaceModel, - }), - ); + const subspaces = subSpaceModelDtos.map((subspaceDto) => + queryRunner.manager.create(this.subspaceModelRepository.target, { + subspaceName: subspaceDto.subspaceName, + spaceModel, + }), + ); - const savedSubspaces = await queryRunner.manager.save(subspaces); + const savedSubspaces = await queryRunner.manager.save(subspaces); - await Promise.all( - subSpaceModelDtos.map(async (dto, index) => { - const subspace = savedSubspaces[index]; + await Promise.all( + subSpaceModelDtos.map(async (dto, index) => { + const subspace = savedSubspaces[index]; + if (dto.tags?.length) { + subspace.tags = await this.tagModelService.createTags( + dto.tags, + queryRunner, + null, + subspace, + otherTags, + ); + } + }), + ); - if (dto.tags && dto.tags.length > 0) { - const tagModels = await this.tagModelService.createTags( - dto.tags, - queryRunner, - null, - subspace, - otherTags, - ); - subspace.tags = tagModels; - } - }), - ); - - return savedSubspaces; - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - throw new HttpException( - error.message || 'Failed to create subspaces.', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } + return savedSubspaces; } async updateSubspaceModels( updateDtos: UpdateSubspaceModelDto[], - spaceModel: SpaceModelEntity, queryRunner: QueryRunner, ): Promise { - try { - const updateResults: IUpdateSubspaceModelInterface[] = []; + const updateResults: IUpdateSubspaceModelInterface[] = []; - const updatePromises = updateDtos.map(async (dto) => { - try { - const subspaceModel = await this.findOne(dto.subspaceUuid); + for (const dto of updateDtos) { + await this.findOne(dto.subspaceUuid); + const updateResult: IUpdateSubspaceModelInterface = { + uuid: dto.subspaceUuid, + }; - if (!subspaceModel) { - throw new HttpException( - `Subspace model with UUID ${dto.subspaceUuid} not found.`, - HttpStatus.NOT_FOUND, - ); - } + if (dto.subspaceName) { + await this.updateSubspaceName( + dto.subspaceUuid, + dto.subspaceName, + queryRunner, + ); + updateResult.subspaceName = dto.subspaceName; + } - const updateResult: IUpdateSubspaceModelInterface = { - uuid: dto.subspaceUuid, - }; + updateResults.push(updateResult); + } - if (dto.subspaceName) { - await this.updateSubspaceName( - dto.subspaceUuid, - dto.subspaceName, - queryRunner, - ); - subspaceModel.subspaceName = dto.subspaceName; - updateResult.subspaceName = dto.subspaceName; - } + return updateResults; + } - updateResults.push(updateResult); - } catch (error) { + async deleteSubspaceModels( + deleteDtos: DeleteSubspaceModelDto[], + queryRunner: QueryRunner, + ): Promise { + const deleteResults: IDeletedSubsaceModelInterface[] = []; + + for (const dto of deleteDtos) { + const subspaceModel = await this.findOne(dto.subspaceUuid); + + await queryRunner.manager.update( + this.subspaceModelRepository.target, + { uuid: dto.subspaceUuid }, + { disabled: true }, + ); + + if (subspaceModel.tags?.length) { + const modifyTagDtos = subspaceModel.tags.map((tag) => ({ + uuid: tag.uuid, + action: ModifyAction.DELETE, + })); + await this.tagModelService.modifyTags( + modifyTagDtos, + queryRunner, + null, + subspaceModel, + ); + } + + deleteResults.push({ uuid: dto.subspaceUuid }); + } + + return deleteResults; + } + + async modifySubSpaceModels( + subspaceDtos: ModifySubspaceModelDto[], + spaceModel: SpaceModelEntity, + queryRunner: QueryRunner, + ): Promise { + for (const subspace of subspaceDtos) { + switch (subspace.action) { + case ModifyAction.ADD: + await this.handleAddAction(subspace, spaceModel, queryRunner); + break; + case ModifyAction.UPDATE: + await this.handleUpdateAction(subspace, queryRunner); + break; + case ModifyAction.DELETE: + await this.handleDeleteAction(subspace, queryRunner); + break; + default: throw new HttpException( - `Failed to update subspace model with UUID ${dto.subspaceUuid}: ${error.message}`, - HttpStatus.INTERNAL_SERVER_ERROR, + `Invalid action "${subspace.action}".`, + HttpStatus.BAD_REQUEST, ); - } - }); + } + } + } - await Promise.all(updatePromises); + private async handleAddAction( + subspace: ModifySubspaceModelDto, + spaceModel: SpaceModelEntity, + queryRunner: QueryRunner, + ): Promise { + const createTagDtos: CreateTagModelDto[] = + subspace.tags?.map((tag) => ({ + tag: tag.tag as string, + productUuid: tag.productUuid as string, + })) || []; + await this.createSubSpaceModels( + [{ subspaceName: subspace.subspaceName, tags: createTagDtos }], + spaceModel, + queryRunner, + ); + } - return updateResults; - } catch (error) { + private async handleUpdateAction( + subspace: ModifySubspaceModelDto, + queryRunner: QueryRunner, + ): Promise { + const existingSubspace = await this.findOne(subspace.uuid); + + if (subspace.subspaceName) { + existingSubspace.subspaceName = subspace.subspaceName; + await queryRunner.manager.save(existingSubspace); + } + + if (subspace.tags?.length) { + await this.tagModelService.modifyTags( + subspace.tags, + queryRunner, + null, + existingSubspace, + ); + } + } + + private async handleDeleteAction( + subspace: ModifySubspaceModelDto, + queryRunner: QueryRunner, + ): Promise { + const subspaceModel = await this.findOne(subspace.uuid); + + await queryRunner.manager.update( + this.subspaceModelRepository.target, + { uuid: subspace.uuid }, + { disabled: true }, + ); + + if (subspaceModel.tags?.length) { + const modifyTagDtos = subspaceModel.tags.map((tag) => ({ + uuid: tag.uuid, + action: ModifyAction.DELETE, + })); + await this.tagModelService.modifyTags( + modifyTagDtos, + queryRunner, + null, + subspaceModel, + ); + } + } + + private async findOne(subspaceUuid: string): Promise { + const subspace = await this.subspaceModelRepository.findOne({ + where: { uuid: subspaceUuid }, + relations: ['tags'], + }); + if (!subspace) { throw new HttpException( - error.message || 'Failed to update subspace models.', - HttpStatus.INTERNAL_SERVER_ERROR, + `SubspaceModel with UUID ${subspaceUuid} not found.`, + HttpStatus.NOT_FOUND, + ); + } + return subspace; + } + + private validateInputDtos(subSpaceModelDtos: CreateSubspaceModelDto[]): void { + if (subSpaceModelDtos.length === 0) { + throw new HttpException( + 'Subspace models cannot be empty.', + HttpStatus.BAD_REQUEST, + ); + } + this.validateName(subSpaceModelDtos.map((dto) => dto.subspaceName)); + } + + private validateName(names: string[]): void { + const seenNames = new Set(); + const duplicateNames = new Set(); + + for (const name of names) { + if (seenNames.has(name)) { + duplicateNames.add(name); + } else { + seenNames.add(name); + } + } + + if (duplicateNames.size > 0) { + throw new HttpException( + `Duplicate subspace names found: ${[...duplicateNames].join(', ')}`, + HttpStatus.CONFLICT, ); } } @@ -138,146 +268,4 @@ export class SubSpaceModelService { { subspaceName }, ); } - - async deleteSubspaceModels( - deleteDtos: DeleteSubspaceModelDto[], - queryRunner: QueryRunner, - ): Promise { - try { - const deleteResults: IDeletedSubsaceModelInterface[] = []; - - const deletePromises = deleteDtos.map(async (dto) => { - try { - const subspaceModel = await this.findOne(dto.subspaceUuid); - - if (!subspaceModel) { - throw new HttpException( - `Subspace model with UUID ${dto.subspaceUuid} not found.`, - HttpStatus.NOT_FOUND, - ); - } - - await queryRunner.manager.update( - this.subspaceModelRepository.target, - { uuid: dto.subspaceUuid }, - { disabled: true }, - ); - - deleteResults.push({ uuid: dto.subspaceUuid }); - } catch (error) { - throw new HttpException( - `Failed to delete subspace model with UUID ${dto.subspaceUuid}: ${error.message}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - }); - - await Promise.all(deletePromises); - - return deleteResults; - } catch (error) { - throw new HttpException( - 'Bulk delete operation failed. Please try again.', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async findOne(subspaceUuid: string) { - const subspace = await this.subspaceModelRepository.findOne({ - where: { - uuid: subspaceUuid, - }, - }); - if (!subspace) { - throw new HttpException( - `SubspaceModel with ${subspaceUuid} not found`, - HttpStatus.NOT_FOUND, - ); - } - return subspace; - } - - private validateInputDtos(subSpaceModelDtos: CreateSubspaceModelDto[]) { - if (subSpaceModelDtos.length === 0) { - throw new HttpException( - 'Subspace models cannot be empty.', - HttpStatus.BAD_REQUEST, - ); - } - const incomingNames = subSpaceModelDtos.map((dto) => dto.subspaceName); - this.validateName(incomingNames); - } - - private validateName(names: string[]) { - const seenNames = new Set(); - const duplicateNames = new Set(); - - for (const name of names) { - if (seenNames.has(name)) { - duplicateNames.add(name); - } else { - seenNames.add(name); - } - } - - if (duplicateNames.size > 0) { - throw new HttpException( - `Duplicate subspace names found in request: ${[...duplicateNames].join(', ')}`, - HttpStatus.CONFLICT, - ); - } - } - - async modifySubSpaceModels( - subspaceDtos: ModifySubspaceModelDto[], - spaceModel: SpaceModelEntity, - queryRunner: QueryRunner, - ) { - try { - for (const subspace of subspaceDtos) { - if (subspace.action === 'add') { - const createTagDtos: CreateTagModelDto[] = - subspace.tags?.map((tag) => ({ - tag: tag.tag as string, - productUuid: tag.productUuid as string, - })) || []; - await this.createSubSpaceModels( - [{ subspaceName: subspace.subspaceName, tags: createTagDtos }], - spaceModel, - queryRunner, - ); - } else if (subspace.action === 'update') { - const existingSubspace = await this.findOne(subspace.uuid); - - if (!existingSubspace) { - throw new HttpException( - `Subspace with ID ${subspace.uuid} not found.`, - HttpStatus.NOT_FOUND, - ); - } - - existingSubspace.subspaceName = - subspace.subspaceName || existingSubspace.subspaceName; - - const updatedSubspace = - await queryRunner.manager.save(existingSubspace); - - if (subspace.tags) { - await this.tagModelService.modifyTags( - subspace.tags, - queryRunner, - null, - updatedSubspace, - ); - } - } - } - } catch (error) { - throw new HttpException( - error.message || 'Failed to modify SpaceModels', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } } diff --git a/src/space-model/services/tag-model.service.ts b/src/space-model/services/tag-model.service.ts index 21be316..500eed1 100644 --- a/src/space-model/services/tag-model.service.ts +++ b/src/space-model/services/tag-model.service.ts @@ -8,6 +8,7 @@ import { SubspaceModelEntity } from '@app/common/modules/space-model/entities'; import { TagModelRepository } from '@app/common/modules/space-model'; import { CreateTagModelDto, ModifyTagModelDto } from '../dtos'; import { ProductService } from 'src/product/services'; +import { ModifyAction } from '@app/common/constants/modify-action.enum'; @Injectable() export class TagModelService { @@ -133,8 +134,9 @@ export class TagModelService { subspaceModel?: SubspaceModelEntity, ): Promise { try { + console.log(tags); for (const tag of tags) { - if (tag.action === 'add') { + if (tag.action === ModifyAction.ADD) { const createTagDto: CreateTagModelDto = { tag: tag.tag as string, productUuid: tag.productUuid as string, @@ -146,9 +148,9 @@ export class TagModelService { spaceModel, subspaceModel, ); - } else if (tag.action === 'update') { + } else if (tag.action === ModifyAction.UPDATE) { await this.updateTag(tag, queryRunner, spaceModel, subspaceModel); - } else if (tag.action === 'delete') { + } else if (tag.action === ModifyAction.DELETE) { await queryRunner.manager.update( this.tagModelRepository.target, { uuid: tag.uuid },