From 1220ee395d8f80a14c1f8d996e5e9aa7e10e0414 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Fri, 7 Mar 2025 23:01:38 +0400 Subject: [PATCH 1/3] fixing propagation --- .../modules/device/entities/device.entity.ts | 8 +- src/device/services/device.service.ts | 17 +++ .../handlers/propate-subspace-handler.ts | 2 +- .../space-model-product-allocation.service.ts | 31 ++++- .../services/space-model.service.ts | 4 +- .../subspace/subspace-model.service.ts | 14 +++ src/space-model/space-model.module.ts | 19 +++ .../space-product-allocation.service.ts | 112 ++++++++++++++++++ .../services/space-validation.service.ts | 25 ++++ src/space/services/space.service.ts | 39 +----- .../services/subspace/subspace.service.ts | 32 ++--- src/space/space.module.ts | 1 + 12 files changed, 236 insertions(+), 68 deletions(-) diff --git a/libs/common/src/modules/device/entities/device.entity.ts b/libs/common/src/modules/device/entities/device.entity.ts index 0ab8c7d..787b100 100644 --- a/libs/common/src/modules/device/entities/device.entity.ts +++ b/libs/common/src/modules/device/entities/device.entity.ts @@ -6,7 +6,6 @@ import { Unique, Index, JoinColumn, - OneToOne, JoinTable, } from 'typeorm'; import { AbstractEntity } from '../../abstract/entities/abstract.entity'; @@ -18,7 +17,6 @@ import { PermissionTypeEntity } from '../../permission/entities'; import { SceneDeviceEntity } from '../../scene-device/entities'; import { SpaceEntity } from '../../space/entities/space.entity'; import { SubspaceEntity } from '../../space/entities/subspace/subspace.entity'; -import { TagEntity } from '../../space/entities/tag.entity'; import { NewTagEntity } from '../../tag'; @Entity({ name: 'device' }) @@ -79,14 +77,10 @@ export class DeviceEntity extends AbstractEntity { @OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {}) sceneDevices: SceneDeviceEntity[]; - @OneToOne(() => TagEntity, (tag) => tag.device, { - nullable: true, - }) - tag: TagEntity; @OneToMany(() => NewTagEntity, (tag) => tag.devices) @JoinTable({ name: 'device_tags' }) - public tags: NewTagEntity[]; + public tag: NewTagEntity[]; constructor(partial: Partial) { super(); diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index c6d6f12..333aee5 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -1546,4 +1546,21 @@ export class DeviceService { ); } } + + async moveDevicesToSpace( + targetSpace: SpaceEntity, + deviceIds: string[], + ): Promise { + if (!deviceIds || deviceIds.length === 0) { + throw new HttpException( + 'No device IDs provided for transfer', + HttpStatus.BAD_REQUEST, + ); + } + + await this.deviceRepository.update( + { uuid: In(deviceIds) }, + { spaceDevice: targetSpace }, + ); + } } diff --git a/src/space-model/handlers/propate-subspace-handler.ts b/src/space-model/handlers/propate-subspace-handler.ts index 1bd244d..36936ff 100644 --- a/src/space-model/handlers/propate-subspace-handler.ts +++ b/src/space-model/handlers/propate-subspace-handler.ts @@ -104,7 +104,7 @@ export class PropogateUpdateSpaceModelHandler for (const space of spaces) { await this.subSpaceService.createSubSpaceFromModel( subspaceModels, - space, + [space], queryRunner, ); } 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 d895500..33f26f0 100644 --- a/src/space-model/services/space-model-product-allocation.service.ts +++ b/src/space-model/services/space-model-product-allocation.service.ts @@ -16,6 +16,7 @@ import { ProductEntity } from '@app/common/modules/product/entities'; import { SpaceRepository } from '@app/common/modules/space'; import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service'; import { SpaceEntity } from '@app/common/modules/space/entities/space.entity'; +import { ProjectEntity } from '@app/common/modules/project/entities'; @Injectable() export class SpaceModelProductAllocationService { @@ -141,7 +142,7 @@ export class SpaceModelProductAllocationService { async updateProductAllocations( dtos: ModifyTagModelDto[], - projectUuid: string, + project: ProjectEntity, spaceModel: SpaceModelEntity, queryRunner: QueryRunner, modifySubspaceModels?: ModifySubspaceModelDto[], @@ -161,7 +162,7 @@ export class SpaceModelProductAllocationService { const processedTags = await this.tagService.processTags( addTagDtos, - projectUuid, + project.uuid, queryRunner, ); const addTagUuidMap = new Map(); @@ -192,13 +193,19 @@ export class SpaceModelProductAllocationService { await Promise.all([ this.processAddActions( filteredDtos, - projectUuid, + project.uuid, spaceModel, queryRunner, modifySubspaceModels, spaces, ), - this.processDeleteActions(filteredDtos, queryRunner, spaceModel), + this.processDeleteActions( + filteredDtos, + queryRunner, + spaceModel, + project, + spaces, + ), ]); } catch (error) { throw this.handleError(error, 'Error while updating product allocations'); @@ -304,6 +311,8 @@ export class SpaceModelProductAllocationService { dtos: ModifyTagModelDto[], queryRunner: QueryRunner, spaceModel: SpaceModelEntity, + project: ProjectEntity, + spaces?: SpaceEntity[], ): Promise { try { if (!dtos || dtos.length === 0) { @@ -325,7 +334,11 @@ export class SpaceModelProductAllocationService { uuid: spaceModel.uuid, }, }, - relations: ['tags'], + relations: [ + 'tags', + 'inheritedSpaceAllocations', + 'inheritedSpaceAllocations.tags', + ], }, ); @@ -365,6 +378,14 @@ export class SpaceModelProductAllocationService { ); } + await this.spaceProductAllocationService.propagateDeleteToInheritedAllocations( + queryRunner, + allocationsToUpdate, + tagUuidsToDelete, + project, + spaces, + ); + await queryRunner.manager .createQueryBuilder() .delete() diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts index 2950a64..ba7d5f5 100644 --- a/src/space-model/services/space-model.service.ts +++ b/src/space-model/services/space-model.service.ts @@ -189,7 +189,7 @@ export class SpaceModelService { async update(dto: UpdateSpaceModelDto, param: SpaceModelParam) { const queryRunner = this.dataSource.createQueryRunner(); - await this.validateProject(param.projectUuid); + const project = await this.validateProject(param.projectUuid); const spaceModel = await this.validateSpaceModel( param.spaceModelUuid, param.projectUuid, @@ -227,7 +227,7 @@ export class SpaceModelService { if (dto.tags) { await this.spaceModelProductAllocationService.updateProductAllocations( dto.tags, - param.projectUuid, + project, spaceModel, queryRunner, dto.subspaceModels, diff --git a/src/space-model/services/subspace/subspace-model.service.ts b/src/space-model/services/subspace/subspace-model.service.ts index 90e1ba1..776e171 100644 --- a/src/space-model/services/subspace/subspace-model.service.ts +++ b/src/space-model/services/subspace/subspace-model.service.ts @@ -14,6 +14,8 @@ import { ProcessTagDto } from 'src/tags/dtos'; import { TagService } from 'src/tags/services'; import { SubspaceModelProductAllocationService } from './subspace-model-product-allocation.service'; import { ISingleSubspaceModel } from 'src/space-model/interfaces'; +import { SpaceEntity } from '@app/common/modules/space/entities/space.entity'; +import { SubSpaceService } from 'src/space/services/subspace'; @Injectable() export class SubSpaceModelService { @@ -21,6 +23,7 @@ export class SubSpaceModelService { private readonly subspaceModelRepository: SubspaceModelRepository, private readonly tagService: TagService, private readonly productAllocationService: SubspaceModelProductAllocationService, + private readonly subspaceService: SubSpaceService, ) {} async createModels( @@ -74,6 +77,7 @@ export class SubSpaceModelService { dtos: ModifySubspaceModelDto[], spaceModel: SpaceModelEntity, queryRunner: QueryRunner, + spaces?: SpaceEntity[], ): Promise { if (!dtos.length) return []; @@ -89,6 +93,14 @@ export class SubSpaceModelService { const savedSubspaces = await queryRunner.manager.save(subspaceEntities); + if (spaces) { + await this.subspaceService.createSubSpaceFromModel( + savedSubspaces, + spaces, + queryRunner, + ); + } + return savedSubspaces.map((subspace, index) => ({ subspaceModel: subspace, action: ModifyAction.ADD, @@ -102,6 +114,7 @@ export class SubSpaceModelService { queryRunner: QueryRunner, projectUuid: string, spaceTagUpdateDtos?: ModifyTagModelDto[], + spaces?: SpaceEntity[], ) { try { if (!dtos || dtos.length === 0) { @@ -125,6 +138,7 @@ export class SubSpaceModelService { addDtos, spaceModel, queryRunner, + spaces, ); const combineModels = [...addedModels, ...updatedModels]; diff --git a/src/space-model/space-model.module.ts b/src/space-model/space-model.module.ts index c9711f2..d49f590 100644 --- a/src/space-model/space-model.module.ts +++ b/src/space-model/space-model.module.ts @@ -46,6 +46,16 @@ import { SpaceModelProductAllocationService } from './services/space-model-produ import { SubspaceModelProductAllocationService } from './services/subspace/subspace-model-product-allocation.service'; import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service'; import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service'; +import { DeviceService } from 'src/device/services'; +import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; +import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; +import { SceneService } from 'src/scene/services'; +import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories'; +import { + SceneIconRepository, + SceneRepository, +} from '@app/common/modules/scene/repositories'; +import { AutomationRepository } from '@app/common/modules/automation/repositories'; const CommandHandlers = [ PropogateUpdateSpaceModelHandler, @@ -80,6 +90,14 @@ const CommandHandlers = [ SpaceLinkRepository, InviteSpaceRepository, NewTagService, + DeviceService, + DeviceStatusFirebaseService, + DeviceStatusLogRepository, + SceneService, + SceneIconRepository, + SceneDeviceRepository, + SceneRepository, + AutomationRepository, SpaceModelProductAllocationRepoitory, SubspaceModelProductAllocationRepoitory, NewTagRepository, @@ -90,6 +108,7 @@ const CommandHandlers = [ SubspaceProductAllocationService, SpaceProductAllocationRepository, SubspaceProductAllocationRepository, + SubSpaceService, ], exports: [CqrsModule, SpaceModelService], }) diff --git a/src/space/services/space-product-allocation.service.ts b/src/space/services/space-product-allocation.service.ts index 8b8acb1..a737f3b 100644 --- a/src/space/services/space-product-allocation.service.ts +++ b/src/space/services/space-product-allocation.service.ts @@ -13,12 +13,16 @@ import { ModifySubspaceDto } from '../dtos'; import { ProcessTagDto } from 'src/tags/dtos'; import { TagService as NewTagService } from 'src/tags/services'; import { SpaceModelProductAllocationEntity } from '@app/common/modules/space-model'; +import { DeviceEntity } from '@app/common/modules/device/entities'; +import { ProjectEntity } from '@app/common/modules/project/entities'; +import { ValidationService } from './space-validation.service'; @Injectable() export class SpaceProductAllocationService { constructor( private readonly tagService: NewTagService, private readonly spaceProductAllocationRepository: SpaceProductAllocationRepository, + private readonly spaceService: ValidationService, ) {} async createSpaceProductAllocations( @@ -220,6 +224,114 @@ export class SpaceProductAllocationService { } } + async propagateDeleteToInheritedAllocations( + queryRunner: QueryRunner, + allocationsToUpdate: SpaceModelProductAllocationEntity[], + tagUuidsToDelete: string[], + project: ProjectEntity, + spaces?: SpaceEntity[], + ): Promise { + try { + const inheritedAllocationUpdates: SpaceProductAllocationEntity[] = []; + const inheritedAllocationsToDelete: SpaceProductAllocationEntity[] = []; + + for (const allocation of allocationsToUpdate) { + for (const inheritedAllocation of allocation.inheritedSpaceAllocations) { + const updatedInheritedTags = inheritedAllocation.tags.filter( + (tag) => !tagUuidsToDelete.includes(tag.uuid), + ); + + if (updatedInheritedTags.length === inheritedAllocation.tags.length) { + continue; + } + + if (updatedInheritedTags.length === 0) { + inheritedAllocationsToDelete.push(inheritedAllocation); + } else { + inheritedAllocation.tags = updatedInheritedTags; + inheritedAllocationUpdates.push(inheritedAllocation); + } + } + } + + if (inheritedAllocationUpdates.length > 0) { + await queryRunner.manager.save( + SpaceProductAllocationEntity, + inheritedAllocationUpdates, + ); + } + + if (inheritedAllocationsToDelete.length > 0) { + await queryRunner.manager.remove( + SpaceProductAllocationEntity, + inheritedAllocationsToDelete, + ); + } + + if (spaces && spaces.length > 0) { + await this.moveDevicesToOrphanSpace( + queryRunner, + spaces, + tagUuidsToDelete, + project, + ); + } + + await queryRunner.manager + .createQueryBuilder() + .delete() + .from('space_product_tags') + .where( + 'space_product_allocation_uuid NOT IN (' + + queryRunner.manager + .createQueryBuilder() + .select('allocation.uuid') + .from(SpaceProductAllocationEntity, 'allocation') + .getQuery() + + ')', + ) + .execute(); + } catch (error) { + throw this.handleError( + error, + `Failed to propagate tag deletion to inherited allocations`, + ); + } + } + + async moveDevicesToOrphanSpace( + queryRunner: QueryRunner, + spaces: SpaceEntity[], + tagUuidsToDelete: string[], + project: ProjectEntity, + ): Promise { + try { + const orphanSpace = await this.spaceService.getOrphanSpace(project); + + const devicesToMove = await queryRunner.manager + .createQueryBuilder(DeviceEntity, 'device') + .leftJoinAndSelect('device.tag', 'tag') + .where('device.spaceDevice IN (:...spaceUuids)', { + spaceUuids: spaces.map((space) => space.uuid), + }) + .andWhere('tag.uuid IN (:...tagUuidsToDelete)', { tagUuidsToDelete }) + .getMany(); + + if (devicesToMove.length === 0) return; + + await queryRunner.manager + .createQueryBuilder() + .update(DeviceEntity) + .set({ spaceDevice: orphanSpace }) + .where('uuid IN (:...deviceUuids)', { + deviceUuids: devicesToMove.map((device) => device.uuid), + }) + .execute(); + } catch (error) { + throw this.handleError(error, `Failed to move devices to orphan space`); + } + } + private async processDeleteActions( dtos: ModifyTagDto[], queryRunner: QueryRunner, diff --git a/src/space/services/space-validation.service.ts b/src/space/services/space-validation.service.ts index be173b0..08828b4 100644 --- a/src/space/services/space-validation.service.ts +++ b/src/space/services/space-validation.service.ts @@ -19,6 +19,11 @@ import { ValidateSpacesDto } from '../dtos/validation.space.dto'; import { ProjectParam } from '../dtos'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { In } from 'typeorm'; +import { + ORPHAN_COMMUNITY_NAME, + ORPHAN_SPACE_NAME, +} from '@app/common/constants/orphan-constant'; +import { ProjectEntity } from '@app/common/modules/project/entities'; @Injectable() export class ValidationService { @@ -286,4 +291,24 @@ export class ValidationService { ); } } + + async getOrphanSpace(project: ProjectEntity): Promise { + const orphanSpace = await this.spaceRepository.findOne({ + where: { + community: { + name: `${ORPHAN_COMMUNITY_NAME}-${project.name}`, + }, + spaceName: ORPHAN_SPACE_NAME, + }, + }); + + if (!orphanSpace) { + throw new HttpException( + `Orphan space not found in community ${project.name}`, + HttpStatus.NOT_FOUND, + ); + } + + return orphanSpace; + } } diff --git a/src/space/services/space.service.ts b/src/space/services/space.service.ts index 844c42f..7a8aa50 100644 --- a/src/space/services/space.service.ts +++ b/src/space/services/space.service.ts @@ -38,6 +38,9 @@ import { ProcessTagDto } from 'src/tags/dtos'; import { SpaceProductAllocationService } from './space-product-allocation.service'; import { SubspaceProductAllocationService } from './subspace/subspace-product-allocation.service'; import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity'; +import { ProjectEntity } from '@app/common/modules/project/entities'; +import { DeviceRepository } from '@app/common/modules/device/repositories'; +import { DeviceService } from 'src/device/services'; @Injectable() export class SpaceService { constructor( @@ -53,6 +56,8 @@ export class SpaceService { private commandBus: CommandBus, private readonly spaceProductAllocationService: SpaceProductAllocationService, private readonly subspaceProductAllocationService: SubspaceProductAllocationService, + private readonly deviceRepository: DeviceRepository, + private readonly deviceSevice: DeviceService, ) {} async createSpace( @@ -186,40 +191,6 @@ export class SpaceService { } } } - async createFromModel( - spaceModelUuid: string, - queryRunner: QueryRunner, - space: SpaceEntity, - ) { - try { - const spaceModel = - await this.spaceModelService.validateSpaceModel(spaceModelUuid); - - space.spaceModel = spaceModel; - await queryRunner.manager.save(SpaceEntity, space); - - await this.subSpaceService.createSubSpaceFromModel( - spaceModel.subspaceModels, - space, - queryRunner, - ); - - await this.tagService.createTagsFromModel( - queryRunner, - spaceModel.tags, - space, - null, - ); - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - throw new HttpException( - 'An error occurred while creating the space from space model', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } async getSpacesHierarchyForCommunity( params: CommunitySpaceParam, diff --git a/src/space/services/subspace/subspace.service.ts b/src/space/services/subspace/subspace.service.ts index 500ea69..023dafb 100644 --- a/src/space/services/subspace/subspace.service.ts +++ b/src/space/services/subspace/subspace.service.ts @@ -70,29 +70,23 @@ export class SubSpaceService { async createSubSpaceFromModel( subspaceModels: SubspaceModelEntity[], - space: SpaceEntity, + spaces: SpaceEntity[], queryRunner: QueryRunner, ): Promise { - if (!subspaceModels?.length) return; + if (!subspaceModels?.length || !spaces?.length) return; - const subspaceData = subspaceModels.map((subSpaceModel) => ({ - subspaceName: subSpaceModel.subspaceName, - space, - subSpaceModel, - })); + const subspaceData = []; - const subspaces = await this.createSubspaces(subspaceData, queryRunner); - - await Promise.all( - subspaceModels.map((model, index) => - this.tagService.createTagsFromModel( - queryRunner, - model.tags || [], - null, - subspaces[index], - ), - ), - ); + for (const space of spaces) { + for (const subSpaceModel of subspaceModels) { + subspaceData.push({ + subspaceName: subSpaceModel.subspaceName, + space, + subSpaceModel, + }); + } + } + await this.createSubspaces(subspaceData, queryRunner); } async createSubspacesFromDto( diff --git a/src/space/space.module.ts b/src/space/space.module.ts index 17cf774..3808a0e 100644 --- a/src/space/space.module.ts +++ b/src/space/space.module.ts @@ -118,6 +118,7 @@ export const CommandHandlers = [DisableSpaceHandler]; UserRepository, SpaceUserService, SpaceSceneService, + DeviceService, SceneService, SceneIconRepository, SceneRepository, From 36612a40b93f714db82b5e55d9d4ac82ca9a22a9 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Sun, 9 Mar 2025 13:56:06 +0400 Subject: [PATCH 2/3] fix propagation --- ...duct-allocation-update-result.interface.ts | 32 ++++++++++ .../services/space-model.service.ts | 19 +++--- ...bspace-model-product-allocation.service.ts | 60 ++++++++++++++----- .../subspace/subspace-model.service.ts | 23 ++++--- src/space/services/space.service.ts | 1 - 5 files changed, 104 insertions(+), 31 deletions(-) create mode 100644 src/space-model/interfaces/subspace-product-allocation-update-result.interface.ts diff --git a/src/space-model/interfaces/subspace-product-allocation-update-result.interface.ts b/src/space-model/interfaces/subspace-product-allocation-update-result.interface.ts new file mode 100644 index 0000000..c262da0 --- /dev/null +++ b/src/space-model/interfaces/subspace-product-allocation-update-result.interface.ts @@ -0,0 +1,32 @@ +import { SubspaceModelProductAllocationEntity } from '@app/common/modules/space-model'; +import { NewTagEntity } from '@app/common/modules/tag'; + +export type IUpdatedAllocations = { + allocation?: SubspaceModelProductAllocationEntity; + tagsRemoved?: NewTagEntity[]; + tagsAdded?: NewTagEntity[]; + newAllocation?: SubspaceModelProductAllocationEntity; + deletedAllocation?: SubspaceModelProductAllocationEntity; +}; + +export interface ISubspaceProductAllocationUpdateResult { + createdAllocations: ICreatedAllocation[]; + updatedAllocations: IUpdatedAllocation[]; + deletedAllocations: IDeletedAllocation[]; +} + +export interface ICreatedAllocation { + allocation: SubspaceModelProductAllocationEntity; + tags: NewTagEntity[]; +} + +export interface IUpdatedAllocation { + allocation: SubspaceModelProductAllocationEntity; + tagsAdded: NewTagEntity[]; + tagsRemoved: NewTagEntity[]; +} + +export interface IDeletedAllocation { + allocation: SubspaceModelProductAllocationEntity; + tagsRemoved: NewTagEntity[]; +} diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts index ba7d5f5..01dea08 100644 --- a/src/space-model/services/space-model.service.ts +++ b/src/space-model/services/space-model.service.ts @@ -44,6 +44,8 @@ import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity'; import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity'; import { DeviceEntity } from '@app/common/modules/device/entities'; +import { ISingleSubspace } from 'src/space/interfaces/single-subspace.interface'; +import { ISingleSubspaceModel } from '../interfaces'; @Injectable() export class SpaceModelService { @@ -195,7 +197,7 @@ export class SpaceModelService { param.projectUuid, ); await queryRunner.connect(); - + let modifiedSubspaces: ISingleSubspaceModel[] = []; try { await queryRunner.startTransaction(); const spaces = await this.fetchModelSpaces(spaceModel); @@ -215,13 +217,14 @@ export class SpaceModelService { } if (dto.subspaceModels) { - await this.subSpaceModelService.modifySubspaceModels( - dto.subspaceModels, - spaceModel, - queryRunner, - param.projectUuid, - dto.tags, - ); + modifiedSubspaces = + await this.subSpaceModelService.modifySubspaceModels( + dto.subspaceModels, + spaceModel, + queryRunner, + param.projectUuid, + dto.tags, + ); } if (dto.tags) { diff --git a/src/space-model/services/subspace/subspace-model-product-allocation.service.ts b/src/space-model/services/subspace/subspace-model-product-allocation.service.ts index cc8d22b..f4979ea 100644 --- a/src/space-model/services/subspace/subspace-model-product-allocation.service.ts +++ b/src/space-model/services/subspace/subspace-model-product-allocation.service.ts @@ -11,6 +11,7 @@ import { NewTagEntity } from '@app/common/modules/tag'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { ModifyTagModelDto } from 'src/space-model/dtos'; import { ISingleSubspaceModel } from 'src/space-model/interfaces'; +import { IUpdatedAllocations } from 'src/space-model/interfaces/subspace-product-allocation-update-result.interface'; import { ProcessTagDto } from 'src/tags/dtos'; import { TagService as NewTagService } from 'src/tags/services'; import { In, QueryRunner } from 'typeorm'; @@ -29,8 +30,10 @@ export class SubspaceModelProductAllocationService { tags: NewTagEntity[], queryRunner?: QueryRunner, spaceAllocationsToExclude?: SpaceModelProductAllocationEntity[], - ): Promise { + ): Promise { try { + const updatedAllocations: IUpdatedAllocations[] = []; + const allocations: SubspaceModelProductAllocationEntity[] = []; for (const tag of tags) { @@ -140,7 +143,6 @@ export class SubspaceModelProductAllocationService { product: tag.product, tags: [tag], }); - allocations.push(allocation); } else { //If allocation exists, add the tag to it @@ -155,6 +157,10 @@ export class SubspaceModelProductAllocationService { existingAllocationsForProduct[0], ); } + updatedAllocations.push({ + allocation: existingAllocationsForProduct[0], + tagsAdded: [tag], + }); } } @@ -168,9 +174,13 @@ export class SubspaceModelProductAllocationService { } else { await this.subspaceModelProductAllocationRepository.save(allocations); } + + allocations.forEach((allocation) => { + updatedAllocations.push({ newAllocation: allocation }); + }); } - return allocations; + return updatedAllocations; } catch (error) { throw new HttpException( `An unexpected error occurred while creating subspace product allocations ${error}`, @@ -267,6 +277,7 @@ export class SubspaceModelProductAllocationService { spaceTagUpdateDtos?: ModifyTagModelDto[], ) { const spaceAllocationToExclude: SpaceModelProductAllocationEntity[] = []; + const updatedAllocations: IUpdatedAllocations[] = []; for (const subspaceModel of subspaceModels) { const tagDtos = subspaceModel.tags; @@ -332,6 +343,11 @@ export class SubspaceModelProductAllocationService { (tag) => tag.uuid !== deletedTag.tagUuid, ); + updatedAllocations.push({ + allocation, + tagsRemoved: [tagEntity], + }); + await queryRunner.manager.save(allocation); const productAllocationExistInSubspace = @@ -350,6 +366,12 @@ export class SubspaceModelProductAllocationService { if (productAllocationExistInSubspace) { productAllocationExistInSubspace.tags.push(tagEntity); + + updatedAllocations.push({ + allocation: productAllocationExistInSubspace, + tagsAdded: [tagEntity], + }); + await queryRunner.manager.save( productAllocationExistInSubspace, ); @@ -363,6 +385,10 @@ export class SubspaceModelProductAllocationService { }, ); + updatedAllocations.push({ + allocation: newProductAllocation, + }); + await queryRunner.manager.save(newProductAllocation); } @@ -406,6 +432,11 @@ export class SubspaceModelProductAllocationService { ), ); + updatedAllocations.push({ + allocation: allocation, + tagsRemoved: repeatedTags, + }); + await queryRunner.manager.save(allocation); const productAllocationExistInSubspace = @@ -421,6 +452,11 @@ export class SubspaceModelProductAllocationService { ); if (productAllocationExistInSubspace) { + updatedAllocations.push({ + allocation: productAllocationExistInSubspace, + tagsAdded: repeatedTags, + }); + productAllocationExistInSubspace.tags.push(...repeatedTags); await queryRunner.manager.save( productAllocationExistInSubspace, @@ -435,19 +471,12 @@ export class SubspaceModelProductAllocationService { }, ); + updatedAllocations.push({ + newAllocation: newProductAllocation, + }); + await queryRunner.manager.save(newProductAllocation); } - - const newAllocation = queryRunner.manager.create( - SubspaceModelProductAllocationEntity, - { - subspaceModel: subspaceModel.subspaceModel, - product: allocation.product, - tags: repeatedTags, - }, - ); - - await queryRunner.manager.save(newAllocation); } } } @@ -479,13 +508,14 @@ export class SubspaceModelProductAllocationService { } // Create new product allocations - await this.createProductAllocations( + const newAllocations = await this.createProductAllocations( subspaceModel.subspaceModel, spaceModel, processedTags, queryRunner, spaceAllocationToExclude, ); + return [...updatedAllocations, ...newAllocations]; } if (tagsToDeleteDto.length > 0) { await this.processDeleteActions(tagsToDeleteDto, queryRunner); diff --git a/src/space-model/services/subspace/subspace-model.service.ts b/src/space-model/services/subspace/subspace-model.service.ts index 776e171..5f65644 100644 --- a/src/space-model/services/subspace/subspace-model.service.ts +++ b/src/space-model/services/subspace/subspace-model.service.ts @@ -115,7 +115,7 @@ export class SubSpaceModelService { projectUuid: string, spaceTagUpdateDtos?: ModifyTagModelDto[], spaces?: SpaceEntity[], - ) { + ): Promise { try { if (!dtos || dtos.length === 0) { return; @@ -129,18 +129,18 @@ export class SubSpaceModelService { (dto) => dto.action === ModifyAction.DELETE, ); - const updatedModels = await this.updateSubspaceModel( + const updatedSubspaces = await this.updateSubspaceModel( combinedDtos, spaceModel, queryRunner, ); - const addedModels = await this.handleAddAction( + const createdSubspaces = await this.handleAddAction( addDtos, spaceModel, queryRunner, spaces, ); - const combineModels = [...addedModels, ...updatedModels]; + const combineModels = [...createdSubspaces, ...updatedSubspaces]; await this.productAllocationService.updateAllocations( combineModels, @@ -150,7 +150,12 @@ export class SubSpaceModelService { spaceTagUpdateDtos, ); - await this.deleteSubspaceModels(deleteDtos, queryRunner, spaceModel); + const deletedSubspaces = await this.deleteSubspaceModels( + deleteDtos, + queryRunner, + spaceModel, + ); + return [...createdSubspaces, ...updatedSubspaces, ...deletedSubspaces]; } catch (error) { console.error('Error in modifySubspaceModels:', error); throw new HttpException( @@ -168,7 +173,7 @@ export class SubSpaceModelService { deleteDtos: ModifySubspaceModelDto[], queryRunner: QueryRunner, spaceModel: SpaceModelEntity, - ) { + ): Promise { try { if (!deleteDtos || deleteDtos.length === 0) { return; @@ -275,7 +280,11 @@ export class SubSpaceModelService { deleteResults.push(...subspaceUuids.map((uuid) => ({ uuid }))); - return deleteResults; + return subspaces.map((subspace) => ({ + subspaceModel: subspace, + action: ModifyAction.DELETE, + tags: [], + })); } catch (error) { if (error instanceof QueryFailedError) { throw new HttpException( diff --git a/src/space/services/space.service.ts b/src/space/services/space.service.ts index 7a8aa50..b811e87 100644 --- a/src/space/services/space.service.ts +++ b/src/space/services/space.service.ts @@ -38,7 +38,6 @@ import { ProcessTagDto } from 'src/tags/dtos'; import { SpaceProductAllocationService } from './space-product-allocation.service'; import { SubspaceProductAllocationService } from './subspace/subspace-product-allocation.service'; import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity'; -import { ProjectEntity } from '@app/common/modules/project/entities'; import { DeviceRepository } from '@app/common/modules/device/repositories'; import { DeviceService } from 'src/device/services'; @Injectable() From d1a976d152701fc55926008f3c94b50fd002015b Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Mon, 10 Mar 2025 10:57:27 +0400 Subject: [PATCH 3/3] removed old tags --- src/space-model/commands/index.ts | 2 +- ...ropagate-subspace-model-update-command.ts} | 8 +- .../handlers/propate-subspace-handler.ts | 97 ++++--------------- .../space-model-product-allocation.service.ts | 8 -- .../services/space-model.service.ts | 14 ++- .../subspace/subspace-model.service.ts | 8 +- .../subspace/subspace-device.service.ts | 38 -------- 7 files changed, 42 insertions(+), 133 deletions(-) rename src/space-model/commands/{propogate-subspace-update-command.ts => propagate-subspace-model-update-command.ts} (56%) diff --git a/src/space-model/commands/index.ts b/src/space-model/commands/index.ts index da760ea..4a7aafa 100644 --- a/src/space-model/commands/index.ts +++ b/src/space-model/commands/index.ts @@ -1,2 +1,2 @@ -export * from './propogate-subspace-update-command'; export * from './propagate-space-model-deletion.command'; +export * from './propagate-subspace-model-update-command'; diff --git a/src/space-model/commands/propogate-subspace-update-command.ts b/src/space-model/commands/propagate-subspace-model-update-command.ts similarity index 56% rename from src/space-model/commands/propogate-subspace-update-command.ts rename to src/space-model/commands/propagate-subspace-model-update-command.ts index a2b5203..ff437e4 100644 --- a/src/space-model/commands/propogate-subspace-update-command.ts +++ b/src/space-model/commands/propagate-subspace-model-update-command.ts @@ -1,14 +1,14 @@ import { ICommand } from '@nestjs/cqrs'; import { SpaceModelEntity } from '@app/common/modules/space-model'; -import { ModifyspaceModelPayload } from '../interfaces'; -import { QueryRunner } from 'typeorm'; +import { ISingleSubspaceModel } from '../interfaces'; +import { SpaceEntity } from '@app/common/modules/space/entities/space.entity'; export class PropogateUpdateSpaceModelCommand implements ICommand { constructor( public readonly param: { spaceModel: SpaceModelEntity; - modifiedSpaceModels: ModifyspaceModelPayload; - queryRunner: QueryRunner; + subspaceModels: ISingleSubspaceModel[]; + spaces: SpaceEntity[]; }, ) {} } diff --git a/src/space-model/handlers/propate-subspace-handler.ts b/src/space-model/handlers/propate-subspace-handler.ts index 36936ff..2bef42a 100644 --- a/src/space-model/handlers/propate-subspace-handler.ts +++ b/src/space-model/handlers/propate-subspace-handler.ts @@ -2,18 +2,16 @@ import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; import { PropogateUpdateSpaceModelCommand } from '../commands'; import { SpaceRepository } from '@app/common/modules/space'; import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository'; -import { - SpaceModelEntity, - SubspaceModelEntity, - TagModel, -} from '@app/common/modules/space-model'; +import { SpaceModelEntity, TagModel } from '@app/common/modules/space-model'; import { DataSource, QueryRunner } from 'typeorm'; import { SubSpaceService } from 'src/space/services'; import { TagService } from 'src/space/services/tag'; -import { UpdatedSubspaceModelPayload } from '../interfaces'; -import { ModifyAction } from '@app/common/constants/modify-action.enum'; -import { ModifySubspaceDto } from 'src/space/dtos'; +import { + ISingleSubspaceModel, + UpdatedSubspaceModelPayload, +} from '../interfaces'; import { SpaceEntity } from '@app/common/modules/space/entities/space.entity'; +import { ModifyAction } from '@app/common/constants/modify-action.enum'; @CommandHandler(PropogateUpdateSpaceModelCommand) export class PropogateUpdateSpaceModelHandler @@ -28,86 +26,27 @@ export class PropogateUpdateSpaceModelHandler ) {} async execute(command: PropogateUpdateSpaceModelCommand): Promise { - const { spaceModel, modifiedSpaceModels, queryRunner } = command.param; + console.log("propagate"); + const { spaceModel, subspaceModels, spaces } = command.param; - try { - const spaces = await queryRunner.manager.find(SpaceEntity, { - where: { spaceModel }, - }); + if (!subspaceModels || subspaceModels.length === 0) return; - const { modifiedSubspaceModels = {}, modifiedTags = {} } = - modifiedSpaceModels; + if (!spaces) { + return; + } - const { - addedSubspaceModels = [], - updatedSubspaceModels = [], - deletedSubspaceModels = [], - } = modifiedSubspaceModels; - - const { added = [], updated = [], deleted = [] } = modifiedTags; - - if (addedSubspaceModels.length > 0) { - await this.addSubspaceModels( - modifiedSpaceModels.modifiedSubspaceModels.addedSubspaceModels, - spaces, - queryRunner, - ); - } else if (updatedSubspaceModels.length > 0) { - await this.updateSubspaceModels( - modifiedSpaceModels.modifiedSubspaceModels.updatedSubspaceModels, - queryRunner, - ); + for (const subspaceModel of subspaceModels) { + if (subspaceModel.action === ModifyAction.ADD) { + await this.addSubspaceModel(subspaceModel, spaces); } - if (deletedSubspaceModels.length > 0) { - const dtos: ModifySubspaceDto[] = - modifiedSpaceModels.modifiedSubspaceModels.deletedSubspaceModels.map( - (model) => ({ - action: ModifyAction.DELETE, - uuid: model, - }), - ); - await this.subSpaceService.modifySubSpace(dtos, queryRunner); - } - - if (added.length > 0) { - await this.createTags( - modifiedSpaceModels.modifiedTags.added, - queryRunner, - null, - spaceModel, - ); - } - - if (updated.length > 0) { - await this.updateTags( - modifiedSpaceModels.modifiedTags.updated, - queryRunner, - ); - } - - if (deleted.length > 0) { - await this.deleteTags( - modifiedSpaceModels.modifiedTags.deleted, - queryRunner, - ); - } - } catch (error) { - console.error(error); } } - async addSubspaceModels( - subspaceModels: SubspaceModelEntity[], + async addSubspaceModel( + subspaceModel: ISingleSubspaceModel, spaces: SpaceEntity[], - queryRunner: QueryRunner, ) { - for (const space of spaces) { - await this.subSpaceService.createSubSpaceFromModel( - subspaceModels, - [space], - queryRunner, - ); - } + console.log(`subspace is ${JSON.stringify(subspaceModel)}`); } async updateSubspaceModels( 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 07a84e5..6a477bf 100644 --- a/src/space-model/services/space-model-product-allocation.service.ts +++ b/src/space-model/services/space-model-product-allocation.service.ts @@ -365,14 +365,6 @@ export class SpaceModelProductAllocationService { ); } - await this.spaceProductAllocationService.propagateDeleteToInheritedAllocations( - queryRunner, - allocationsToUpdate, - tagUuidsToDelete, - project, - spaces, - ); - await queryRunner.manager .createQueryBuilder() .delete() diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts index 01dea08..e15c4aa 100644 --- a/src/space-model/services/space-model.service.ts +++ b/src/space-model/services/space-model.service.ts @@ -25,7 +25,10 @@ import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { CommandBus } from '@nestjs/cqrs'; import { ProcessTagDto } from 'src/tags/dtos'; import { SpaceModelProductAllocationService } from './space-model-product-allocation.service'; -import { PropogateDeleteSpaceModelCommand } from '../commands'; +import { + PropogateDeleteSpaceModelCommand, + PropogateUpdateSpaceModelCommand, +} from '../commands'; import { SpaceProductAllocationRepository, SpaceRepository, @@ -44,7 +47,6 @@ import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity'; import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity'; import { DeviceEntity } from '@app/common/modules/device/entities'; -import { ISingleSubspace } from 'src/space/interfaces/single-subspace.interface'; import { ISingleSubspaceModel } from '../interfaces'; @Injectable() @@ -239,6 +241,14 @@ export class SpaceModelService { } await queryRunner.commitTransaction(); + await this.commandBus.execute( + new PropogateUpdateSpaceModelCommand({ + spaceModel: spaceModel, + subspaceModels: modifiedSubspaces, + spaces: spaces, + }), + ); + return new SuccessResponseDto({ message: 'SpaceModel updated successfully', }); diff --git a/src/space-model/services/subspace/subspace-model.service.ts b/src/space-model/services/subspace/subspace-model.service.ts index 5f65644..da15ac4 100644 --- a/src/space-model/services/subspace/subspace-model.service.ts +++ b/src/space-model/services/subspace/subspace-model.service.ts @@ -155,7 +155,13 @@ export class SubSpaceModelService { queryRunner, spaceModel, ); - return [...createdSubspaces, ...updatedSubspaces, ...deletedSubspaces]; + return [ + createdSubspaces ?? [], + updatedSubspaces ?? [], + deletedSubspaces ?? [], + ] + .filter((arr) => arr.length > 0) + .flat(); } catch (error) { console.error('Error in modifySubspaceModels:', error); throw new HttpException( diff --git a/src/space/services/subspace/subspace-device.service.ts b/src/space/services/subspace/subspace-device.service.ts index 8fc062c..04e998e 100644 --- a/src/space/services/subspace/subspace-device.service.ts +++ b/src/space/services/subspace/subspace-device.service.ts @@ -81,24 +81,6 @@ export class SubspaceDeviceService { const subspace = await this.findSubspace(subSpaceUuid); const device = await this.findDevice(deviceUuid); - if (device.tag?.subspace?.uuid !== subspace.uuid) { - await this.tagRepository.update( - { uuid: device.tag.uuid }, - { subspace, space: null }, - ); - } - - if (!device.tag) { - const tag = this.tagRepository.create({ - tag: `Tag ${this.findNextTag()}`, - product: device.productDevice, - subspace: subspace, - device: device, - }); - await this.tagRepository.save(tag); - device.tag = tag; - } - device.subspace = subspace; const newDevice = await this.deviceRepository.save(device); @@ -140,26 +122,6 @@ export class SubspaceDeviceService { ); } - if (device.tag?.subspace !== null) { - await this.tagRepository.update( - { uuid: device.tag.uuid }, - { subspace: null, space: device.spaceDevice }, - ); - } - - if (!device.tag) { - const tag = this.tagRepository.create({ - tag: `Tag ${this.findNextTag()}`, - product: device.productDevice, - subspace: null, - space: device.spaceDevice, - device: device, - }); - - await this.tagRepository.save(tag); - device.tag = tag; - } - device.subspace = null; const updatedDevice = await this.deviceRepository.save(device);