diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts index 37b9ab1..7359e25 100644 --- a/src/space-model/services/space-model.service.ts +++ b/src/space-model/services/space-model.service.ts @@ -6,10 +6,12 @@ import { ProjectParam } from 'src/community/dtos'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { SubSpaceModelService } from './subspace-model.service'; import { SpaceProductModelService } from './space-product-model.service'; +import { DataSource } from 'typeorm'; @Injectable() export class SpaceModelService { constructor( + private readonly dataSource: DataSource, private readonly spaceModelRepository: SpaceModelRepository, private readonly projectRepository: ProjectRepository, private readonly subSpaceModelService: SubSpaceModelService, @@ -24,6 +26,11 @@ export class SpaceModelService { createSpaceModelDto; const project = await this.validateProject(params.projectUuid); + const queryRunner = this.dataSource.createQueryRunner(); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { const isModelExist = await this.validateName( modelName, @@ -40,17 +47,24 @@ export class SpaceModelService { modelName, project, }); - const savedSpaceModel = await this.spaceModelRepository.save(spaceModel); + const savedSpaceModel = await queryRunner.manager.save(spaceModel); - await this.subSpaceModelService.createSubSpaceModels( - subspaceModels, - savedSpaceModel, - ); + if (subspaceModels) { + await this.subSpaceModelService.createSubSpaceModels( + subspaceModels, + savedSpaceModel, + queryRunner, + ); + } - await this.spaceProductModelService.createSpaceProductModels( - spaceProductModels, - savedSpaceModel, - ); + if (spaceProductModels) { + await this.spaceProductModelService.createSpaceProductModels( + spaceProductModels, + savedSpaceModel, + queryRunner, + ); + } + await queryRunner.commitTransaction(); return new SuccessResponseDto({ message: `Successfully created new space model with uuid ${savedSpaceModel.uuid}`, @@ -58,6 +72,8 @@ export class SpaceModelService { statusCode: HttpStatus.CREATED, }); } catch (error) { + await queryRunner.rollbackTransaction(); + if (error instanceof HttpException) { throw error; } @@ -66,6 +82,8 @@ export class SpaceModelService { error.message || `An unexpected error occurred`, HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + await queryRunner.release(); } } diff --git a/src/space-model/services/space-product-item-model.service.ts b/src/space-model/services/space-product-item-model.service.ts index 0a5b43d..b2f856c 100644 --- a/src/space-model/services/space-product-item-model.service.ts +++ b/src/space-model/services/space-product-item-model.service.ts @@ -5,6 +5,7 @@ import { } from '@app/common/modules/space-model'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { CreateSpaceProductItemModelDto } from '../dtos'; +import { QueryRunner } from 'typeorm'; @Injectable() export class SpaceProductItemModelService { @@ -16,41 +17,37 @@ export class SpaceProductItemModelService { itemModelDtos: CreateSpaceProductItemModelDto[], spaceProductModel: SpaceProductModelEntity, spaceModel: SpaceModelEntity, + queryRunner: QueryRunner, ) { - try { - await this.validateTags(itemModelDtos, spaceModel); + await this.validateTags(itemModelDtos, spaceModel, queryRunner); - for (const itemModelDto of itemModelDtos) { - await this.create(itemModelDto, spaceProductModel, spaceModel); - } + try { + const productItems = itemModelDtos.map((dto) => + queryRunner.manager.create(this.spaceProductItemRepository.target, { + tag: dto.tag, + spaceProductModel, + spaceModel, + }), + ); + + await queryRunner.manager.save(productItems); } catch (error) { if (error instanceof HttpException) { throw error; } throw new HttpException( - error.message || `An unexpected error occurred`, + error.message || + 'An unexpected error occurred while creating product items.', HttpStatus.INTERNAL_SERVER_ERROR, ); } } - async create( - itemModelDto: CreateSpaceProductItemModelDto, - spaceProductModel: SpaceProductModelEntity, - spaceModel: SpaceModelEntity, - ) { - const productItem = this.spaceProductItemRepository.create({ - tag: itemModelDto.tag, - spaceProductModel, - spaceModel, - }); - await this.spaceProductItemRepository.save(productItem); - } - - async validateTags( + private async validateTags( itemModelDtos: CreateSpaceProductItemModelDto[], spaceModel: SpaceModelEntity, + queryRunner: QueryRunner, ) { const incomingTags = itemModelDtos.map((item) => item.tag); @@ -59,15 +56,18 @@ export class SpaceProductItemModelService { ); if (duplicateTags.length > 0) { throw new HttpException( - `Duplicate tags found in request: ${duplicateTags.join(', ')}`, - HttpStatus.CONFLICT, + `Duplicate tags found in the request: ${[...new Set(duplicateTags)].join(', ')}`, + HttpStatus.BAD_REQUEST, ); } - const existingTags = await this.spaceProductItemRepository.find({ - where: { spaceModel }, - select: ['tag'], - }); + const existingTags = await queryRunner.manager.find( + this.spaceProductItemRepository.target, + { + where: { spaceModel }, + select: ['tag'], + }, + ); const existingTagSet = new Set(existingTags.map((item) => item.tag)); const conflictingTags = incomingTags.filter((tag) => diff --git a/src/space-model/services/space-product-model.service.ts b/src/space-model/services/space-product-model.service.ts index cf60203..aa08a16 100644 --- a/src/space-model/services/space-product-model.service.ts +++ b/src/space-model/services/space-product-model.service.ts @@ -6,6 +6,7 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { CreateSpaceProductModelDto } from '../dtos'; import { ProductRepository } from '@app/common/modules/product/repositories'; import { SpaceProductItemModelService } from './space-product-item-model.service'; +import { QueryRunner } from 'typeorm'; @Injectable() export class SpaceProductModelService { @@ -18,60 +19,66 @@ export class SpaceProductModelService { async createSpaceProductModels( spaceProductModelDtos: CreateSpaceProductModelDto[], spaceModel: SpaceModelEntity, + queryRunner: QueryRunner, ) { try { - for (const spaceProductModelDto of spaceProductModelDtos) { - await this.create(spaceProductModelDto, spaceModel); - } + const productModels = await Promise.all( + spaceProductModelDtos.map(async (dto) => { + this.validateProductCount(dto); + const product = await this.getProduct(dto.productId); + return queryRunner.manager.create( + this.spaceProductModelRepository.target, + { + product, + productCount: dto.productCount, + spaceModel, + }, + ); + }), + ); + + const savedProductModels = await queryRunner.manager.save(productModels); + + await Promise.all( + spaceProductModelDtos.map((dto, index) => + this.spaceProductItemModelService.createProdutItemModel( + dto.items, + savedProductModels[index], + spaceModel, + queryRunner, + ), + ), + ); } catch (error) { if (error instanceof HttpException) { throw error; } - throw new HttpException( - error.message || `An unexpected error occurred`, + error.message || + 'An unexpected error occurred while creating product models.', HttpStatus.INTERNAL_SERVER_ERROR, ); } } - async create( - spaceProductModelDto: CreateSpaceProductModelDto, - spaceModel: SpaceModelEntity, - ) { - this.validateCount(spaceProductModelDto); - - const product = await this.productRepository.findOneBy({ - uuid: spaceProductModelDto.productId, - }); - if (!product) { + private validateProductCount(dto: CreateSpaceProductModelDto) { + const productItemCount = dto.items.length; + if (dto.productCount !== productItemCount) { throw new HttpException( - `Product with ID ${spaceProductModelDto.productId} not found`, - HttpStatus.NOT_FOUND, - ); - } - const spaceProductModel = this.spaceProductModelRepository.create({ - product, - productCount: spaceProductModelDto.productCount, - spaceModel: spaceModel, - }); - const newProductModel = - await this.spaceProductModelRepository.save(spaceProductModel); - - await this.spaceProductItemModelService.createProdutItemModel( - spaceProductModelDto.items, - newProductModel, - spaceModel, - ); - } - - private validateCount(spaceProductModelDto: CreateSpaceProductModelDto) { - const productItemCount = spaceProductModelDto.items.length; - if (spaceProductModelDto.productCount !== productItemCount) { - throw new HttpException( - `Product count (${spaceProductModelDto.productCount}) does not match the number of items (${productItemCount}) for product ID ${spaceProductModelDto.productId}.`, + `Product count (${dto.productCount}) does not match the number of items (${productItemCount}) for product ID ${dto.productId}.`, HttpStatus.BAD_REQUEST, ); } } + + private async getProduct(productId: string) { + const product = await this.productRepository.findOneBy({ uuid: productId }); + if (!product) { + throw new HttpException( + `Product with ID ${productId} not found.`, + HttpStatus.NOT_FOUND, + ); + } + return product; + } } diff --git a/src/space-model/services/subspace-model.service.ts b/src/space-model/services/subspace-model.service.ts index 5d4d347..a6a75aa 100644 --- a/src/space-model/services/subspace-model.service.ts +++ b/src/space-model/services/subspace-model.service.ts @@ -4,6 +4,7 @@ import { } from '@app/common/modules/space-model'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { CreateSubspaceModelDto } from '../dtos'; +import { QueryRunner } from 'typeorm'; @Injectable() export class SubSpaceModelService { @@ -14,16 +15,19 @@ export class SubSpaceModelService { async createSubSpaceModels( subSpaceModelDtos: CreateSubspaceModelDto[], spaceModel: SpaceModelEntity, + queryRunner: QueryRunner, ) { + this.validateInputDtos(subSpaceModelDtos); + try { - this.validateInputDtos(subSpaceModelDtos); - for (const subspaceDto of subSpaceModelDtos) { - const subspace = this.subspaceModelRepository.create({ + const subspaces = subSpaceModelDtos.map((subspaceDto) => + queryRunner.manager.create(this.subspaceModelRepository.target, { subspaceName: subspaceDto.subspaceName, spaceModel: spaceModel, - }); - await this.subspaceModelRepository.save(subspace); - } + }), + ); + + await queryRunner.manager.save(subspaces); } catch (error) { if (error instanceof HttpException) { throw error;