From b2a422f71b7e27ad357713498ab0b5d2a1e79716 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Wed, 11 Dec 2024 10:51:17 +0400 Subject: [PATCH] created space model create service --- .../dtos/create-space-model.dto.ts | 33 +++++++ .../create-space-product-item-model.dto.ts | 12 +++ .../dtos/create-space-product-model.dto.ts | 30 ++++++ .../dtos/create-subspace-model.dto.ts | 12 +++ src/space-model/dtos/index.ts | 5 + src/space-model/dtos/project-param.dto.ts | 11 +++ src/space-model/services/index.ts | 4 + .../services/space-model.service.ts | 94 +++++++++++++++++++ .../space-product-item-model.service.ts | 79 ++++++++++++++++ .../services/space-product-model.service.ts | 61 ++++++++++++ .../services/subspace-model.service.ts | 33 +++++++ 11 files changed, 374 insertions(+) create mode 100644 src/space-model/dtos/create-space-model.dto.ts create mode 100644 src/space-model/dtos/create-space-product-item-model.dto.ts create mode 100644 src/space-model/dtos/create-space-product-model.dto.ts create mode 100644 src/space-model/dtos/create-subspace-model.dto.ts create mode 100644 src/space-model/dtos/index.ts create mode 100644 src/space-model/dtos/project-param.dto.ts create mode 100644 src/space-model/services/index.ts create mode 100644 src/space-model/services/space-model.service.ts create mode 100644 src/space-model/services/space-product-item-model.service.ts create mode 100644 src/space-model/services/space-product-model.service.ts create mode 100644 src/space-model/services/subspace-model.service.ts diff --git a/src/space-model/dtos/create-space-model.dto.ts b/src/space-model/dtos/create-space-model.dto.ts new file mode 100644 index 0000000..9506728 --- /dev/null +++ b/src/space-model/dtos/create-space-model.dto.ts @@ -0,0 +1,33 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString, IsArray, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; +import { CreateSubspaceModelDto } from './create-subspace-model.dto'; +import { CreateSpaceProductModelDto } from './create-space-product-model.dto'; + +export class CreateSpaceModelDto { + @ApiProperty({ + description: 'Name of the space model', + example: 'Apartment Model', + }) + @IsNotEmpty() + @IsString() + modelName: string; + + @ApiProperty({ + description: 'List of subspaces included in the model', + type: [CreateSubspaceModelDto], + }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => CreateSubspaceModelDto) + subspaceModels?: CreateSubspaceModelDto[]; + + @ApiProperty({ + description: 'List of products included in the model', + type: [CreateSpaceProductModelDto], + }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => CreateSpaceProductModelDto) + spaceProductModels?: CreateSpaceProductModelDto[]; +} diff --git a/src/space-model/dtos/create-space-product-item-model.dto.ts b/src/space-model/dtos/create-space-product-item-model.dto.ts new file mode 100644 index 0000000..3825219 --- /dev/null +++ b/src/space-model/dtos/create-space-product-item-model.dto.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; + +export class CreateSpaceProductItemModelDto { + @ApiProperty({ + description: 'Specific name for the product item', + example: 'Light 1', + }) + @IsNotEmpty() + @IsString() + tag: string; +} diff --git a/src/space-model/dtos/create-space-product-model.dto.ts b/src/space-model/dtos/create-space-product-model.dto.ts new file mode 100644 index 0000000..63fb9dd --- /dev/null +++ b/src/space-model/dtos/create-space-product-model.dto.ts @@ -0,0 +1,30 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString, IsArray, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; +import { CreateSpaceProductItemModelDto } from './create-space-product-item-model.dto'; + +export class CreateSpaceProductModelDto { + @ApiProperty({ + description: 'ID of the product associated with the model', + example: 'product-uuid', + }) + @IsNotEmpty() + @IsString() + productId: string; + + @ApiProperty({ + description: 'Number of products in the model', + example: 3, + }) + @IsNotEmpty() + productCount: number; + + @ApiProperty({ + description: 'Specific names for each product item', + type: [CreateSpaceProductItemModelDto], + }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => CreateSpaceProductItemModelDto) + items: CreateSpaceProductItemModelDto[]; +} diff --git a/src/space-model/dtos/create-subspace-model.dto.ts b/src/space-model/dtos/create-subspace-model.dto.ts new file mode 100644 index 0000000..a27ad3b --- /dev/null +++ b/src/space-model/dtos/create-subspace-model.dto.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; + +export class CreateSubspaceModelDto { + @ApiProperty({ + description: 'Name of the subspace', + example: 'Living Room', + }) + @IsNotEmpty() + @IsString() + subspaceName: string; +} diff --git a/src/space-model/dtos/index.ts b/src/space-model/dtos/index.ts new file mode 100644 index 0000000..b4b1e07 --- /dev/null +++ b/src/space-model/dtos/index.ts @@ -0,0 +1,5 @@ +export * from './create-space-model.dto'; +export * from './create-space-product-item-model.dto'; +export * from './create-space-product-model.dto'; +export * from './create-subspace-model.dto'; +export * from './project-param.dto'; diff --git a/src/space-model/dtos/project-param.dto.ts b/src/space-model/dtos/project-param.dto.ts new file mode 100644 index 0000000..e7d9e97 --- /dev/null +++ b/src/space-model/dtos/project-param.dto.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsUUID } from 'class-validator'; + +export class projectParam { + @ApiProperty({ + description: 'UUID of the Project', + example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', + }) + @IsUUID() + projectUuid: string; +} diff --git a/src/space-model/services/index.ts b/src/space-model/services/index.ts new file mode 100644 index 0000000..88e2d41 --- /dev/null +++ b/src/space-model/services/index.ts @@ -0,0 +1,4 @@ +export * from './space-model.service'; +export * from './space-product-item-model.service'; +export * from './space-product-model.service'; +export * from './subspace-model.service'; diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts new file mode 100644 index 0000000..f7b8f28 --- /dev/null +++ b/src/space-model/services/space-model.service.ts @@ -0,0 +1,94 @@ +import { SpaceModelRepository } from '@app/common/modules/space-model'; +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { CreateSpaceModelDto } from '../dtos'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; +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'; + +@Injectable() +export class SpaceModelService { + constructor( + private readonly spaceModelRepository: SpaceModelRepository, + private readonly projectRepository: ProjectRepository, + private readonly subSpaceModelService: SubSpaceModelService, + private readonly spaceProductModelService: SpaceProductModelService, + ) {} + + async createSpaceModel( + createSpaceModelDto: CreateSpaceModelDto, + params: ProjectParam, + ) { + const { modelName, subspaceModels, spaceProductModels } = + createSpaceModelDto; + const project = await this.validateProject(params.projectUuid); + + try { + const isModelExist = await this.validateName( + modelName, + params.projectUuid, + ); + if (isModelExist) { + throw new HttpException( + `Model name "${modelName}" already exists in this project ${project.name}.`, + HttpStatus.CONFLICT, + ); + } + + const spaceModel = await this.spaceModelRepository.create({ + modelName, + project, + }); + const savedSpaceModel = await this.spaceModelRepository.save(spaceModel); + + await this.subSpaceModelService.createSubSpaceModels( + subspaceModels, + savedSpaceModel, + ); + + await this.spaceProductModelService.createSpaceProductModels( + spaceProductModels, + savedSpaceModel, + ); + + return new SuccessResponseDto({ + message: `Successfully created new space model with uuid ${savedSpaceModel.uuid}`, + data: savedSpaceModel, + statusCode: HttpStatus.CREATED, + }); + } catch (error) { + if (error instanceof HttpException) { + throw error; + } + + throw new HttpException( + error.message || `An unexpected error occurred`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + + async validateProject(projectUuid: string) { + const project = await this.projectRepository.findOne({ + where: { + uuid: projectUuid, + }, + }); + + if (!project) { + throw new HttpException( + `Project with uuid ${projectUuid} not found`, + HttpStatus.NOT_FOUND, + ); + } + return project; + } + + async validateName(modelName: string, projectUuid: string): Promise { + const isModelExist = await this.spaceModelRepository.exists({ + where: { modelName, project: { uuid: projectUuid } }, + }); + return isModelExist; + } +} diff --git a/src/space-model/services/space-product-item-model.service.ts b/src/space-model/services/space-product-item-model.service.ts new file mode 100644 index 0000000..ebf7d2d --- /dev/null +++ b/src/space-model/services/space-product-item-model.service.ts @@ -0,0 +1,79 @@ +import { + SpaceModelEntity, + SpaceProductItemModelRepository, + SpaceProductModelEntity, +} from '@app/common/modules/space-model'; +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { CreateSpaceProductItemModelDto } from '../dtos'; + +@Injectable() +export class SpaceProductItemModelService { + constructor( + private readonly spaceProductItemRepository: SpaceProductItemModelRepository, + ) {} + + async createProdutItemModel( + itemModelDtos: CreateSpaceProductItemModelDto[], + spaceProductModel: SpaceProductModelEntity, + spaceModel: SpaceModelEntity, + ) { + try { + await this.validateTags(itemModelDtos, spaceModel); + + for (const itemModelDto of itemModelDtos) { + await this.create(itemModelDto, spaceProductModel, spaceModel); + } + } catch (error) { + throw new HttpException( + error.message || `An unexpected error occurred`, + 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( + itemModelDtos: CreateSpaceProductItemModelDto[], + spaceModel: SpaceModelEntity, + ) { + const incomingTags = itemModelDtos.map((item) => item.tag); + + const duplicateTags = incomingTags.filter( + (tag, index) => incomingTags.indexOf(tag) !== index, + ); + if (duplicateTags.length > 0) { + throw new HttpException( + `Duplicate tags found in request: ${duplicateTags.join(', ')}`, + HttpStatus.CONFLICT, + ); + } + + const existingTags = await this.spaceProductItemRepository.find({ + where: { spaceModel }, + select: ['tag'], + }); + const existingTagSet = new Set(existingTags.map((item) => item.tag)); + + const conflictingTags = incomingTags.filter((tag) => + existingTagSet.has(tag), + ); + if (conflictingTags.length > 0) { + throw new HttpException( + `Tags already exist in the model: ${conflictingTags.join(', ')}`, + HttpStatus.CONFLICT, + ); + } + } +} diff --git a/src/space-model/services/space-product-model.service.ts b/src/space-model/services/space-product-model.service.ts new file mode 100644 index 0000000..10ee9f5 --- /dev/null +++ b/src/space-model/services/space-product-model.service.ts @@ -0,0 +1,61 @@ +import { + SpaceModelEntity, + SpaceProductModelRepository, +} from '@app/common/modules/space-model'; +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'; + +@Injectable() +export class SpaceProductModelService { + constructor( + private readonly spaceProductModelRepository: SpaceProductModelRepository, + private readonly productRepository: ProductRepository, + private readonly spaceProductItemModelService: SpaceProductItemModelService, + ) {} + + async createSpaceProductModels( + spaceProductModelDtos: CreateSpaceProductModelDto[], + spaceModel: SpaceModelEntity, + ) { + try { + for (const spaceProductModelDto of spaceProductModelDtos) { + await this.create(spaceProductModelDto, spaceModel); + } + } catch (error) { + throw new HttpException( + error.message || `An unexpected error occurred`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + + async create( + spaceProductModelDto: CreateSpaceProductModelDto, + spaceModel: SpaceModelEntity, + ) { + const product = await this.productRepository.findOneBy({ + uuid: spaceProductModelDto.productId, + }); + if (!product) { + 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, + ); + } +} diff --git a/src/space-model/services/subspace-model.service.ts b/src/space-model/services/subspace-model.service.ts new file mode 100644 index 0000000..45d33ef --- /dev/null +++ b/src/space-model/services/subspace-model.service.ts @@ -0,0 +1,33 @@ +import { + SpaceModelEntity, + SubspaceModelRepository, +} from '@app/common/modules/space-model'; +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { CreateSubspaceModelDto } from '../dtos'; + +@Injectable() +export class SubSpaceModelService { + constructor( + private readonly subspaceModelRepository: SubspaceModelRepository, + ) {} + + async createSubSpaceModels( + subSpaceModelDtos: CreateSubspaceModelDto[], + spaceModel: SpaceModelEntity, + ) { + try { + for (const subspaceDto of subSpaceModelDtos) { + const subspace = this.subspaceModelRepository.create({ + subspaceName: subspaceDto.subspaceName, + spaceModel: spaceModel, + }); + await this.subspaceModelRepository.save(subspace); + } + } catch (error) { + throw new HttpException( + error.message || `An unexpected error occurred`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } +}