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 { 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 { 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 { if (queryRunner) { await queryRunner.manager.save( SubspaceProductAllocationEntity, allocation, ); } else { await this.subspaceProductAllocationRepository.save(allocation); } } private async saveAllocations( allocations: SubspaceProductAllocationEntity[], queryRunner?: QueryRunner, ): Promise { 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, ); } } }