Merge pull request #299 from SyncrowIOT:bugix/delete-subspace

Bugix/delete-subspace
This commit is contained in:
hannathkadher
2025-03-11 12:44:56 +04:00
committed by GitHub
6 changed files with 157 additions and 46 deletions

View File

@ -1,6 +1,9 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { PropogateUpdateSpaceModelCommand } from '../commands'; import { PropogateUpdateSpaceModelCommand } from '../commands';
import { SpaceRepository } from '@app/common/modules/space'; import {
SpaceProductAllocationRepository,
SpaceRepository,
} from '@app/common/modules/space';
import { import {
SubspaceProductAllocationRepository, SubspaceProductAllocationRepository,
SubspaceRepository, SubspaceRepository,
@ -10,7 +13,7 @@ import {
SubspaceModelProductAllocationRepoitory, SubspaceModelProductAllocationRepoitory,
TagModel, TagModel,
} from '@app/common/modules/space-model'; } from '@app/common/modules/space-model';
import { DataSource, QueryRunner } from 'typeorm'; import { DataSource, In, QueryRunner } from 'typeorm';
import { SubSpaceService } from 'src/space/services'; import { SubSpaceService } from 'src/space/services';
import { TagService } from 'src/space/services/tag'; import { TagService } from 'src/space/services/tag';
import { import {
@ -32,6 +35,7 @@ export class PropogateUpdateSpaceModelHandler
private readonly tagService: TagService, private readonly tagService: TagService,
private readonly subspaceModelProductRepository: SubspaceModelProductAllocationRepoitory, private readonly subspaceModelProductRepository: SubspaceModelProductAllocationRepoitory,
private readonly subspaceProductRepository: SubspaceProductAllocationRepository, private readonly subspaceProductRepository: SubspaceProductAllocationRepository,
private readonly spaceProductRepository: SpaceProductAllocationRepository,
) {} ) {}
async execute(command: PropogateUpdateSpaceModelCommand): Promise<void> { async execute(command: PropogateUpdateSpaceModelCommand): Promise<void> {
@ -43,6 +47,8 @@ export class PropogateUpdateSpaceModelHandler
for (const subspaceModel of subspaceModels) { for (const subspaceModel of subspaceModels) {
if (subspaceModel.action === ModifyAction.ADD) { if (subspaceModel.action === ModifyAction.ADD) {
await this.addSubspaceModel(subspaceModel, spaces); await this.addSubspaceModel(subspaceModel, spaces);
} else if (subspaceModel.action === ModifyAction.DELETE) {
await this.deleteSubspaceModel(subspaceModel, spaces);
} }
} }
} }
@ -84,6 +90,68 @@ export class PropogateUpdateSpaceModelHandler
} }
} }
async deleteSubspaceModel(
subspaceModel: ISingleSubspaceModel,
spaces: SpaceEntity[],
) {
const subspaces = await this.subspaceRepository.find({
where: {
subSpaceModel: { uuid: subspaceModel.subspaceModel.uuid },
disabled: false,
},
relations: [
'productAllocations',
'productAllocations.product',
'productAllocations.tags',
],
});
if (!subspaces.length) return;
const allocationUuidsToRemove = subspaces.flatMap((subspace) =>
subspace.productAllocations.map((allocation) => allocation.uuid),
);
if (allocationUuidsToRemove.length) {
await this.subspaceProductRepository.delete(allocationUuidsToRemove);
}
await this.subspaceRepository.update(
{ uuid: In(subspaces.map((s) => s.uuid)) },
{ disabled: true },
);
const relocatedAllocations = subspaceModel.relocatedAllocations || [];
if (!relocatedAllocations.length) return;
for (const space of spaces) {
for (const { allocation, tags = [] } of relocatedAllocations) {
const spaceAllocation = await this.spaceProductRepository.findOne({
where: {
inheritedFromModel: { uuid: allocation.uuid },
space: { uuid: space.uuid },
},
relations: ['tags'],
});
if (spaceAllocation) {
if (tags.length) {
spaceAllocation.tags.push(...tags);
await this.spaceProductRepository.save(spaceAllocation);
}
} else {
const newSpaceAllocation = this.spaceProductRepository.create({
space,
inheritedFromModel: allocation,
tags: allocation.tags,
product: allocation.product,
});
await this.spaceProductRepository.save(newSpaceAllocation);
}
}
}
}
async updateSubspaceModels( async updateSubspaceModels(
subspaceModels: UpdatedSubspaceModelPayload[], subspaceModels: UpdatedSubspaceModelPayload[],
queryRunner: QueryRunner, queryRunner: QueryRunner,

View File

@ -1,9 +1,18 @@
import { SubspaceModelEntity } from '@app/common/modules/space-model'; import {
SpaceModelProductAllocationEntity,
SubspaceModelEntity,
} from '@app/common/modules/space-model';
import { ModifyTagModelDto } from '../dtos'; import { ModifyTagModelDto } from '../dtos';
import { ModifyAction } from '@app/common/constants/modify-action.enum'; import { ModifyAction } from '@app/common/constants/modify-action.enum';
import { NewTagEntity } from '@app/common/modules/tag';
export interface IRelocatedAllocation {
allocation: SpaceModelProductAllocationEntity;
tags?: NewTagEntity[];
}
export interface ISingleSubspaceModel { export interface ISingleSubspaceModel {
subspaceModel: SubspaceModelEntity; subspaceModel: SubspaceModelEntity;
action: ModifyAction; action: ModifyAction;
tags: ModifyTagModelDto[]; tags?: ModifyTagModelDto[];
relocatedAllocations?: IRelocatedAllocation[];
} }

View File

@ -14,7 +14,6 @@ import { ModifyAction } from '@app/common/constants/modify-action.enum';
import { NewTagEntity } from '@app/common/modules/tag'; import { NewTagEntity } from '@app/common/modules/tag';
import { ProductEntity } from '@app/common/modules/product/entities'; import { ProductEntity } from '@app/common/modules/product/entities';
import { SpaceRepository } from '@app/common/modules/space'; import { SpaceRepository } from '@app/common/modules/space';
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
import { ProjectEntity } from '@app/common/modules/project/entities'; import { ProjectEntity } from '@app/common/modules/project/entities';
@Injectable() @Injectable()
@ -31,10 +30,11 @@ export class SpaceModelProductAllocationService {
tags: ProcessTagDto[], tags: ProcessTagDto[],
queryRunner?: QueryRunner, queryRunner?: QueryRunner,
modifySubspaceModels?: ModifySubspaceModelDto[], modifySubspaceModels?: ModifySubspaceModelDto[],
spaces?: SpaceEntity[],
): Promise<SpaceModelProductAllocationEntity[]> { ): Promise<SpaceModelProductAllocationEntity[]> {
try { try {
if (!tags.length) return []; if (!tags.length) {
return [];
}
const processedTags = await this.tagService.processTags( const processedTags = await this.tagService.processTags(
tags, tags,
@ -81,6 +81,7 @@ export class SpaceModelProductAllocationService {
) )
) { ) {
isTagNeeded = true; isTagNeeded = true;
break; break;
} }
} }
@ -93,7 +94,9 @@ export class SpaceModelProductAllocationService {
spaceModel, spaceModel,
); );
if (hasTags) continue; if (hasTags) {
continue;
}
let allocation = existingAllocations.get(tag.product.uuid); let allocation = existingAllocations.get(tag.product.uuid);
if (!allocation) { if (!allocation) {
@ -120,9 +123,11 @@ export class SpaceModelProductAllocationService {
if (productAllocations.length > 0) { if (productAllocations.length > 0) {
await this.saveAllocations(productAllocations, queryRunner); await this.saveAllocations(productAllocations, queryRunner);
} }
return productAllocations; return productAllocations;
} catch (error) { } catch (error) {
console.error(
`[ERROR] Failed to create product allocations: ${error.message}`,
);
throw this.handleError(error, 'Failed to create product allocations'); throw this.handleError(error, 'Failed to create product allocations');
} }
} }
@ -133,7 +138,6 @@ export class SpaceModelProductAllocationService {
spaceModel: SpaceModelEntity, spaceModel: SpaceModelEntity,
queryRunner: QueryRunner, queryRunner: QueryRunner,
modifySubspaceModels?: ModifySubspaceModelDto[], modifySubspaceModels?: ModifySubspaceModelDto[],
spaces?: SpaceEntity[],
): Promise<void> { ): Promise<void> {
try { try {
const addDtos = dtos.filter((dto) => dto.action === ModifyAction.ADD); const addDtos = dtos.filter((dto) => dto.action === ModifyAction.ADD);
@ -184,15 +188,8 @@ export class SpaceModelProductAllocationService {
spaceModel, spaceModel,
queryRunner, queryRunner,
modifySubspaceModels, modifySubspaceModels,
spaces,
),
this.processDeleteActions(
filteredDtos,
queryRunner,
spaceModel,
project,
spaces,
), ),
this.processDeleteActions(filteredDtos, queryRunner, spaceModel),
]); ]);
} catch (error) { } catch (error) {
throw this.handleError(error, 'Error while updating product allocations'); throw this.handleError(error, 'Error while updating product allocations');
@ -205,7 +202,6 @@ export class SpaceModelProductAllocationService {
spaceModel: SpaceModelEntity, spaceModel: SpaceModelEntity,
queryRunner: QueryRunner, queryRunner: QueryRunner,
modifySubspaceModels?: ModifySubspaceModelDto[], modifySubspaceModels?: ModifySubspaceModelDto[],
spaces?: SpaceEntity[],
): Promise<void> { ): Promise<void> {
const addDtos: ProcessTagDto[] = dtos const addDtos: ProcessTagDto[] = dtos
.filter((dto) => dto.action === ModifyAction.ADD) .filter((dto) => dto.action === ModifyAction.ADD)
@ -222,7 +218,6 @@ export class SpaceModelProductAllocationService {
addDtos, addDtos,
queryRunner, queryRunner,
modifySubspaceModels, modifySubspaceModels,
spaces,
); );
} }
} }
@ -298,8 +293,6 @@ export class SpaceModelProductAllocationService {
dtos: ModifyTagModelDto[], dtos: ModifyTagModelDto[],
queryRunner: QueryRunner, queryRunner: QueryRunner,
spaceModel: SpaceModelEntity, spaceModel: SpaceModelEntity,
project: ProjectEntity,
spaces?: SpaceEntity[],
): Promise<SpaceModelProductAllocationEntity[]> { ): Promise<SpaceModelProductAllocationEntity[]> {
try { try {
if (!dtos || dtos.length === 0) { if (!dtos || dtos.length === 0) {
@ -409,7 +402,7 @@ export class SpaceModelProductAllocationService {
(allocation) => allocation.tags, (allocation) => allocation.tags,
); );
// Check if the tag is already assigned to the same product in this subspace // Check if the tag is already assigned to the same product in this space
const isDuplicateTag = existingTagsForProduct.some( const isDuplicateTag = existingTagsForProduct.some(
(existingTag) => existingTag.uuid === tag.uuid, (existingTag) => existingTag.uuid === tag.uuid,
); );

View File

@ -481,7 +481,6 @@ export class SpaceModelService {
await this.subspaceRepository.save(subspace); await this.subspaceRepository.save(subspace);
} }
const subspaceAllocations = subspaceModel.productAllocations.map( const subspaceAllocations = subspaceModel.productAllocations.map(
(modelAllocation) => (modelAllocation) =>
this.subspaceProductAllocationRepository.create({ this.subspaceProductAllocationRepository.create({

View File

@ -13,7 +13,10 @@ import { ModifyAction } from '@app/common/constants/modify-action.enum';
import { ProcessTagDto } from 'src/tags/dtos'; import { ProcessTagDto } from 'src/tags/dtos';
import { TagService } from 'src/tags/services'; import { TagService } from 'src/tags/services';
import { SubspaceModelProductAllocationService } from './subspace-model-product-allocation.service'; import { SubspaceModelProductAllocationService } from './subspace-model-product-allocation.service';
import { ISingleSubspaceModel } from 'src/space-model/interfaces'; import {
IRelocatedAllocation,
ISingleSubspaceModel,
} from 'src/space-model/interfaces';
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity'; import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
import { SubSpaceService } from 'src/space/services/subspace'; import { SubSpaceService } from 'src/space/services/subspace';
@ -154,6 +157,7 @@ export class SubSpaceModelService {
deleteDtos, deleteDtos,
queryRunner, queryRunner,
spaceModel, spaceModel,
spaceTagUpdateDtos,
); );
return [ return [
createdSubspaces ?? [], createdSubspaces ?? [],
@ -179,10 +183,11 @@ export class SubSpaceModelService {
deleteDtos: ModifySubspaceModelDto[], deleteDtos: ModifySubspaceModelDto[],
queryRunner: QueryRunner, queryRunner: QueryRunner,
spaceModel: SpaceModelEntity, spaceModel: SpaceModelEntity,
spaceTagUpdateDtos?: ModifyTagModelDto[],
): Promise<ISingleSubspaceModel[]> { ): Promise<ISingleSubspaceModel[]> {
try { try {
if (!deleteDtos || deleteDtos.length === 0) { if (!deleteDtos || deleteDtos.length === 0) {
return; return [];
} }
const deleteResults = []; const deleteResults = [];
@ -205,10 +210,14 @@ export class SubSpaceModelService {
{ disabled: true }, { disabled: true },
); );
const allocationsToRemove = subspaces.flatMap( const allocationsToRemove = subspaces.flatMap((subspace) =>
(subspace) => subspace.productAllocations, (subspace.productAllocations || []).map((allocation) => ({
...allocation,
subspaceModel: subspace,
})),
); );
const relocatedAllocationsMap = new Map<string, IRelocatedAllocation[]>();
if (allocationsToRemove.length > 0) { if (allocationsToRemove.length > 0) {
const spaceAllocationsMap = new Map< const spaceAllocationsMap = new Map<
string, string,
@ -218,7 +227,7 @@ export class SubSpaceModelService {
for (const allocation of allocationsToRemove) { for (const allocation of allocationsToRemove) {
const product = allocation.product; const product = allocation.product;
const tags = allocation.tags; const tags = allocation.tags;
const subspaceUuid = allocation.subspaceModel.uuid;
const spaceAllocationKey = `${spaceModel.uuid}-${product.uuid}`; const spaceAllocationKey = `${spaceModel.uuid}-${product.uuid}`;
if (!spaceAllocationsMap.has(spaceAllocationKey)) { if (!spaceAllocationsMap.has(spaceAllocationKey)) {
@ -237,7 +246,10 @@ export class SubSpaceModelService {
} }
} }
const movedToAlreadyExistingSpaceAllocations: IRelocatedAllocation[] =
[];
const spaceAllocation = spaceAllocationsMap.get(spaceAllocationKey); const spaceAllocation = spaceAllocationsMap.get(spaceAllocationKey);
if (spaceAllocation) { if (spaceAllocation) {
const existingTagUuids = new Set( const existingTagUuids = new Set(
spaceAllocation.tags.map((tag) => tag.uuid), spaceAllocation.tags.map((tag) => tag.uuid),
@ -247,19 +259,57 @@ export class SubSpaceModelService {
); );
if (newTags.length > 0) { if (newTags.length > 0) {
movedToAlreadyExistingSpaceAllocations.push({
tags: newTags,
allocation: spaceAllocation,
});
spaceAllocation.tags.push(...newTags); spaceAllocation.tags.push(...newTags);
await queryRunner.manager.save(spaceAllocation); await queryRunner.manager.save(spaceAllocation);
} }
} else { } else {
const newSpaceAllocation = queryRunner.manager.create( let tagsToAdd = [...tags];
SpaceModelProductAllocationEntity,
{ if (spaceTagUpdateDtos && spaceTagUpdateDtos.length > 0) {
spaceModel: spaceModel, const spaceTagDtosToAdd = spaceTagUpdateDtos.filter(
product: product, (dto) => dto.action === ModifyAction.ADD,
);
tagsToAdd = tagsToAdd.filter(
(tag) =>
!spaceTagDtosToAdd.some(
(addDto) =>
(addDto.name && addDto.name === tag.name) ||
(addDto.newTagUuid && addDto.newTagUuid === tag.uuid),
),
);
}
if (tagsToAdd.length > 0) {
const newSpaceAllocation = queryRunner.manager.create(
SpaceModelProductAllocationEntity,
{
spaceModel: spaceModel,
product: product,
tags: tags,
},
);
movedToAlreadyExistingSpaceAllocations.push({
allocation: newSpaceAllocation,
tags: tags, tags: tags,
}, });
); await queryRunner.manager.save(newSpaceAllocation);
await queryRunner.manager.save(newSpaceAllocation); }
}
if (movedToAlreadyExistingSpaceAllocations.length > 0) {
if (!relocatedAllocationsMap.has(subspaceUuid)) {
relocatedAllocationsMap.set(subspaceUuid, []);
}
relocatedAllocationsMap
.get(subspaceUuid)
.push(...movedToAlreadyExistingSpaceAllocations);
} }
} }
@ -289,7 +339,7 @@ export class SubSpaceModelService {
return subspaces.map((subspace) => ({ return subspaces.map((subspace) => ({
subspaceModel: subspace, subspaceModel: subspace,
action: ModifyAction.DELETE, action: ModifyAction.DELETE,
tags: [], relocatedAllocations: relocatedAllocationsMap.get(subspace.uuid) || [],
})); }));
} catch (error) { } catch (error) {
if (error instanceof QueryFailedError) { if (error instanceof QueryFailedError) {

View File

@ -27,7 +27,6 @@ import {
ORPHAN_SPACE_NAME, ORPHAN_SPACE_NAME,
} from '@app/common/constants/orphan-constant'; } from '@app/common/constants/orphan-constant';
import { CommandBus } from '@nestjs/cqrs'; import { CommandBus } from '@nestjs/cqrs';
import { TagService } from './tag';
import { TagService as NewTagService } from 'src/tags/services/tags.service'; import { TagService as NewTagService } from 'src/tags/services/tags.service';
import { SpaceModelService } from 'src/space-model/services'; import { SpaceModelService } from 'src/space-model/services';
import { DisableSpaceCommand } from '../commands'; import { DisableSpaceCommand } from '../commands';
@ -36,10 +35,7 @@ import { removeCircularReferences } from '@app/common/helper/removeCircularRefer
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity'; import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
import { ProcessTagDto } from 'src/tags/dtos'; import { ProcessTagDto } from 'src/tags/dtos';
import { SpaceProductAllocationService } from './space-product-allocation.service'; 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 { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
import { DeviceRepository } from '@app/common/modules/device/repositories';
import { DeviceService } from 'src/device/services';
@Injectable() @Injectable()
export class SpaceService { export class SpaceService {
constructor( constructor(
@ -49,14 +45,10 @@ export class SpaceService {
private readonly spaceLinkService: SpaceLinkService, private readonly spaceLinkService: SpaceLinkService,
private readonly subSpaceService: SubSpaceService, private readonly subSpaceService: SubSpaceService,
private readonly validationService: ValidationService, private readonly validationService: ValidationService,
private readonly tagService: TagService,
private readonly newTagService: NewTagService, private readonly newTagService: NewTagService,
private readonly spaceModelService: SpaceModelService, private readonly spaceModelService: SpaceModelService,
private commandBus: CommandBus, private commandBus: CommandBus,
private readonly spaceProductAllocationService: SpaceProductAllocationService, private readonly spaceProductAllocationService: SpaceProductAllocationService,
private readonly subspaceProductAllocationService: SubspaceProductAllocationService,
private readonly deviceRepository: DeviceRepository,
private readonly deviceSevice: DeviceService,
) {} ) {}
async createSpace( async createSpace(