Files
backend/src/space/services/subspace/subspace-product-allocation.service.ts
ZaydSkaff 689a38ee0c Revamp/space management (#409)
* task: add getCommunitiesV2

* task: update getOneSpace API to match revamp structure

* refactor: implement modifications to pace management APIs

* refactor: remove space link
2025-06-18 10:34:29 +03:00

250 lines
7.7 KiB
TypeScript

import { SpaceProductAllocationRepository } from '@app/common/modules/space';
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
import { SubspaceProductAllocationRepository } from '@app/common/modules/space/repositories/subspace.repository';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { UpdateSubspaceDto } from 'src/space/dtos';
import { TagService as NewTagService } from 'src/tags/services';
import { In, Not, QueryRunner } from 'typeorm';
@Injectable()
export class SubspaceProductAllocationService {
constructor(
private readonly tagService: NewTagService,
private readonly spaceProductAllocationRepository: SpaceProductAllocationRepository,
private readonly subspaceProductAllocationRepository: SubspaceProductAllocationRepository,
) {}
async createProductAllocations(
subspace: SubspaceEntity,
allocationsData: { product: string; tag: string }[],
queryRunner?: QueryRunner,
// spaceAllocationsToExclude?: SpaceProductAllocationEntity[],
): Promise<void> {
try {
if (!allocationsData.length) return;
const allocations: SubspaceProductAllocationEntity[] = [];
for (const allocationData of allocationsData) {
// await this.validateTagWithinSubspace(
// queryRunner,
// allocationData.tag,
// subspace,
// spaceAllocationsToExclude,
// );
if (
await this.isAllocationExist(allocationData, subspace, queryRunner)
) {
continue;
}
const allocation = this.createNewSubspaceAllocation(
subspace,
allocationData,
queryRunner,
);
allocations.push(allocation);
}
if (allocations.length > 0) {
await this.saveAllocations(allocations, queryRunner);
}
} catch (error) {
throw this.handleError(
error,
'Failed to create subspace product allocations',
);
}
}
async updateSubspaceProductAllocationsV2(
subSpaces: UpdateSubspaceDto[],
projectUuid: string,
queryRunner: QueryRunner,
) {
await Promise.all(
subSpaces.map(async (subspace) => {
await queryRunner.manager.delete(SubspaceProductAllocationEntity, {
subspace: subspace.uuid ? { uuid: subspace.uuid } : undefined,
tag: subspace.productAllocations
? {
uuid: Not(
In(
subspace.productAllocations
.filter((allocation) => allocation.tagUuid)
.map((allocation) => allocation.tagUuid),
),
),
}
: undefined,
product: subspace.productAllocations
? {
uuid: Not(
In(
subspace.productAllocations
.filter((allocation) => allocation.productUuid)
.map((allocation) => allocation.productUuid),
),
),
}
: undefined,
});
const subspaceEntity = await queryRunner.manager.findOne(
SubspaceEntity,
{
where: { uuid: subspace.uuid },
},
);
const processedTags = await this.tagService.upsertTags(
subspace.productAllocations,
projectUuid,
queryRunner,
);
const createdTagsByUUID = new Map(
processedTags.map((t) => [t.uuid, t]),
);
const createdTagsByName = new Map(
processedTags.map((t) => [t.name, t]),
);
// Create the product-tag mapping based on the processed tags
const productTagMapping = subspace.productAllocations.map(
({ tagUuid, tagName, productUuid }) => {
const inputTag = tagUuid
? createdTagsByUUID.get(tagUuid)
: createdTagsByName.get(tagName);
return {
tag: inputTag?.uuid,
product: productUuid,
};
},
);
await this.createProductAllocations(
subspaceEntity,
productTagMapping,
queryRunner,
);
}),
);
}
async unlinkModels(
allocations: SubspaceProductAllocationEntity[],
queryRunner: QueryRunner,
) {
try {
if (allocations.length === 0) return;
const allocationUuids = allocations.map((allocation) => allocation.uuid);
await queryRunner.manager.update(
SubspaceProductAllocationEntity,
{ uuid: In(allocationUuids) },
{ inheritedFromModel: null },
);
} catch (error) {
throw new HttpException(
'Failed to unlink models',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
private createNewSubspaceAllocation(
subspace: SubspaceEntity,
allocationData: { product: string; tag: string },
queryRunner?: QueryRunner,
): SubspaceProductAllocationEntity {
return queryRunner
? queryRunner.manager.create(SubspaceProductAllocationEntity, {
subspace,
product: { uuid: allocationData.product },
tag: { uuid: allocationData.tag },
})
: this.subspaceProductAllocationRepository.create({
subspace,
product: { uuid: allocationData.product },
tag: { uuid: allocationData.tag },
});
}
private async isAllocationExist(
allocationData: { product: string; tag: string },
subspace: SubspaceEntity,
queryRunner?: QueryRunner,
): Promise<boolean> {
const allocation = queryRunner
? await queryRunner.manager.findOne(SubspaceProductAllocationEntity, {
where: {
subspace: { uuid: subspace.uuid },
product: { uuid: allocationData.product },
tag: { uuid: allocationData.tag },
},
})
: await this.subspaceProductAllocationRepository.findOne({
where: {
subspace: { uuid: subspace.uuid },
product: { uuid: allocationData.product },
tag: { uuid: allocationData.tag },
},
});
return !!allocation;
}
private async saveAllocation(
allocation: SubspaceProductAllocationEntity,
queryRunner?: QueryRunner,
): Promise<void> {
if (queryRunner) {
await queryRunner.manager.save(
SubspaceProductAllocationEntity,
allocation,
);
} else {
await this.subspaceProductAllocationRepository.save(allocation);
}
}
private async saveAllocations(
allocations: SubspaceProductAllocationEntity[],
queryRunner?: QueryRunner,
): Promise<void> {
if (queryRunner) {
await queryRunner.manager.save(
SubspaceProductAllocationEntity,
allocations,
);
} else {
await this.subspaceProductAllocationRepository.save(allocations);
}
}
private handleError(error: any, message: string): HttpException {
return new HttpException(
error instanceof HttpException ? error.message : message,
error instanceof HttpException
? error.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR,
);
}
async clearAllAllocations(subspaceUuids: string[], queryRunner: QueryRunner) {
try {
await queryRunner.manager.delete(SubspaceProductAllocationEntity, {
subspace: { uuid: In(subspaceUuids) },
});
} catch (error) {
throw new HttpException(
error instanceof HttpException
? error.message
: 'An unexpected error occurred while clearing allocations',
error instanceof HttpException
? error.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
}