mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-10 15:17:41 +00:00
Merge branch 'dev'
This commit is contained in:
@ -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';
|
@ -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[];
|
||||
},
|
||||
) {}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
import { ICommand } from '@nestjs/cqrs';
|
||||
import { SpaceModelEntity } from '@app/common/modules/space-model';
|
||||
import { ISingleSubspaceModel } from '../interfaces';
|
||||
import { ISubspaceModelUpdates } from '../interfaces';
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||
|
||||
export class PropogateUpdateSpaceModelCommand implements ICommand {
|
||||
constructor(
|
||||
public readonly param: {
|
||||
spaceModel: SpaceModelEntity;
|
||||
subspaceModels: ISingleSubspaceModel[];
|
||||
subspaceUpdates: ISubspaceModelUpdates;
|
||||
spaces: SpaceEntity[];
|
||||
},
|
||||
) {}
|
||||
|
@ -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';
|
||||
|
@ -1,303 +0,0 @@
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
import { PropogateUpdateSpaceModelCommand } from '../commands';
|
||||
import {
|
||||
SpaceProductAllocationRepository,
|
||||
SpaceRepository,
|
||||
} from '@app/common/modules/space';
|
||||
import {
|
||||
SubspaceProductAllocationRepository,
|
||||
SubspaceRepository,
|
||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SubspaceModelProductAllocationRepoitory,
|
||||
TagModel,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { In, QueryRunner } from 'typeorm';
|
||||
import { TagService } from 'src/space/services/tag';
|
||||
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
|
||||
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,
|
||||
) {}
|
||||
|
||||
async execute(command: PropogateUpdateSpaceModelCommand): Promise<void> {
|
||||
const { subspaceModels, spaces } = command.param;
|
||||
try {
|
||||
if (!subspaceModels || subspaceModels.length === 0) return;
|
||||
if (!spaces || spaces.length === 0) return;
|
||||
|
||||
for (const subspaceModel of subspaceModels) {
|
||||
if (subspaceModel.action === ModifyAction.ADD) {
|
||||
await this.addSubspaceModel(subspaceModel, spaces);
|
||||
} else if (subspaceModel.action === ModifyAction.DELETE) {
|
||||
await this.deleteSubspaceModel(subspaceModel, spaces);
|
||||
} else if (subspaceModel.action === ModifyAction.UPDATE) {
|
||||
await this.updateSubspaceModel(subspaceModel);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error processing subspaceModel updates`, 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 },
|
||||
);
|
||||
}
|
||||
async updateSubspaceModels(
|
||||
subspaceModels: UpdatedSubspaceModelPayload[],
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<void> {
|
||||
const subspaceUpdatePromises = subspaceModels.map(async (model) => {
|
||||
const {
|
||||
updated: tagsToUpdate,
|
||||
deleted: tagsToDelete,
|
||||
added: tagsToAdd,
|
||||
} = model.modifiedTags;
|
||||
|
||||
// Perform tag operations concurrently
|
||||
await Promise.all([
|
||||
tagsToUpdate?.length && this.updateTags(tagsToUpdate, queryRunner),
|
||||
tagsToDelete?.length && this.deleteTags(tagsToDelete, queryRunner),
|
||||
tagsToAdd?.length &&
|
||||
this.createTags(
|
||||
tagsToAdd,
|
||||
queryRunner,
|
||||
model.subspaceModelUuid,
|
||||
null,
|
||||
),
|
||||
]);
|
||||
|
||||
// Update subspace names
|
||||
const subspaces = await queryRunner.manager.find(
|
||||
this.subspaceRepository.target,
|
||||
{
|
||||
where: {
|
||||
subSpaceModel: {
|
||||
uuid: model.subspaceModelUuid,
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (subspaces.length > 0) {
|
||||
const updateSubspacePromises = subspaces.map((subspace) =>
|
||||
queryRunner.manager.update(
|
||||
this.subspaceRepository.target,
|
||||
{ uuid: subspace.uuid },
|
||||
{ subspaceName: model.subspaceName },
|
||||
),
|
||||
);
|
||||
await Promise.all(updateSubspacePromises);
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for all subspace model updates to complete
|
||||
await Promise.all(subspaceUpdatePromises);
|
||||
}
|
||||
async updateTags(models: TagModel[], queryRunner: QueryRunner) {
|
||||
if (!models?.length) return;
|
||||
|
||||
const updatePromises = models.map((model) =>
|
||||
this.tagService.updateTagsFromModel(model, queryRunner),
|
||||
);
|
||||
await Promise.all(updatePromises);
|
||||
}
|
||||
|
||||
async deleteTags(uuids: string[], queryRunner: QueryRunner) {
|
||||
const deletePromises = uuids.map((uuid) =>
|
||||
this.tagService.deleteTagFromModel(uuid, queryRunner),
|
||||
);
|
||||
await Promise.all(deletePromises);
|
||||
}
|
||||
|
||||
async createTags(
|
||||
models: TagModel[],
|
||||
queryRunner: QueryRunner,
|
||||
subspaceModelUuid?: string,
|
||||
spaceModel?: SpaceModelEntity,
|
||||
): Promise<void> {
|
||||
if (!models.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (subspaceModelUuid) {
|
||||
await this.processSubspaces(subspaceModelUuid, models, queryRunner);
|
||||
}
|
||||
|
||||
if (spaceModel) {
|
||||
await this.processSpaces(spaceModel.uuid, models, queryRunner);
|
||||
}
|
||||
}
|
||||
|
||||
private async processSubspaces(
|
||||
subspaceModelUuid: string,
|
||||
models: TagModel[],
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<void> {
|
||||
const subspaces = await this.subspaceRepository.find({
|
||||
where: {
|
||||
subSpaceModel: {
|
||||
uuid: subspaceModelUuid,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (subspaces.length > 0) {
|
||||
const subspacePromises = subspaces.map((subspace) =>
|
||||
this.tagService.createTagsFromModel(
|
||||
queryRunner,
|
||||
models,
|
||||
null,
|
||||
subspace,
|
||||
),
|
||||
);
|
||||
await Promise.all(subspacePromises);
|
||||
}
|
||||
}
|
||||
|
||||
private async processSpaces(
|
||||
spaceModelUuid: string,
|
||||
models: TagModel[],
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<void> {
|
||||
const spaces = await this.spaceRepository.find({
|
||||
where: {
|
||||
spaceModel: {
|
||||
uuid: spaceModelUuid,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (spaces.length > 0) {
|
||||
const spacePromises = spaces.map((space) =>
|
||||
this.tagService.createTagsFromModel(queryRunner, models, space, null),
|
||||
);
|
||||
await Promise.all(spacePromises);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
286
src/space-model/handlers/propogate-subspace-handler.ts
Normal file
286
src/space-model/handlers/propogate-subspace-handler.ts
Normal file
@ -0,0 +1,286 @@
|
||||
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 },
|
||||
);
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
import { ModifyTagModelDto } from '../dtos';
|
||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
||||
import { NewTagEntity } from '@app/common/modules/tag';
|
||||
import { IUpdatedAllocations } from './subspace-product-allocation-update-result.interface';
|
||||
|
||||
export interface IRelocatedAllocation {
|
||||
allocation: SpaceModelProductAllocationEntity;
|
||||
@ -16,3 +17,8 @@ export interface ISingleSubspaceModel {
|
||||
tags?: ModifyTagModelDto[];
|
||||
relocatedAllocations?: IRelocatedAllocation[];
|
||||
}
|
||||
|
||||
export interface ISubspaceModelUpdates {
|
||||
subspaceModels: ISingleSubspaceModel[];
|
||||
updatedAllocations: IUpdatedAllocations[];
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
@ -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`);
|
||||
}
|
||||
|
@ -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 } from '../interfaces';
|
||||
import {
|
||||
ISingleSubspaceModel,
|
||||
ISubspaceModelUpdates,
|
||||
IUpdatedSpaceAllocations,
|
||||
} from '../interfaces';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceModelService {
|
||||
@ -199,7 +204,8 @@ export class SpaceModelService {
|
||||
param.projectUuid,
|
||||
);
|
||||
await queryRunner.connect();
|
||||
let modifiedSubspaces: ISingleSubspaceModel[] = [];
|
||||
let modifiedSubspaces: ISubspaceModelUpdates;
|
||||
let modifiedProductAllocations: IUpdatedSpaceAllocations[];
|
||||
try {
|
||||
await queryRunner.startTransaction();
|
||||
const spaces = await this.fetchModelSpaces(spaceModel);
|
||||
@ -230,6 +236,7 @@ export class SpaceModelService {
|
||||
}
|
||||
|
||||
if (dto.tags) {
|
||||
modifiedProductAllocations =
|
||||
await this.spaceModelProductAllocationService.updateProductAllocations(
|
||||
dto.tags,
|
||||
project,
|
||||
@ -243,11 +250,21 @@ export class SpaceModelService {
|
||||
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',
|
||||
});
|
||||
|
@ -16,6 +16,7 @@ import { SubspaceModelProductAllocationService } from './subspace-model-product-
|
||||
import {
|
||||
IRelocatedAllocation,
|
||||
ISingleSubspaceModel,
|
||||
ISubspaceModelUpdates,
|
||||
} from 'src/space-model/interfaces';
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||
import { SubSpaceService } from 'src/space/services/subspace';
|
||||
@ -118,7 +119,7 @@ export class SubSpaceModelService {
|
||||
projectUuid: string,
|
||||
spaceTagUpdateDtos?: ModifyTagModelDto[],
|
||||
spaces?: SpaceEntity[],
|
||||
): Promise<ISingleSubspaceModel[]> {
|
||||
): Promise<ISubspaceModelUpdates> {
|
||||
try {
|
||||
if (!dtos || dtos.length === 0) {
|
||||
return;
|
||||
@ -160,13 +161,16 @@ export class SubSpaceModelService {
|
||||
spaceModel,
|
||||
spaceTagUpdateDtos,
|
||||
);
|
||||
return [
|
||||
return {
|
||||
subspaceModels: [
|
||||
createdSubspaces ?? [],
|
||||
updatedSubspaces ?? [],
|
||||
deletedSubspaces ?? [],
|
||||
]
|
||||
.filter((arr) => arr.length > 0)
|
||||
.flat();
|
||||
.flat(),
|
||||
updatedAllocations: updatedAllocations,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in modifySubspaceModels:', error);
|
||||
throw new HttpException(
|
||||
|
@ -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({
|
||||
|
@ -500,6 +500,13 @@ export class SpaceService {
|
||||
await this.subSpaceService.unlinkModels(space.subspaces, queryRunner);
|
||||
}
|
||||
|
||||
if (hasTags && space.productAllocations && space.spaceModel) {
|
||||
await this.spaceProductAllocationService.unlinkModels(
|
||||
space,
|
||||
queryRunner,
|
||||
);
|
||||
}
|
||||
|
||||
if (hasSubspace) {
|
||||
await this.subSpaceService.modifySubSpace(
|
||||
updateSpaceDto.subspace,
|
||||
|
Reference in New Issue
Block a user