propagate add

This commit is contained in:
hannathkadher
2024-12-19 09:12:26 +04:00
parent 23d3cd620c
commit a771fa8ee5
12 changed files with 291 additions and 14 deletions

View File

@ -0,0 +1 @@
export * from './propogate-subspace-update-command';

View File

@ -0,0 +1,6 @@
import { ICommand } from '@nestjs/cqrs';
import { UpdatedSubspaceModelInterface } from '../interfaces';
export class PropogateSubspaceCommand implements ICommand {
constructor(public readonly param: UpdatedSubspaceModelInterface) {}
}

View File

@ -5,3 +5,4 @@ export * from './create-subspace-model.dto';
export * from './project-param.dto'; export * from './project-param.dto';
export * from './update-space-model.dto'; export * from './update-space-model.dto';
export * from './space-model-param'; export * from './space-model-param';
export * from './update-subspace-model.dto';

View File

@ -2,8 +2,9 @@ import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsOptional, IsString, ValidateNested } from 'class-validator'; import { IsArray, IsOptional, IsString, ValidateNested } from 'class-validator';
import { CreateSubspaceModelDto } from './create-subspace-model.dto'; import { CreateSubspaceModelDto } from './create-subspace-model.dto';
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { UpdateSubspaceModelDto } from './update-subspace-model.dto';
export class UpdateSubspaceModelDto { export class UpdateSubspacesModelDto {
@ApiProperty({ @ApiProperty({
description: 'List of subspaces to add', description: 'List of subspaces to add',
type: [CreateSubspaceModelDto], type: [CreateSubspaceModelDto],
@ -14,7 +15,19 @@ export class UpdateSubspaceModelDto {
@ValidateNested({ each: true }) @ValidateNested({ each: true })
@Type(() => CreateSubspaceModelDto) @Type(() => CreateSubspaceModelDto)
add?: CreateSubspaceModelDto[]; add?: CreateSubspaceModelDto[];
@ApiProperty({
description: 'List of subspaces to add',
type: [CreateSubspaceModelDto],
required: false,
})
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => UpdateSubspaceModelDto)
update?: UpdateSubspaceModelDto[];
} }
export class UpdateSpaceModelDto { export class UpdateSpaceModelDto {
@ApiProperty({ @ApiProperty({
description: 'Updated name of the space model', description: 'Updated name of the space model',
@ -25,5 +38,5 @@ export class UpdateSpaceModelDto {
modelName?: string; modelName?: string;
@IsOptional() @IsOptional()
subspaceModels?: UpdateSubspaceModelDto; subspaceModels?: UpdateSubspacesModelDto;
} }

View File

@ -0,0 +1,30 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
IsNotEmpty,
IsString,
IsArray,
IsOptional,
ValidateNested,
} from 'class-validator';
import { CreateSpaceProductModelDto } from './create-space-product-model.dto';
export class UpdateSubspaceModelDto {
@ApiProperty({
description: 'Name of the subspace',
example: 'Living Room',
})
@IsNotEmpty()
@IsString()
subspaceName?: string;
@ApiProperty({
description: 'List of products included in the model',
type: [CreateSpaceProductModelDto],
})
@IsArray()
@IsOptional()
@ValidateNested({ each: true })
@Type(() => CreateSpaceProductModelDto)
spaceProductModels?: CreateSpaceProductModelDto[];
}

View File

@ -0,0 +1 @@
export * from './propate-subspace-handler';

View File

@ -0,0 +1,177 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { PropogateSubspaceCommand } from '../commands';
import { Logger } from '@nestjs/common';
import { SpaceEntity, SpaceRepository } from '@app/common/modules/space';
import {
SubspaceProductItemRepository,
SubspaceProductRepository,
SubspaceRepository,
} from '@app/common/modules/space/repositories/subspace.repository';
@CommandHandler(PropogateSubspaceCommand)
export class PropogateSubspaceHandler
implements ICommandHandler<PropogateSubspaceCommand>
{
private readonly logger = new Logger(PropogateSubspaceHandler.name);
constructor(
private readonly spaceRepository: SpaceRepository,
private readonly subspaceRepository: SubspaceRepository,
private readonly productRepository: SubspaceProductRepository,
private readonly productItemRepository: SubspaceProductItemRepository,
) {}
async execute(command: PropogateSubspaceCommand): Promise<void> {
try {
const newSubspaceModels = command.param?.new;
if (!newSubspaceModels || newSubspaceModels.length === 0) {
this.logger.warn('No new subspace models provided.');
return;
}
const spaceModelUuid =
newSubspaceModels[0]?.subspaceModel?.spaceModel?.uuid;
if (!spaceModelUuid) {
this.logger.error(
'Space model UUID is missing in the command parameters.',
);
return;
}
const spaces = await this.getSpacesByModel(spaceModelUuid);
if (spaces.length === 0) {
this.logger.warn(`No spaces found for model UUID: ${spaceModelUuid}`);
return;
}
await this.processSubspaces(newSubspaceModels, spaces);
} catch (error) {
this.logger.error(
'Error in PropogateSubspaceHandler execution',
error.stack,
);
}
}
private async processSubspaces(
newSubspaceModels: any[],
spaces: SpaceEntity[],
) {
for (const newSubspaceModel of newSubspaceModels) {
for (const space of spaces) {
try {
const subspace = await this.createSubspace(newSubspaceModel, space);
if (newSubspaceModel.productModels?.length > 0) {
await this.processProducts(
newSubspaceModel.productModels,
subspace,
);
}
} catch (error) {
this.logger.error(
`Failed to create subspace for space ID: ${space.uuid}`,
error.stack,
);
}
}
}
}
private async createSubspace(newSubspaceModel: any, space: SpaceEntity) {
const subspace = this.subspaceRepository.create({
subspaceName: newSubspaceModel.subspaceModel.subspaceName,
space,
subSpaceModel: newSubspaceModel.subspaceModel,
});
const createdSubspace = await this.subspaceRepository.save(subspace);
this.logger.log(
`Subspace created for space ${space.uuid} with name ${createdSubspace.subspaceName}`,
);
return createdSubspace;
}
private async processProducts(productModels: any[], subspace: any) {
for (const productModel of productModels) {
try {
const subspaceProduct = await this.createSubspaceProduct(
productModel,
subspace,
);
if (productModel.productItemModels?.length > 0) {
await this.processProductItems(
productModel.productItemModels,
subspaceProduct,
);
}
} catch (error) {
this.logger.error(
`Failed to create product for subspace ID: ${subspace.id}`,
error.stack,
);
}
}
}
private async createSubspaceProduct(productModel: any, subspace: any) {
const subspaceProduct = this.productRepository.create({
product: productModel.productModel.product,
subspace,
productCount: productModel.productModel.productCount,
model: productModel.productModel,
});
const createdSubspaceProduct =
await this.productRepository.save(subspaceProduct);
this.logger.log(
`Product added to subspace ${subspace.id} with count ${createdSubspaceProduct.productCount}`,
);
return createdSubspaceProduct;
}
private async processProductItems(
productItemModels: any[],
subspaceProduct: any,
) {
for (const productItemModel of productItemModels) {
try {
const subspaceProductItem = this.productItemRepository.create({
tag: productItemModel.tag,
subspaceProduct,
model: productItemModel,
});
await this.productItemRepository.save(subspaceProductItem);
this.logger.log(
`Product item added to subspace product ${subspaceProduct.id} with tag ${subspaceProductItem.tag}`,
);
} catch (error) {
this.logger.error(
`Failed to create product item for subspace product ID: ${subspaceProduct.id}`,
error.stack,
);
}
}
}
private async getSpacesByModel(uuid: string): Promise<SpaceEntity[]> {
try {
return await this.spaceRepository.find({
where: {
spaceModel: { uuid },
},
});
} catch (error) {
this.logger.error(
`Failed to fetch spaces for model UUID: ${uuid}`,
error.stack,
);
throw error;
}
}
}

View File

@ -0,0 +1 @@
export * from './update-subspace.interface'

View File

@ -0,0 +1,19 @@
import {
SubspaceModelEntity,
SubspaceProductItemModelEntity,
SubspaceProductModelEntity,
} from '@app/common/modules/space-model';
export interface AddSubspaceModelInterface {
subspaceModel: SubspaceModelEntity;
productModels: ProductModelInterface[];
}
export interface ProductModelInterface {
productModel: SubspaceProductModelEntity;
productItemModels: SubspaceProductItemModelEntity[];
}
export interface UpdatedSubspaceModelInterface {
new?: AddSubspaceModelInterface[];
}

View File

@ -18,6 +18,9 @@ import { SpaceModelDto } from '@app/common/modules/space-model/dtos';
import { SpaceModelParam } from '../dtos/space-model-param'; import { SpaceModelParam } from '../dtos/space-model-param';
import { ProjectService } from 'src/project/services'; import { ProjectService } from 'src/project/services';
import { ProjectEntity } from '@app/common/modules/project/entities'; import { ProjectEntity } from '@app/common/modules/project/entities';
import { UpdatedSubspaceModelInterface } from '../interfaces';
import { CommandBus } from '@nestjs/cqrs';
import { PropogateSubspaceCommand } from '../commands';
@Injectable() @Injectable()
export class SpaceModelService { export class SpaceModelService {
@ -27,6 +30,7 @@ export class SpaceModelService {
private readonly projectService: ProjectService, private readonly projectService: ProjectService,
private readonly subSpaceModelService: SubSpaceModelService, private readonly subSpaceModelService: SubSpaceModelService,
private readonly spaceProductModelService: SpaceProductModelService, private readonly spaceProductModelService: SpaceProductModelService,
private commandBus: CommandBus,
) {} ) {}
async createSpaceModel( async createSpaceModel(
@ -142,21 +146,27 @@ export class SpaceModelService {
await queryRunner.startTransaction(); await queryRunner.startTransaction();
try { try {
const { modelName } = dto; const { modelName } = dto;
let updatedSubspaces: UpdatedSubspaceModelInterface;
if (modelName) spaceModel.modelName = modelName; if (modelName) spaceModel.modelName = modelName;
await queryRunner.manager.save(spaceModel); await queryRunner.manager.save(spaceModel);
if (dto.subspaceModels) { if (dto.subspaceModels) {
const updatedSubspaces = updatedSubspaces = await this.subSpaceModelService.modifySubSpaceModels(
await this.subSpaceModelService.updateSubSpaceModels( dto.subspaceModels,
dto.subspaceModels, spaceModel,
spaceModel, queryRunner,
queryRunner, );
);
} }
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
if (updatedSubspaces) {
await this.commandBus.execute(
new PropogateSubspaceCommand(updatedSubspaces),
);
}
return new SuccessResponseDto({ return new SuccessResponseDto({
message: 'SpaceModel updated successfully', message: 'SpaceModel updated successfully',
data: spaceModel, data: spaceModel,

View File

@ -3,9 +3,10 @@ import {
SubspaceModelRepository, SubspaceModelRepository,
} from '@app/common/modules/space-model'; } from '@app/common/modules/space-model';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateSubspaceModelDto, UpdateSubspaceModelDto } from '../../dtos'; import { CreateSubspaceModelDto, UpdateSubspacesModelDto } from '../../dtos';
import { QueryRunner } from 'typeorm'; import { QueryRunner } from 'typeorm';
import { SubspaceProductModelService } from './subspace-product-model.service'; import { SubspaceProductModelService } from './subspace-product-model.service';
import { UpdatedSubspaceModelInterface } from 'src/space-model/interfaces';
@Injectable() @Injectable()
export class SubSpaceModelService { export class SubSpaceModelService {
@ -91,12 +92,12 @@ export class SubSpaceModelService {
} }
} }
async updateSubSpaceModels( async modifySubSpaceModels(
dto: UpdateSubspaceModelDto, dto: UpdateSubspacesModelDto,
spaceModel: SpaceModelEntity, spaceModel: SpaceModelEntity,
queryRunner: QueryRunner, queryRunner: QueryRunner,
) { ) {
const subspaces: { new?: any } = {}; const subspaces: UpdatedSubspaceModelInterface = {};
try { try {
if (dto.add) { if (dto.add) {
const addedSubspaces = await this.createSubSpaceModels( const addedSubspaces = await this.createSubSpaceModels(
@ -105,6 +106,8 @@ export class SubSpaceModelService {
queryRunner, queryRunner,
); );
subspaces.new = addedSubspaces; subspaces.new = addedSubspaces;
} else if (dto.update) {
} }
return subspaces; return subspaces;
} catch (error) { } catch (error) {

View File

@ -20,13 +20,25 @@ import {
import { ProjectRepository } from '@app/common/modules/project/repositiories'; import { ProjectRepository } from '@app/common/modules/project/repositiories';
import { ProductRepository } from '@app/common/modules/product/repositories'; import { ProductRepository } from '@app/common/modules/product/repositories';
import { SubspaceProductModelService } from './services/subspace/subspace-product-model.service'; import { SubspaceProductModelService } from './services/subspace/subspace-product-model.service';
import { PropogateSubspaceHandler } from './handlers';
import { CqrsModule } from '@nestjs/cqrs';
import { SpaceRepository } from '@app/common/modules/space';
import {
SubspaceProductItemRepository,
SubspaceProductRepository,
SubspaceRepository,
} from '@app/common/modules/space/repositories/subspace.repository';
const CommandHandlers = [PropogateSubspaceHandler];
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule], imports: [ConfigModule, SpaceRepositoryModule, CqrsModule],
controllers: [SpaceModelController], controllers: [SpaceModelController],
providers: [ providers: [
...CommandHandlers,
SpaceModelService, SpaceModelService,
SpaceModelRepository, SpaceModelRepository,
SpaceRepository,
ProjectRepository, ProjectRepository,
SubSpaceModelService, SubSpaceModelService,
SpaceProductModelService, SpaceProductModelService,
@ -39,7 +51,10 @@ import { SubspaceProductModelService } from './services/subspace/subspace-produc
SubspaceProductItemModelRepository, SubspaceProductItemModelRepository,
SubspaceProductModelService, SubspaceProductModelService,
SubspaceProductModelRepository, SubspaceProductModelRepository,
SubspaceRepository,
SubspaceProductRepository,
SubspaceProductItemRepository,
], ],
exports: [], exports: [CqrsModule],
}) })
export class SpaceModelModule {} export class SpaceModelModule {}