diff --git a/src/space-model/controllers/space-model.controller.ts b/src/space-model/controllers/space-model.controller.ts index 57e2db6..808cf3c 100644 --- a/src/space-model/controllers/space-model.controller.ts +++ b/src/space-model/controllers/space-model.controller.ts @@ -70,9 +70,9 @@ export class SpaceModelController { @UseGuards(PermissionsGuard) @Permissions('SPACE_MODEL_VIEW') @ApiOperation({ - summary: ControllerRoute.SPACE_MODEL.ACTIONS.LIST_SPACE_MODEL_SUMMARY, + summary: ControllerRoute.SPACE_MODEL.ACTIONS.GET_SPACE_MODEL_SUMMARY, description: - ControllerRoute.SPACE_MODEL.ACTIONS.LIST_SPACE_MODEL_DESCRIPTION, + ControllerRoute.SPACE_MODEL.ACTIONS.GET_SPACE_MODEL_DESCRIPTION, }) @Get(':spaceModelUuid') async get(@Param() param: SpaceModelParam): Promise { diff --git a/src/space-model/dtos/space-model-param.ts b/src/space-model/dtos/space-model-param.ts index 2111546..f775acc 100644 --- a/src/space-model/dtos/space-model-param.ts +++ b/src/space-model/dtos/space-model-param.ts @@ -3,7 +3,7 @@ import { IsUUID } from 'class-validator'; import { ProjectParam } from './project-param.dto'; export class SpaceModelParam extends ProjectParam { @ApiProperty({ - description: 'UUID of the Space', + description: 'UUID of the Space model', example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', }) @IsUUID() diff --git a/src/space-model/handlers/propate-subspace-handler.ts b/src/space-model/handlers/propate-subspace-handler.ts index d88abf8..1bd244d 100644 --- a/src/space-model/handlers/propate-subspace-handler.ts +++ b/src/space-model/handlers/propate-subspace-handler.ts @@ -10,7 +10,6 @@ import { import { DataSource, QueryRunner } from 'typeorm'; import { SubSpaceService } from 'src/space/services'; import { TagService } from 'src/space/services/tag'; -import { TagModelService } from '../services'; import { UpdatedSubspaceModelPayload } from '../interfaces'; import { ModifyAction } from '@app/common/constants/modify-action.enum'; import { ModifySubspaceDto } from 'src/space/dtos'; @@ -26,7 +25,6 @@ export class PropogateUpdateSpaceModelHandler private readonly dataSource: DataSource, private readonly subSpaceService: SubSpaceService, private readonly tagService: TagService, - private readonly tagModelService: TagModelService, ) {} async execute(command: PropogateUpdateSpaceModelCommand): Promise { diff --git a/src/space-model/services/index.ts b/src/space-model/services/index.ts index 20dca88..9999493 100644 --- a/src/space-model/services/index.ts +++ b/src/space-model/services/index.ts @@ -1,3 +1,2 @@ export * from './space-model.service'; export * from './subspace'; -export * from './tag-model.service'; diff --git a/src/space-model/services/space-model-product-allocation.service.ts b/src/space-model/services/space-model-product-allocation.service.ts index 56bbb24..3d20b28 100644 --- a/src/space-model/services/space-model-product-allocation.service.ts +++ b/src/space-model/services/space-model-product-allocation.service.ts @@ -311,16 +311,6 @@ export class SpaceModelProductAllocationService { } } - private async getAllocationByTagUuid( - tagUuid: string, - queryRunner: QueryRunner, - ): Promise { - return queryRunner.manager.findOne(SpaceModelProductAllocationEntity, { - where: { tags: { uuid: tagUuid } }, - relations: ['tags'], - }); - } - private async validateTagWithinSpaceModel( queryRunner: QueryRunner, tag: NewTagEntity, @@ -351,4 +341,29 @@ export class SpaceModelProductAllocationService { ); } } + + async clearAllAllocations(spaceModelUuid: string, queryRunner: QueryRunner) { + try { + await queryRunner.manager + .createQueryBuilder() + .delete() + .from(SpaceModelProductAllocationEntity, 'allocation') + .relation(SpaceModelProductAllocationEntity, 'tags') + .of( + await queryRunner.manager.find(SpaceModelProductAllocationEntity, { + where: { spaceModel: { uuid: spaceModelUuid } }, + }), + ) + .execute(); + + await queryRunner.manager + .createQueryBuilder() + .delete() + .from(SpaceModelProductAllocationEntity) + .where('spaceModelUuid = :spaceModelUuid', { spaceModelUuid }) + .execute(); + } catch (error) { + throw this.handleError(error, `Failed to clear all allocations`); + } + } } diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts index 26dd6fe..a402a5b 100644 --- a/src/space-model/services/space-model.service.ts +++ b/src/space-model/services/space-model.service.ts @@ -1,30 +1,24 @@ import { SpaceModelEntity, + SpaceModelProductAllocationEntity, SpaceModelRepository, + SubspaceModelProductAllocationEntity, } from '@app/common/modules/space-model'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { - CreateSpaceModelDto, - LinkSpacesToModelDto, - UpdateSpaceModelDto, -} from '../dtos'; +import { CreateSpaceModelDto, UpdateSpaceModelDto } from '../dtos'; import { ProjectParam } from 'src/community/dtos'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { SubSpaceModelService } from './subspace/subspace-model.service'; -import { DataSource, In, QueryRunner } from 'typeorm'; +import { DataSource, QueryRunner, SelectQueryBuilder } from 'typeorm'; import { TypeORMCustomModel, TypeORMCustomModelFindAllQuery, } from '@app/common/models/typeOrmCustom.model'; -import { PageResponse } from '@app/common/dto/pagination.response.dto'; import { SpaceModelParam } from '../dtos/space-model-param'; import { ProjectService } from 'src/project/services'; import { ProjectEntity } from '@app/common/modules/project/entities'; -import { TagModelService } from './tag-model.service'; import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { CommandBus } from '@nestjs/cqrs'; -import { SpaceModelDto } from '@app/common/modules/space-model/dtos'; -import { TagService as NewTagService } from 'src/tags/services'; import { ProcessTagDto } from 'src/tags/dtos'; import { SpaceModelProductAllocationService } from './space-model-product-allocation.service'; import { SpaceRepository } from '@app/common/modules/space'; @@ -36,9 +30,7 @@ export class SpaceModelService { private readonly spaceModelRepository: SpaceModelRepository, private readonly projectService: ProjectService, private readonly subSpaceModelService: SubSpaceModelService, - private readonly tagModelService: TagModelService, private commandBus: CommandBus, - private readonly tagService: NewTagService, private readonly spaceModelProductAllocationService: SpaceModelProductAllocationService, private readonly spaceRepository: SpaceRepository, ) {} @@ -134,34 +126,9 @@ export class SpaceModelService { disabled: false, }; pageable.include = - 'subspaceModels,tags,subspaceModels.tags,tags.product,subspaceModels.tags.product'; + 'subspaceModels.productAllocations,subspaceModelProductAllocations.tags,subspaceModels, productAllocations, productAllocations.tags'; - const queryBuilder = await this.spaceModelRepository - .createQueryBuilder('spaceModel') - .leftJoinAndSelect( - 'spaceModel.subspaceModels', - 'subspaceModels', - 'subspaceModels.disabled = :subspaceDisabled', - { subspaceDisabled: false }, - ) - .leftJoinAndSelect( - 'spaceModel.tags', - 'tags', - 'tags.disabled = :tagsDisabled', - { tagsDisabled: false }, - ) - .leftJoinAndSelect('tags.product', 'spaceTagproduct') - .leftJoinAndSelect( - 'subspaceModels.tags', - 'subspaceModelTags', - 'subspaceModelTags.disabled = :subspaceModelTagsDisabled', - { subspaceModelTagsDisabled: false }, - ) - .leftJoinAndSelect('subspaceModelTags.product', 'subspaceTagproduct') - .where('spaceModel.disabled = :disabled', { disabled: false }) - .andWhere('spaceModel.project = :projectUuid', { - projectUuid: param.projectUuid, - }); + const queryBuilder = this.buildSpaceModelQuery(param.projectUuid); const customModel = TypeORMCustomModel(this.spaceModelRepository); const { baseResponseDto, paginationResponseDto } = @@ -174,10 +141,14 @@ export class SpaceModelService { queryBuilder, ); - return new PageResponse( - baseResponseDto, - paginationResponseDto, - ); + const formattedData = this.transformSpaceModelData(baseResponseDto.data); + + return { + code: 200, + data: formattedData, + message: 'Success get list spaceModel', + ...paginationResponseDto, + }; } catch (error) { throw new HttpException( `Error fetching paginated list: ${error.message}`, @@ -193,7 +164,10 @@ export class SpaceModelService { async update(dto: UpdateSpaceModelDto, param: SpaceModelParam) { const queryRunner = this.dataSource.createQueryRunner(); await this.validateProject(param.projectUuid); - const spaceModel = await this.validateSpaceModel(param.spaceModelUuid); + const spaceModel = await this.validateSpaceModel( + param.spaceModelUuid, + param.projectUuid, + ); await queryRunner.connect(); try { @@ -259,7 +233,10 @@ export class SpaceModelService { try { await this.validateProject(param.projectUuid); - const spaceModel = await this.validateSpaceModel(param.spaceModelUuid); + const spaceModel = await this.validateSpaceModel( + param.spaceModelUuid, + param.projectUuid, + ); if (spaceModel.subspaceModels?.length) { const deleteSubspaceUuids = spaceModel.subspaceModels.map( @@ -272,10 +249,11 @@ export class SpaceModelService { ); } - if (spaceModel.tags?.length) { - const deleteSpaceTagsDtos = spaceModel.tags.map((tag) => tag.uuid); - - await this.tagModelService.deleteTags(deleteSpaceTagsDtos, queryRunner); + if (spaceModel.productAllocations?.length) { + await this.spaceModelProductAllocationService.clearAllAllocations( + spaceModel.uuid, + queryRunner, + ); } await queryRunner.manager.update( @@ -341,11 +319,15 @@ export class SpaceModelService { async findOne(params: SpaceModelParam): Promise { try { await this.validateProject(params.projectUuid); - const spaceModel = await this.validateSpaceModel(params.spaceModelUuid); + const spaceModel = await this.validateSpaceModel( + params.spaceModelUuid, + params.projectUuid, + ); + const response = this.formatSpaceModelResponse(spaceModel); return new SuccessResponseDto({ message: 'SpaceModel retrieved successfully', - data: spaceModel, + data: response, }); } catch (error) { throw new HttpException( @@ -355,38 +337,19 @@ export class SpaceModelService { } } - async validateSpaceModel(uuid: string): Promise { - const spaceModel = await this.spaceModelRepository - .createQueryBuilder('spaceModel') - .leftJoinAndSelect( - 'spaceModel.subspaceModels', - 'subspaceModels', - 'subspaceModels.disabled = :subspaceDisabled', - { subspaceDisabled: false }, - ) - .leftJoinAndSelect( - 'spaceModel.tags', - 'tags', - 'tags.disabled = :tagsDisabled', - { tagsDisabled: false }, - ) - .leftJoinAndSelect('tags.product', 'spaceTagproduct') - .leftJoinAndSelect( - 'subspaceModels.tags', - 'subspaceModelTags', - 'subspaceModelTags.disabled = :subspaceModelTagsDisabled', - { subspaceModelTagsDisabled: false }, - ) - .leftJoinAndSelect('subspaceModelTags.product', 'subspaceTagproduct') - .where('spaceModel.disabled = :disabled', { disabled: false }) - .where('spaceModel.disabled = :disabled', { disabled: false }) + async validateSpaceModel( + uuid: string, + projectUuid?: string, + ): Promise { + const query = this.buildSpaceModelQuery(projectUuid); + const result = await query .andWhere('spaceModel.uuid = :uuid', { uuid }) .getOne(); - if (!spaceModel) { + if (!result) { throw new HttpException('space model not found', HttpStatus.NOT_FOUND); } - return spaceModel; + return result; } private validateUniqueTags(allTags: ProcessTagDto[]) { @@ -415,33 +378,102 @@ export class SpaceModelService { } } - async linkSpacesToModel(params: SpaceModelParam, dto: LinkSpacesToModelDto) { - await this.validateProject(params.projectUuid); - const spaceModel = await this.validateSpaceModel(params.spaceModelUuid); + private buildSpaceModelQuery( + projectUuid: string, + ): SelectQueryBuilder { + return this.spaceModelRepository + .createQueryBuilder('spaceModel') + .leftJoinAndSelect( + 'spaceModel.subspaceModels', + 'subspaceModels', + 'subspaceModels.disabled = :subspaceDisabled', + { subspaceDisabled: false }, + ) + .leftJoinAndSelect( + 'subspaceModels.productAllocations', + 'subspaceModelProductAllocations', + ) + .leftJoinAndSelect( + 'subspaceModelProductAllocations.tags', + 'subspaceModelTags', + ) + .leftJoinAndSelect('subspaceModelTags.product', 'subspaceModelTagProduct') + .leftJoinAndSelect('spaceModel.productAllocations', 'productAllocations') + .leftJoinAndSelect('productAllocations.product', 'allocatedProduct') + .leftJoinAndSelect('productAllocations.tags', 'productTags') + .leftJoinAndSelect('productTags.product', 'productTagProduct') + .where('spaceModel.disabled = false') + .andWhere('spaceModel.project = :projectUuid', { projectUuid }); + } - const spaces = await this.spaceRepository.find({ - where: { uuid: In(dto.spaceUuids) }, - relations: [ - 'spaceModel', - 'devices', - 'subspaces', - 'productAllocations', - 'subspace.productAllocations', - ], - }); + private transformSpaceModelData(spaceModelsArray: SpaceModelEntity[]): any[] { + if (!Array.isArray(spaceModelsArray)) return []; - if (!spaces.length) { - throw new HttpException( - `No spaces found for the given UUIDs`, - HttpStatus.NOT_FOUND, - ); - } + return spaceModelsArray.map((spaceModel) => ({ + uuid: spaceModel.uuid, + createdAt: spaceModel.createdAt, + updatedAt: spaceModel.updatedAt, + modelName: spaceModel.modelName, + disabled: spaceModel.disabled, + subspaceModels: (spaceModel.subspaceModels ?? []).map((subspace) => ({ + uuid: subspace.uuid, + createdAt: subspace.createdAt, + updatedAt: subspace.updatedAt, + subspaceName: subspace.subspaceName, + disabled: subspace.disabled, + tags: this.extractTags(subspace.productAllocations), + })), + tags: this.extractTags(spaceModel.productAllocations), + })); + } - for (const space of spaces) { - const hasDependencies = - space.devices.length > 0 || - space.subspaces.length > 0 || - space.productAllocations.length > 0; - } + private extractTags( + productAllocations: + | SpaceModelProductAllocationEntity[] + | SubspaceModelProductAllocationEntity[] + | undefined, + ): any[] { + if (!productAllocations) return []; + + return productAllocations + .flatMap((allocation) => allocation.tags ?? []) + .map((tag) => ({ + uuid: tag.uuid, + createdAt: tag.createdAt, + updatedAt: tag.updatedAt, + tag: tag.tag, + disabled: tag.disabled, + product: tag.product + ? { + uuid: tag.product.uuid, + createdAt: tag.product.createdAt, + updatedAt: tag.product.updatedAt, + catName: tag.product.catName, + prodId: tag.product.prodId, + name: tag.product.name, + prodType: tag.product.prodType, + } + : null, + })); + } + + private formatSpaceModelResponse(spaceModel: SpaceModelEntity): any { + return { + uuid: spaceModel.uuid, + createdAt: spaceModel.createdAt, + updatedAt: spaceModel.updatedAt, + modelName: spaceModel.modelName, + disabled: spaceModel.disabled, + subspaceModels: + spaceModel.subspaceModels?.map((subspace) => ({ + uuid: subspace.uuid, + createdAt: subspace.createdAt, + updatedAt: subspace.updatedAt, + subspaceName: subspace.subspaceName, + disabled: subspace.disabled, + tags: this.extractTags(subspace.productAllocations), + })) ?? [], + tags: this.extractTags(spaceModel.productAllocations), + }; } } diff --git a/src/space-model/services/tag-model.service.ts b/src/space-model/services/tag-model.service.ts deleted file mode 100644 index 05bdce3..0000000 --- a/src/space-model/services/tag-model.service.ts +++ /dev/null @@ -1,579 +0,0 @@ -import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; -import { QueryRunner } from 'typeorm'; -import { - SpaceModelEntity, - TagModel, -} from '@app/common/modules/space-model/entities'; -import { SubspaceModelEntity } from '@app/common/modules/space-model/entities'; -import { TagModelRepository } from '@app/common/modules/space-model'; -import { - CreateTagModelDto, - ModifySubspaceModelDto, - ModifyTagModelDto, -} from '../dtos'; -import { ProductService } from 'src/product/services'; -import { ModifyAction } from '@app/common/constants/modify-action.enum'; -import { ModifiedTagsModelPayload } from '../interfaces'; -import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository'; - -@Injectable() -export class TagModelService { - constructor( - private readonly tagModelRepository: TagModelRepository, - private readonly productService: ProductService, - private readonly tagRepository: NewTagRepository, - ) {} - - async createTags( - tags: CreateTagModelDto[], - queryRunner: QueryRunner, - spaceModel?: SpaceModelEntity, - subspaceModel?: SubspaceModelEntity, - additionalTags?: CreateTagModelDto[], - tagsToDelete?: ModifyTagModelDto[], - ): Promise { - if (!tags.length) { - throw new HttpException('Tags cannot be empty.', HttpStatus.BAD_REQUEST); - } - - const combinedTags = additionalTags ? [...tags, ...additionalTags] : tags; - const duplicateTags = this.findDuplicateTags(combinedTags); - - if (duplicateTags.length > 0) { - throw new HttpException( - `Duplicate tags found for the same product: ${duplicateTags.join(', ')}`, - HttpStatus.BAD_REQUEST, - ); - } - - const tagEntitiesToCreate = tags.filter((tagDto) => !tagDto.uuid); - const tagEntitiesToUpdate = tags.filter((tagDto) => !!tagDto.uuid); - - try { - const createdTags = await this.bulkSaveTags( - tagEntitiesToCreate, - queryRunner, - spaceModel, - subspaceModel, - tagsToDelete, - ); - - // Update existing tags - const updatedTags = await this.moveTags( - tagEntitiesToUpdate, - queryRunner, - spaceModel, - subspaceModel, - ); - - // Combine created and updated tags - return [...createdTags, ...updatedTags]; - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - - throw new HttpException( - `Failed to create tag models due to an unexpected error.: ${error}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async bulkSaveTags( - tags: CreateTagModelDto[], - queryRunner: QueryRunner, - spaceModel?: SpaceModelEntity, - subspaceModel?: SubspaceModelEntity, - tagsToDelete?: ModifyTagModelDto[], - ): Promise { - if (!tags.length) { - return []; - } - - const tagEntities = await Promise.all( - tags.map((tagDto) => - this.prepareTagEntity( - tagDto, - queryRunner, - spaceModel, - subspaceModel, - tagsToDelete, - ), - ), - ); - - try { - return await queryRunner.manager.save(tagEntities); - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - - throw new HttpException( - `Failed to save tag models due to an unexpected error: ${error.message}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async moveTags( - tags: CreateTagModelDto[], - queryRunner: QueryRunner, - spaceModel?: SpaceModelEntity, - subspaceModel?: SubspaceModelEntity, - ): Promise { - if (!tags.length) { - return []; - } - - try { - return await Promise.all( - tags.map(async (tagDto) => { - try { - const tag = await this.getTagByUuid(tagDto.uuid); - if (!tag) { - throw new HttpException( - `Tag with UUID ${tagDto.uuid} not found.`, - HttpStatus.NOT_FOUND, - ); - } - - if (subspaceModel && subspaceModel.spaceModel) { - await queryRunner.manager.update( - this.tagModelRepository.target, - { uuid: tag.uuid }, - { subspaceModel, spaceModel: null }, - ); - tag.subspaceModel = subspaceModel; - } - - if (!subspaceModel && spaceModel) { - await queryRunner.manager.update( - this.tagModelRepository.target, - { uuid: tag.uuid }, - { subspaceModel: null, spaceModel: spaceModel }, - ); - tag.subspaceModel = null; - tag.spaceModel = spaceModel; - } - - return tag; - } catch (error) { - console.error( - `Error moving tag with UUID ${tagDto.uuid}: ${error.message}`, - ); - throw error; // Re-throw the error to propagate it to the parent Promise.all - } - }), - ); - } catch (error) { - console.error(`Error in moveTags: ${error.message}`); - throw new HttpException( - `Failed to move tags due to an unexpected error: ${error.message}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async updateTag( - tag: ModifyTagModelDto, - queryRunner: QueryRunner, - spaceModel?: SpaceModelEntity, - subspaceModel?: SubspaceModelEntity, - ): Promise { - try { - const existingTag = await this.getTagByUuid(tag.uuid); - - if (tag.tag !== existingTag.tag) { - if (spaceModel) { - await this.checkTagReuse( - tag.tag, - existingTag.product.uuid, - spaceModel, - ); - } else { - await this.checkTagReuse( - tag.tag, - existingTag.product.uuid, - subspaceModel.spaceModel, - ); - } - - if (tag.tag) { - existingTag.tag = tag.tag; - } - } - return await queryRunner.manager.save(existingTag); - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - throw new HttpException( - error.message || 'Failed to update tags', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async deleteTags(tagUuids: string[], queryRunner: QueryRunner) { - try { - const deletePromises = tagUuids.map((id) => - queryRunner.manager.update( - this.tagModelRepository.target, - { uuid: id }, - { disabled: true }, - ), - ); - - await Promise.all(deletePromises); - return { message: 'Tags deleted successfully', tagUuids }; - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - throw new HttpException( - error.message || 'Failed to delete tags', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - private findDuplicateTags(tags: CreateTagModelDto[]): string[] { - const seen = new Map(); - const duplicates: string[] = []; - - tags.forEach((tagDto) => { - const key = `${tagDto.productUuid}-${tagDto.tag}`; - if (seen.has(key)) { - duplicates.push(`${tagDto.tag} for Product: ${tagDto.productUuid}`); - } else { - seen.set(key, true); - } - }); - - return duplicates; - } - - async modifyTags( - tags: ModifyTagModelDto[], - queryRunner: QueryRunner, - spaceModel?: SpaceModelEntity, - subspaceModel?: SubspaceModelEntity, - ): Promise { - const modifiedTagModels: ModifiedTagsModelPayload = { - added: [], - updated: [], - deleted: [], - }; - try { - const tagsToDelete = tags.filter( - (tag) => tag.action === ModifyAction.DELETE, - ); - - for (const tag of tags) { - if (tag.action === ModifyAction.ADD) { - const createTagDto: CreateTagModelDto = { - tag: tag.tag as string, - uuid: tag.uuid, - productUuid: tag.productUuid as string, - }; - - const newModel = await this.createTags( - [createTagDto], - queryRunner, - spaceModel, - subspaceModel, - null, - tagsToDelete, - ); - modifiedTagModels.added.push(...newModel); - } else if (tag.action === ModifyAction.UPDATE) { - const updatedModel = await this.updateTag( - tag, - queryRunner, - spaceModel, - subspaceModel, - ); - modifiedTagModels.updated.push(updatedModel); - } else if (tag.action === ModifyAction.DELETE) { - await queryRunner.manager.update( - this.tagModelRepository.target, - { uuid: tag.uuid }, - { disabled: true }, - ); - modifiedTagModels.deleted.push(tag.uuid); - } else { - throw new HttpException( - `Invalid action "${tag.action}" provided.`, - HttpStatus.BAD_REQUEST, - ); - } - } - return modifiedTagModels; - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - - throw new HttpException( - `An error occurred while modifying tag models: ${error.message}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - private async checkTagReuse( - tag: string, - productUuid: string, - spaceModel: SpaceModelEntity, - tagsToDelete?: ModifyTagModelDto[], - ): Promise { - try { - // Query to find existing tags - const tagExists = await this.tagModelRepository.find({ - where: [ - { - tag, - spaceModel: { uuid: spaceModel.uuid }, - product: { uuid: productUuid }, - disabled: false, - }, - { - tag, - subspaceModel: { spaceModel: { uuid: spaceModel.uuid } }, - product: { uuid: productUuid }, - disabled: false, - }, - ], - }); - - // Remove tags that are marked for deletion - const filteredTagExists = tagExists.filter( - (existingTag) => - !tagsToDelete?.some( - (deleteTag) => deleteTag.uuid === existingTag.uuid, - ), - ); - - // If any tags remain, throw an exception - if (filteredTagExists.length > 0) { - throw new HttpException( - `Tag ${tag} can't be reused`, - HttpStatus.CONFLICT, - ); - } - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - console.error(`Error while checking tag reuse: ${error.message}`); - throw new HttpException( - `An error occurred while checking tag reuse: ${error.message}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - private async prepareTagEntity( - tagDto: CreateTagModelDto, - queryRunner: QueryRunner, - spaceModel?: SpaceModelEntity, - subspaceModel?: SubspaceModelEntity, - tagsToDelete?: ModifyTagModelDto[], - ): Promise { - try { - const product = await this.productService.findOne(tagDto.productUuid); - - if (!product) { - throw new HttpException( - `Product with UUID ${tagDto.productUuid} not found.`, - HttpStatus.NOT_FOUND, - ); - } - - if (spaceModel) { - await this.checkTagReuse( - tagDto.tag, - tagDto.productUuid, - spaceModel, - tagsToDelete, - ); - } else if (subspaceModel && subspaceModel.spaceModel) { - await this.checkTagReuse( - tagDto.tag, - tagDto.productUuid, - subspaceModel.spaceModel, - ); - } else { - throw new HttpException( - `Invalid subspaceModel or spaceModel provided.`, - HttpStatus.BAD_REQUEST, - ); - } - - return queryRunner.manager.create(TagModel, { - tag: tagDto.tag, - product: product.data, - spaceModel: spaceModel, - subspaceModel: subspaceModel, - }); - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - throw new HttpException( - `An error occurred while preparing the tag entity: ${error.message}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async getTagByUuid(uuid: string): Promise { - const tag = await this.tagModelRepository.findOne({ - where: { uuid, disabled: false }, - relations: ['product'], - }); - if (!tag) { - throw new HttpException( - `Tag model with ID ${uuid} not found.`, - HttpStatus.NOT_FOUND, - ); - } - return tag; - } - - async getTagByName( - tag: string, - subspaceUuid?: string, - spaceUuid?: string, - ): Promise { - const queryConditions: any = { tag }; - - if (spaceUuid) { - queryConditions.spaceModel = { uuid: spaceUuid }; - } else if (subspaceUuid) { - queryConditions.subspaceModel = { uuid: subspaceUuid }; - } else { - throw new HttpException( - 'Either spaceUuid or subspaceUuid must be provided.', - HttpStatus.BAD_REQUEST, - ); - } - queryConditions.disabled = false; - - const existingTag = await this.tagModelRepository.findOne({ - where: queryConditions, - relations: ['product'], - }); - - if (!existingTag) { - throw new HttpException( - `Tag model with tag "${tag}" not found.`, - HttpStatus.NOT_FOUND, - ); - } - - return existingTag; - } - - getSubspaceTagsToBeAdded( - spaceTags?: ModifyTagModelDto[], - subspaceModels?: ModifySubspaceModelDto[], - ): ModifyTagModelDto[] { - if (!subspaceModels || subspaceModels.length === 0) { - return spaceTags; - } - - const spaceTagsToDelete = spaceTags?.filter( - (tag) => tag.action === 'delete', - ); - - const tagsToAdd = subspaceModels.flatMap( - (subspace) => subspace.tags?.filter((tag) => tag.action === 'add') || [], - ); - - const commonTagUuids = new Set( - tagsToAdd - .filter((tagToAdd) => - spaceTagsToDelete.some( - (tagToDelete) => tagToAdd.uuid === tagToDelete.uuid, - ), - ) - .map((tag) => tag.uuid), - ); - - const remainingTags = spaceTags.filter( - (tag) => !commonTagUuids.has(tag.uuid), // Exclude tags in commonTagUuids - ); - - return remainingTags; - } - - getModifiedSubspaces( - spaceTags: ModifyTagModelDto[], - subspaceModels: ModifySubspaceModelDto[], - ): ModifySubspaceModelDto[] { - if (!subspaceModels || subspaceModels.length === 0) { - return []; - } - - // Extract tags marked for addition in spaceTags - const spaceTagsToAdd = spaceTags.filter((tag) => tag.action === 'add'); - - const subspaceTagsToAdd = subspaceModels.flatMap( - (subspace) => subspace.tags?.filter((tag) => tag.action === 'add') || [], - ); - - const subspaceTagsToDelete = subspaceModels.flatMap( - (subspace) => - subspace.tags?.filter((tag) => tag.action === 'delete') || [], - ); - - const subspaceTagsToDeleteUuids = new Set( - subspaceTagsToDelete.map((tag) => tag.uuid), - ); - - const commonTagsInSubspaces = subspaceTagsToAdd.filter((tag) => - subspaceTagsToDeleteUuids.has(tag.uuid), - ); - - // Find UUIDs of tags that are common between spaceTagsToAdd and subspace tags marked for deletion - const commonTagUuids = new Set( - spaceTagsToAdd - .flatMap((tagToAdd) => - subspaceModels.flatMap( - (subspace) => - subspace.tags?.filter( - (tagToDelete) => - tagToDelete.action === 'delete' && - tagToAdd.uuid === tagToDelete.uuid, - ) || [], - ), - ) - .map((tag) => tag.uuid), - ); - - // Modify subspaceModels by removing tags with UUIDs present in commonTagUuids - let modifiedSubspaces = subspaceModels.map((subspace) => ({ - ...subspace, - tags: subspace.tags?.filter((tag) => !commonTagUuids.has(tag.uuid)) || [], - })); - - modifiedSubspaces = modifiedSubspaces.map((subspace) => ({ - ...subspace, - tags: - subspace.tags?.filter( - (tag) => - !( - tag.action === 'delete' && - commonTagsInSubspaces.some( - (commonTag) => commonTag.uuid === tag.uuid, - ) - ), - ) || [], - })); - - return modifiedSubspaces; - } -} diff --git a/src/space-model/space-model.module.ts b/src/space-model/space-model.module.ts index 5b15275..b73eceb 100644 --- a/src/space-model/space-model.module.ts +++ b/src/space-model/space-model.module.ts @@ -2,11 +2,7 @@ import { SpaceRepositoryModule } from '@app/common/modules/space/space.repositor import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { SpaceModelController } from './controllers'; -import { - SpaceModelService, - SubSpaceModelService, - TagModelService, -} from './services'; +import { SpaceModelService, SubSpaceModelService } from './services'; import { SpaceModelProductAllocationRepoitory, SpaceModelRepository, @@ -64,7 +60,6 @@ const CommandHandlers = [ SubspaceModelRepository, ProductRepository, SubspaceRepository, - TagModelService, TagModelRepository, SubSpaceService, ValidationService, diff --git a/src/space/space.module.ts b/src/space/space.module.ts index a4f904d..e197f6c 100644 --- a/src/space/space.module.ts +++ b/src/space/space.module.ts @@ -59,7 +59,6 @@ import { TagService } from './services/tag'; import { SpaceModelService, SubSpaceModelService, - TagModelService, } from 'src/space-model/services'; import { UserService, UserSpaceService } from 'src/users/services'; import { UserDevicePermissionService } from 'src/user-device-permission/services'; @@ -120,7 +119,6 @@ export const CommandHandlers = [DisableSpaceHandler]; SceneDeviceRepository, SpaceModelService, SubSpaceModelService, - TagModelService, ProjectRepository, SpaceModelRepository, SubspaceModelRepository,