Files
backend/src/space-model/handlers/propogate-subspace-handler.ts
2025-03-12 23:08:18 +04:00

287 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { PropogateUpdateSpaceModelCommand } from '../commands';
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 { ISingleSubspaceModel } from '../interfaces';
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
import { ModifyAction } from '@app/common/constants/modify-action.enum';
import { IUpdatedAllocations } from '../interfaces/subspace-product-allocation-update-result.interface';
@CommandHandler(PropogateUpdateSpaceModelCommand)
export class PropogateUpdateSpaceModelHandler
implements ICommandHandler<PropogateUpdateSpaceModelCommand>
{
constructor(
private readonly subspaceRepository: SubspaceRepository,
private readonly subspaceModelProductRepository: SubspaceModelProductAllocationRepoitory,
private readonly subspaceProductRepository: SubspaceProductAllocationRepository,
private readonly spaceProductRepository: SpaceProductAllocationRepository,
) {}
async execute(command: PropogateUpdateSpaceModelCommand): Promise<void> {
const { subspaceUpdates, spaces } = command.param;
try {
if (!subspaceUpdates?.subspaceModels?.length) return; // Exit if no updates
if (!spaces?.length) return; // Exit if no spaces
const subspaceModels = subspaceUpdates.subspaceModels;
// 🔹 Filter subspace models by action
const subspacesToAdd = subspaceModels.filter(
(m) => m.action === ModifyAction.ADD,
);
const subspacesToUpdate = subspaceModels.filter(
(m) => m.action === ModifyAction.UPDATE,
);
const subspacesToDelete = subspaceModels.filter(
(m) => m.action === ModifyAction.DELETE,
);
// 1⃣ Create Subspace Models First (if any)
await Promise.all(
subspacesToAdd.map((m) => this.addSubspaceModel(m, spaces)),
);
// 2⃣ Update Allocations
await this.updateAllocations(subspaceUpdates.updatedAllocations);
// 3⃣ Update Existing Subspace Models (if any)
await Promise.all(
subspacesToUpdate.map((m) => this.updateSubspaceModel(m)),
);
// 4⃣ Delete Subspace Models (if any)
await Promise.all(
subspacesToDelete.map((m) => this.deleteSubspaceModel(m, spaces)),
);
console.log('Successfully executed PropogateUpdateSpaceModelCommand');
} catch (error) {
console.error('Error processing subspace model updates', error);
}
}
async updateAllocations(allocations: IUpdatedAllocations[]) {
try {
for (const allocation of allocations) {
if (!allocation) continue;
if (allocation.allocation) {
try {
const subspaceAllocations =
await this.subspaceProductRepository.find({
where: {
inheritedFromModel: { uuid: allocation.allocation.uuid },
},
relations: ['tags'],
});
if (!subspaceAllocations || subspaceAllocations.length === 0)
continue;
if (allocation.tagsAdded?.length) {
for (const subspaceAllocation of subspaceAllocations) {
subspaceAllocation.tags.push(...allocation.tagsAdded);
}
await this.subspaceProductRepository.save(subspaceAllocations);
console.log(
`Added tags to ${subspaceAllocations.length} subspace allocations.`,
);
}
if (allocation.tagsRemoved?.length) {
const tagsToRemoveUUIDs = allocation.tagsRemoved.map(
(tag) => tag.uuid,
);
for (const subspaceAllocation of subspaceAllocations) {
subspaceAllocation.tags = subspaceAllocation.tags.filter(
(tag) => !tagsToRemoveUUIDs.includes(tag.uuid),
);
}
await this.subspaceProductRepository.save(subspaceAllocations);
console.log(
`Removed tags from ${subspaceAllocations.length} subspace allocations.`,
);
}
} catch (error) {
console.error('Error processing allocation update:', error);
}
}
if (allocation.newAllocation) {
try {
const subspaceModel = allocation.newAllocation.subspaceModel;
const subspaces = await this.subspaceRepository.find({
where: { subSpaceModel: { uuid: subspaceModel.uuid } },
});
if (!subspaces || subspaces.length === 0) continue;
const newAllocations = subspaces.map((subspace) =>
this.subspaceProductRepository.create({
product: allocation.newAllocation.product,
tags: allocation.newAllocation.tags,
subspace,
inheritedFromModel: allocation.newAllocation,
}),
);
await this.subspaceProductRepository.save(newAllocations);
console.log(
`Created ${newAllocations.length} new subspace allocations.`,
);
} catch (error) {
console.error('Error creating new subspace allocation:', error);
}
}
if (allocation.deletedAllocation) {
try {
const subspaceAllocations =
await this.subspaceProductRepository.find({
where: {
inheritedFromModel: {
uuid: allocation.deletedAllocation.uuid,
},
},
});
if (!subspaceAllocations || subspaceAllocations.length === 0)
continue;
await this.subspaceProductRepository.remove(subspaceAllocations);
console.log(
`Deleted ${subspaceAllocations.length} subspace allocations.`,
);
} catch (error) {
console.error('Error deleting subspace allocation:', error);
}
}
}
} catch (error) {
console.error('Error in updateAllocations method:', error);
}
}
async addSubspaceModel(
subspaceModel: ISingleSubspaceModel,
spaces: SpaceEntity[],
) {
const subspaceModelAllocations =
await this.subspaceModelProductRepository.find({
where: {
subspaceModel: {
uuid: subspaceModel.subspaceModel.uuid,
},
},
relations: ['tags', 'product'],
});
for (const space of spaces) {
const subspace = this.subspaceRepository.create({
subspaceName: subspaceModel.subspaceModel.subspaceName,
space: space,
});
subspace.subSpaceModel = subspaceModel.subspaceModel;
await this.subspaceRepository.save(subspace);
if (subspaceModelAllocations?.length > 0) {
for (const allocation of subspaceModelAllocations) {
const subspaceAllocation = this.subspaceProductRepository.create({
subspace: subspace,
product: allocation.product,
tags: allocation.tags,
inheritedFromModel: allocation,
});
await this.subspaceProductRepository.save(subspaceAllocation);
}
}
}
}
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 updateSubspaceModel(subspaceModel: ISingleSubspaceModel) {
return this.subspaceRepository.update(
{
subSpaceModel: { uuid: subspaceModel.subspaceModel.uuid },
disabled: false,
},
{ subspaceName: subspaceModel.subspaceModel.subspaceName },
);
}
}