updated space product model allocation

This commit is contained in:
hannathkadher
2025-03-12 23:08:18 +04:00
parent 537f20f8de
commit 8cbbb3a8ba
10 changed files with 222 additions and 25 deletions

View File

@ -1,2 +1,3 @@
export * from './propagate-space-model-deletion.command';
export * from './propagate-subspace-model-update-command';
export * from './propagate-space-model-product-allocation-command';

View File

@ -0,0 +1,16 @@
import { ICommand } from '@nestjs/cqrs';
import { SpaceModelEntity } from '@app/common/modules/space-model';
import { IUpdatedSpaceAllocations } from '../interfaces';
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
export class PropogateUpdateSpaceModelProductAllocationCommand
implements ICommand
{
constructor(
public readonly param: {
spaceModel: SpaceModelEntity;
updatedAllocations: IUpdatedSpaceAllocations[];
spaces: SpaceEntity[];
},
) {}
}

View File

@ -1,2 +1,3 @@
export * from './propate-subspace-handler';
export * from './propogate-subspace-handler';
export * from './propogate-space-model-deletion.handler';
export * from './propogate-space-model-product-allocation.handler';

View File

@ -0,0 +1,123 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { PropogateUpdateSpaceModelProductAllocationCommand } from '../commands';
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
import { SubspaceModelProductAllocationRepoitory } from '@app/common/modules/space-model';
import {
SubspaceRepository,
SubspaceProductAllocationRepository,
} from '@app/common/modules/space/repositories/subspace.repository';
@CommandHandler(PropogateUpdateSpaceModelProductAllocationCommand)
export class PropogateUpdateSpaceModelProductAllocationHandler
implements ICommandHandler<PropogateUpdateSpaceModelProductAllocationCommand>
{
constructor(
private readonly subspaceRepository: SubspaceRepository,
private readonly subspaceModelProductRepository: SubspaceModelProductAllocationRepoitory,
private readonly subspaceProductRepository: SubspaceProductAllocationRepository,
private readonly spaceProductRepository: SpaceProductAllocationRepository,
) {}
async execute(
command: PropogateUpdateSpaceModelProductAllocationCommand,
): Promise<void> {
const { spaces, updatedAllocations } = command.param;
try {
if (!updatedAllocations || updatedAllocations.length === 0) {
console.log('No updated allocations found. Exiting execution.');
return;
}
console.log(`Processing ${updatedAllocations.length} allocations...`);
for (const allocation of updatedAllocations) {
try {
if (allocation.allocation) {
const spaceAllocations = await this.spaceProductRepository.find({
where: { uuid: allocation.allocation.uuid },
relations: ['tags'],
});
if (!spaceAllocations || spaceAllocations.length === 0) {
console.warn(
`No space allocations found for UUID: ${allocation.allocation.uuid}`,
);
continue;
}
if (allocation.tagsAdded?.length) {
for (const spaceAllocation of spaceAllocations) {
spaceAllocation.tags.push(...allocation.tagsAdded);
}
await this.spaceProductRepository.save(spaceAllocations);
console.log(
`Added tags to ${spaceAllocations.length} space allocations.`,
);
}
if (allocation.tagsRemoved?.length) {
const tagsToRemoveUUIDs = new Set(
allocation.tagsRemoved.map((tag) => tag.uuid),
);
for (const spaceAllocation of spaceAllocations) {
spaceAllocation.tags = spaceAllocation.tags.filter(
(tag) => !tagsToRemoveUUIDs.has(tag.uuid),
);
}
await this.spaceProductRepository.save(spaceAllocations);
console.log(
`Removed tags from ${spaceAllocations.length} space allocations.`,
);
}
}
if (allocation.deletedAllocation) {
const spaceAllocations = await this.spaceProductRepository.find({
where: { uuid: allocation.deletedAllocation.uuid },
relations: ['tags'],
});
if (!spaceAllocations || spaceAllocations.length === 0) {
console.warn(
`No space allocations found to delete for UUID: ${allocation.deletedAllocation.uuid}`,
);
continue;
}
await this.spaceProductRepository.remove(spaceAllocations);
console.log(
`Deleted ${spaceAllocations.length} space allocations.`,
);
}
if (allocation.newAllocation) {
const newAllocations = spaces.map((space) =>
this.spaceProductRepository.create({
space,
product: allocation.newAllocation.product,
tags: allocation.newAllocation.tags,
inheritedFromModel: allocation.newAllocation,
}),
);
await this.spaceProductRepository.save(newAllocations);
console.log(
`Created ${newAllocations.length} new space allocations.`,
);
}
} catch (error) {
console.error(
`Error processing allocation update: ${JSON.stringify(allocation)}`,
error,
);
}
}
console.log('Finished processing all allocations.');
} catch (error) {
console.error('Unexpected error during execute method:', error);
}
}
}

View File

@ -1,16 +1,12 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { PropogateUpdateSpaceModelCommand } from '../commands';
import {
SpaceProductAllocationRepository,
SpaceRepository,
} from '@app/common/modules/space';
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
import {
SubspaceProductAllocationRepository,
SubspaceRepository,
} from '@app/common/modules/space/repositories/subspace.repository';
import { SubspaceModelProductAllocationRepoitory } from '@app/common/modules/space-model';
import { In } from 'typeorm';
import { TagService } from 'src/space/services/tag';
import { ISingleSubspaceModel } from '../interfaces';
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
import { ModifyAction } from '@app/common/constants/modify-action.enum';
@ -21,9 +17,7 @@ export class PropogateUpdateSpaceModelHandler
implements ICommandHandler<PropogateUpdateSpaceModelCommand>
{
constructor(
private readonly spaceRepository: SpaceRepository,
private readonly subspaceRepository: SubspaceRepository,
private readonly tagService: TagService,
private readonly subspaceModelProductRepository: SubspaceModelProductAllocationRepoitory,
private readonly subspaceProductRepository: SubspaceProductAllocationRepository,
private readonly spaceProductRepository: SpaceProductAllocationRepository,

View File

@ -1,3 +1,4 @@
export * from './update-subspace.interface';
export * from './modify-subspace.interface';
export * from './single-subspace.interface';
export * from './space-product-allocation.interface';

View File

@ -0,0 +1,10 @@
import { SpaceModelProductAllocationEntity } from '@app/common/modules/space-model';
import { NewTagEntity } from '@app/common/modules/tag';
export type IUpdatedSpaceAllocations = {
allocation?: SpaceModelProductAllocationEntity;
tagsRemoved?: NewTagEntity[];
tagsAdded?: NewTagEntity[];
newAllocation?: SpaceModelProductAllocationEntity;
deletedAllocation?: SpaceModelProductAllocationEntity;
};

View File

@ -15,6 +15,7 @@ import { NewTagEntity } from '@app/common/modules/tag';
import { ProductEntity } from '@app/common/modules/product/entities';
import { SpaceRepository } from '@app/common/modules/space';
import { ProjectEntity } from '@app/common/modules/project/entities';
import { IUpdatedSpaceAllocations } from '../interfaces';
@Injectable()
export class SpaceModelProductAllocationService {
@ -30,10 +31,12 @@ export class SpaceModelProductAllocationService {
tags: ProcessTagDto[],
queryRunner?: QueryRunner,
modifySubspaceModels?: ModifySubspaceModelDto[],
): Promise<SpaceModelProductAllocationEntity[]> {
): Promise<IUpdatedSpaceAllocations[]> {
try {
if (!tags.length) return [];
const allocationUpdates: IUpdatedSpaceAllocations[] = [];
const processedTags = await this.tagService.processTags(
tags,
projectUuid,
@ -108,8 +111,15 @@ export class SpaceModelProductAllocationService {
if (!allocation) {
allocation = this.createNewAllocation(spaceModel, tag, queryRunner);
productAllocations.push(allocation);
allocationUpdates.push({
newAllocation: allocation,
});
} else if (!allocation.tags.some((t) => t.uuid === tag.uuid)) {
allocation.tags.push(tag);
allocationUpdates.push({
allocation: allocation,
tagsAdded: [tag],
});
await this.saveAllocation(allocation, queryRunner);
}
}
@ -119,7 +129,7 @@ export class SpaceModelProductAllocationService {
await this.saveAllocations(productAllocations, queryRunner);
}
return productAllocations;
return allocationUpdates;
} catch (error) {
throw this.handleError(error, 'Failed to create product allocations');
}
@ -131,7 +141,7 @@ export class SpaceModelProductAllocationService {
spaceModel: SpaceModelEntity,
queryRunner: QueryRunner,
modifySubspaceModels?: ModifySubspaceModelDto[],
): Promise<void> {
): Promise<IUpdatedSpaceAllocations[]> {
try {
const addDtos = dtos.filter((dto) => dto.action === ModifyAction.ADD);
const deleteDtos = dtos.filter(
@ -144,11 +154,13 @@ export class SpaceModelProductAllocationService {
uuid: dto.newTagUuid,
}));
// Process added tags
const processedTags = await this.tagService.processTags(
addTagDtos,
project.uuid,
queryRunner,
);
const addTagUuidMap = new Map<string, ModifyTagModelDto>();
processedTags.forEach((tag, index) => {
addTagUuidMap.set(tag.uuid, addDtos[index]);
@ -161,6 +173,7 @@ export class SpaceModelProductAllocationService {
[...addTagUuids].filter((uuid) => deleteTagUuids.has(uuid)),
);
// Filter out tags that are added and deleted in the same request
const filteredDtos = dtos.filter(
(dto) =>
!(
@ -174,7 +187,8 @@ export class SpaceModelProductAllocationService {
),
);
await Promise.all([
// Process add and delete actions concurrently
const [updatedAllocations, deletedAllocations] = await Promise.all([
this.processAddActions(
filteredDtos,
project.uuid,
@ -184,6 +198,9 @@ export class SpaceModelProductAllocationService {
),
this.processDeleteActions(filteredDtos, queryRunner, spaceModel),
]);
// Combine results and return
return [...updatedAllocations, ...deletedAllocations];
} catch (error) {
throw this.handleError(error, 'Error while updating product allocations');
}
@ -195,7 +212,9 @@ export class SpaceModelProductAllocationService {
spaceModel: SpaceModelEntity,
queryRunner: QueryRunner,
modifySubspaceModels?: ModifySubspaceModelDto[],
): Promise<void> {
): Promise<IUpdatedSpaceAllocations[]> {
let allocationUpdates: IUpdatedSpaceAllocations[] = [];
const addDtos: ProcessTagDto[] = dtos
.filter((dto) => dto.action === ModifyAction.ADD)
.map((dto) => ({
@ -205,7 +224,7 @@ export class SpaceModelProductAllocationService {
}));
if (addDtos.length > 0) {
await this.createProductAllocations(
allocationUpdates = await this.createProductAllocations(
projectUuid,
spaceModel,
addDtos,
@ -213,6 +232,7 @@ export class SpaceModelProductAllocationService {
modifySubspaceModels,
);
}
return allocationUpdates;
}
private createNewAllocation(
@ -292,11 +312,12 @@ export class SpaceModelProductAllocationService {
dtos: ModifyTagModelDto[],
queryRunner: QueryRunner,
spaceModel: SpaceModelEntity,
): Promise<SpaceModelProductAllocationEntity[]> {
): Promise<IUpdatedSpaceAllocations[]> {
try {
if (!dtos || dtos.length === 0) {
return;
}
let allocationUpdateToPropagate: IUpdatedSpaceAllocations[] = [];
const tagUuidsToDelete = dtos
.filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
@ -331,15 +352,26 @@ export class SpaceModelProductAllocationService {
(tag) => !tagUuidsToDelete.includes(tag.uuid),
);
const deletedTags = allocation.tags.filter((tag) =>
tagUuidsToDelete.includes(tag.uuid),
);
if (updatedTags.length === allocation.tags.length) {
continue;
}
if (updatedTags.length === 0) {
deletedAllocations.push(allocation);
allocationUpdateToPropagate.push({
deletedAllocation: allocation,
});
} else {
allocation.tags = updatedTags;
allocationUpdates.push(allocation);
allocationUpdateToPropagate.push({
allocation: allocation,
tagsRemoved: deletedTags,
});
}
}
@ -372,7 +404,7 @@ export class SpaceModelProductAllocationService {
)
.execute();
return deletedAllocations;
return allocationUpdateToPropagate;
} catch (error) {
throw this.handleError(error, `Failed to delete tags in space model`);
}

View File

@ -28,6 +28,7 @@ import { SpaceModelProductAllocationService } from './space-model-product-alloca
import {
PropogateDeleteSpaceModelCommand,
PropogateUpdateSpaceModelCommand,
PropogateUpdateSpaceModelProductAllocationCommand,
} from '../commands';
import {
SpaceProductAllocationRepository,
@ -47,7 +48,11 @@ 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 { ISingleSubspaceModel, ISubspaceModelUpdates } from '../interfaces';
import {
ISingleSubspaceModel,
ISubspaceModelUpdates,
IUpdatedSpaceAllocations,
} from '../interfaces';
@Injectable()
export class SpaceModelService {
@ -200,6 +205,7 @@ export class SpaceModelService {
);
await queryRunner.connect();
let modifiedSubspaces: ISubspaceModelUpdates;
let modifiedProductAllocations: IUpdatedSpaceAllocations[];
try {
await queryRunner.startTransaction();
const spaces = await this.fetchModelSpaces(spaceModel);
@ -230,24 +236,35 @@ export class SpaceModelService {
}
if (dto.tags) {
await this.spaceModelProductAllocationService.updateProductAllocations(
dto.tags,
project,
spaceModel,
queryRunner,
dto.subspaceModels,
);
modifiedProductAllocations =
await this.spaceModelProductAllocationService.updateProductAllocations(
dto.tags,
project,
spaceModel,
queryRunner,
dto.subspaceModels,
);
}
await queryRunner.commitTransaction();
await this.commandBus.execute(
new PropogateUpdateSpaceModelCommand({
spaceModel: spaceModel,
subspaceModels: modifiedSubspaces,
subspaceUpdates: modifiedSubspaces,
spaces: spaces,
}),
);
if (modifiedProductAllocations?.length > 0) {
await this.commandBus.execute(
new PropogateUpdateSpaceModelProductAllocationCommand({
spaceModel: spaceModel,
updatedAllocations: modifiedProductAllocations,
spaces: spaces,
}),
);
}
return new SuccessResponseDto({
message: 'SpaceModel updated successfully',
});

View File

@ -15,6 +15,7 @@ import { ProductRepository } from '@app/common/modules/product/repositories';
import {
PropogateDeleteSpaceModelHandler,
PropogateUpdateSpaceModelHandler,
PropogateUpdateSpaceModelProductAllocationHandler,
} from './handlers';
import { CqrsModule } from '@nestjs/cqrs';
import {
@ -60,6 +61,7 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie
const CommandHandlers = [
PropogateUpdateSpaceModelHandler,
PropogateDeleteSpaceModelHandler,
PropogateUpdateSpaceModelProductAllocationHandler,
];
@Module({