updated create space model

This commit is contained in:
hannathkadher
2024-12-23 12:25:24 +04:00
parent 4b55c4e39c
commit a4740e8bbd
8 changed files with 216 additions and 39 deletions

View File

@ -3,3 +3,4 @@ export * from './project-param.dto';
export * from './update-space-model.dto';
export * from './space-model-param';
export * from './subspaces-model-dtos';
export * from './tag-model-dtos';

View File

@ -0,0 +1,2 @@
export * from './create-tag-model.dto';
export * from './update-tag-model.dto';

View File

@ -0,0 +1,21 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
export class UpdateTagModelDto {
@ApiProperty({
description: 'UUID of the tag to be updated',
example: '123e4567-e89b-12d3-a456-426614174000',
})
@IsNotEmpty()
@IsUUID()
uuid: string;
@ApiProperty({
description: 'Updated name of the tag',
example: 'Updated Tag Name',
required: false,
})
@IsOptional()
@IsString()
tag?: string;
}

View File

@ -1,2 +1,3 @@
export * from './space-model.service';
export * from './subspace';
export * from './tag-model.service';

View File

@ -17,6 +17,8 @@ import { SpaceModelDto } from '@app/common/modules/space-model/dtos';
import { SpaceModelParam } from '../dtos/space-model-param';
import { ProjectService } from 'src/project/services';
import { ProjectEntity } from '@app/common/modules/project/entities';
import { TagModelService } from './tag-model.service';
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
@Injectable()
export class SpaceModelService {
@ -25,21 +27,21 @@ export class SpaceModelService {
private readonly spaceModelRepository: SpaceModelRepository,
private readonly projectService: ProjectService,
private readonly subSpaceModelService: SubSpaceModelService,
private readonly tagModelService: TagModelService,
) {}
async createSpaceModel(
createSpaceModelDto: CreateSpaceModelDto,
params: ProjectParam,
) {
const { modelName, subspaceModels } = createSpaceModelDto;
const project = await this.validateProject(params.projectUuid);
): Promise<BaseResponseDto> {
const { modelName, subspaceModels, tags } = createSpaceModelDto;
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const project = await this.validateProject(params.projectUuid);
const isModelExist = await this.validateName(
modelName,
params.projectUuid,
@ -55,13 +57,25 @@ export class SpaceModelService {
modelName,
project,
});
const savedSpaceModel = await queryRunner.manager.save(spaceModel);
if (subspaceModels) {
await this.subSpaceModelService.createSubSpaceModels(
subspaceModels,
savedSpaceModel,
if (subspaceModels?.length) {
savedSpaceModel.subspaceModels =
await this.subSpaceModelService.createSubSpaceModels(
subspaceModels,
savedSpaceModel,
queryRunner,
tags,
);
}
if (tags?.length) {
savedSpaceModel.tags = await this.tagModelService.createTags(
tags,
queryRunner,
savedSpaceModel,
null,
);
}
@ -75,14 +89,16 @@ export class SpaceModelService {
} catch (error) {
await queryRunner.rollbackTransaction();
if (error instanceof HttpException) {
throw error;
}
const errorMessage =
error instanceof HttpException
? error.message
: 'An unexpected error occurred';
const statusCode =
error instanceof HttpException
? error.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
throw new HttpException(
error.message || `An unexpected error occurred`,
HttpStatus.INTERNAL_SERVER_ERROR,
);
throw new HttpException(errorMessage, statusCode);
} finally {
await queryRunner.release();
}

View File

@ -1,5 +1,6 @@
import {
SpaceModelEntity,
SubspaceModelEntity,
SubspaceModelRepository,
} from '@app/common/modules/space-model';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
@ -7,6 +8,7 @@ import {
CreateSubspaceModelDto,
UpdateSubspaceModelDto,
ModifySubspacesModelDto,
CreateTagModelDto,
} from '../../dtos';
import { QueryRunner } from 'typeorm';
import {
@ -15,47 +17,53 @@ import {
IUpdateSubspaceModelInterface,
} from 'src/space-model/interfaces';
import { DeleteSubspaceModelDto } from 'src/space-model/dtos/subspaces-model-dtos';
import { TagModelService } from '../tag-model.service';
@Injectable()
export class SubSpaceModelService {
constructor(
private readonly subspaceModelRepository: SubspaceModelRepository,
private readonly tagModelService: TagModelService,
) {}
async createSubSpaceModels(
subSpaceModelDtos: CreateSubspaceModelDto[],
spaceModel: SpaceModelEntity,
queryRunner: QueryRunner,
) {
otherTags: CreateTagModelDto[],
): Promise<SubspaceModelEntity[]> {
this.validateInputDtos(subSpaceModelDtos);
try {
const subspaces = subSpaceModelDtos.map((subspaceDto) =>
queryRunner.manager.create(this.subspaceModelRepository.target, {
subspaceName: subspaceDto.subspaceName,
spaceModel: spaceModel,
spaceModel,
}),
);
const newSubspaces = await queryRunner.manager.save(subspaces);
const savedSubspaces = await queryRunner.manager.save(subspaces);
const addedSubspaces = await Promise.all(
await Promise.all(
subSpaceModelDtos.map(async (dto, index) => {
const subspaceModel = newSubspaces[index];
const subspace = savedSubspaces[index];
return {
subspaceModel,
};
if (dto.tags && dto.tags.length > 0) {
const tagModels = await this.tagModelService.createTags(
dto.tags,
queryRunner,
null,
subspace,
otherTags,
);
subspace.tags = tagModels;
}
}),
);
return addedSubspaces;
} catch (error) {
if (error instanceof HttpException) {
throw error;
}
return savedSubspaces;
} catch (error) {
throw new HttpException(
error.message || `An unexpected error occurred`,
error.message || 'Failed to create subspaces.',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
@ -230,13 +238,6 @@ export class SubSpaceModelService {
const actions = [];
if (dto.add) {
actions.push(
this.createSubSpaceModels(dto.add, spaceModel, queryRunner).then(
(addedSubspaces) => {
subspaces.new = addedSubspaces;
},
),
);
}
if (dto.update) {

View File

@ -0,0 +1,128 @@
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { QueryRunner } from 'typeorm';
import {
SpaceModelEntity,
TagModel,
} from '@app/common/modules/space-model/entities';
import { SubspaceModelEntity } from '@app/common/modules/space-model/entities';
import { TagModelRepository } from '@app/common/modules/space-model';
import { CreateTagModelDto, UpdateTagModelDto } from '../dtos';
import { ProductService } from 'src/product/services';
@Injectable()
export class TagModelService {
constructor(
private readonly tagModelRepository: TagModelRepository,
private readonly productService: ProductService,
) {}
async createTags(
tags: CreateTagModelDto[],
queryRunner: QueryRunner,
spaceModel?: SpaceModelEntity,
subspaceModel?: SubspaceModelEntity,
otherTags?: CreateTagModelDto[],
): Promise<TagModel[]> {
let alltags: CreateTagModelDto[] = [];
if (!tags.length) {
throw new HttpException('Tags cannot be empty.', HttpStatus.BAD_REQUEST);
}
if (otherTags) {
alltags = [...tags, ...otherTags];
}
const duplicates = this.checkForDuplicates(alltags);
if (duplicates.length > 0) {
throw new HttpException(
`Duplicate tags found for the same product: ${duplicates.join(', ')}`,
HttpStatus.BAD_REQUEST,
);
}
const tagEntities = await Promise.all(
tags.map(async (tagDto) => {
const product = await this.productService.findOne(tagDto.productUuid);
if (!product) {
throw new HttpException(
`Product with UUID ${tagDto.productUuid} not found.`,
HttpStatus.NOT_FOUND,
);
}
return queryRunner.manager.create(TagModel, {
tag: tagDto.tag,
product: product.data,
spaceModel,
subspaceModel,
});
}),
);
try {
return await queryRunner.manager.save(tagEntities);
} catch (error) {
throw new HttpException(
'Failed to save tag models due to an unexpected error.',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async updateTags(tags: UpdateTagModelDto[], queryRunner: QueryRunner) {
try {
const updatePromises = tags.map(async (tagDto) => {
const existingTag = await this.tagModelRepository.findOne({
where: { uuid: tagDto.uuid },
});
if (!existingTag) {
throw new HttpException(
`Tag with ID ${tagDto.uuid} not found`,
HttpStatus.NOT_FOUND,
);
}
existingTag.tag = tagDto.tag || existingTag.tag;
return queryRunner.manager.save(existingTag);
});
return await Promise.all(updatePromises);
} catch (error) {
throw new HttpException(
error.message || 'Failed to update tags',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async deleteTags(tagUuids: string[], queryRunner: QueryRunner) {
try {
const deletePromises = tagUuids.map((id) =>
queryRunner.manager.softDelete(this.tagModelRepository.target, id),
);
await Promise.all(deletePromises);
return { message: 'Tags deleted successfully', tagUuids };
} catch (error) {
throw new HttpException(
error.message || 'Failed to delete tags',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
private checkForDuplicates(tags: CreateTagModelDto[]): string[] {
const seen = new Map<string, boolean>();
const duplicates: string[] = [];
tags.forEach((tagDto) => {
const key = `${tagDto.productUuid}-${tagDto.tag}`;
if (seen.has(key)) {
duplicates.push(`${tagDto.tag} for Product: ${tagDto.productUuid}`);
} else {
seen.set(key, true);
}
});
return duplicates;
}
}

View File

@ -2,10 +2,15 @@ import { SpaceRepositoryModule } from '@app/common/modules/space/space.repositor
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { SpaceModelController } from './controllers';
import { SpaceModelService, SubSpaceModelService } from './services';
import {
SpaceModelService,
SubSpaceModelService,
TagModelService,
} from './services';
import {
SpaceModelRepository,
SubspaceModelRepository,
TagModelRepository,
} from '@app/common/modules/space-model';
import { ProjectRepository } from '@app/common/modules/project/repositiories';
import { ProductRepository } from '@app/common/modules/product/repositories';
@ -35,6 +40,8 @@ const CommandHandlers = [PropogateSubspaceHandler];
SubspaceRepository,
SubspaceProductRepository,
SubspaceProductItemRepository,
TagModelService,
TagModelRepository,
],
exports: [CqrsModule],
})