chore: add order to the service category

This commit is contained in:
mahyargdz
2025-03-09 16:56:43 +03:30
parent cdeca5375e
commit cb8ecd770c
4 changed files with 100 additions and 23 deletions
+4
View File
@@ -134,6 +134,10 @@ export const enum CategoryMessage {
IS_ACTIVE_SHOULD_BE_1_0 = "وضعیت دسته بندی باید یکی از مقادیر ۰ و ۱ باشد",
IS_SUGGEST_SHOULD_BE_1_0 = "وضعیت پیشنهادی بودن دسته بندی باید یکی از مقادیر ۰ و ۱ باشد",
CATEGORY_NOT_EXIST_OR_HAS_NO_SERVICE = "دسته بندی مورد نظر یافت نشد یا هیچ سرویسی در این دسته بندی وجود ندارد",
ORDER_REQUIRED = "ترتیب دسته بندی مورد نیاز است",
ORDER_SHOULD_BE_INT = "ترتیب دسته بندی باید یک عدد صحیح باشد",
CREATION_FAILED = "ایجاد دسته بندی موفیقیت آمیز نبود",
UPDATE_FAILED = "به روز رسانی دسته بندی موفیقیت آمیز نبود",
}
export const enum ServiceMessage {
@@ -1,5 +1,5 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import { IsBoolean, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length } from "class-validator";
import { IsBoolean, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length } from "class-validator";
import { CategoryMessage } from "../../../common/enums/message.enum";
@@ -25,4 +25,9 @@ export class CreateCategoryDto {
@IsUUID("4", { message: CategoryMessage.PARENT_ID_SHOULD_BE_UUID })
@ApiPropertyOptional({ description: "Parent category id", example: "8b1e8b1e-8b1e-8b1e-8b1e-8b1e8b1e8b1e" })
parentId?: string;
@IsNotEmpty({ message: CategoryMessage.ORDER_REQUIRED })
@IsInt({ message: CategoryMessage.ORDER_SHOULD_BE_INT })
@ApiProperty({ description: "Category order", example: 1 })
order: number;
}
@@ -14,6 +14,9 @@ export class DanakServiceCategory extends BaseEntity {
@Column({ type: "boolean", default: true })
isActive: boolean;
@Column({ type: "int", default: 1 })
order: number;
@ManyToOne(() => DanakServiceCategory, (category) => category.children)
@JoinColumn({ name: "parentId" })
parent: DanakServiceCategory;
@@ -1,5 +1,5 @@
import { BadRequestException, Injectable } from "@nestjs/common";
import { FindOptionsWhere, In, IsNull } from "typeorm";
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import { DataSource, FindOptionsWhere, In, IsNull, Not, QueryRunner } from "typeorm";
import { ParamDto } from "../../../common/DTO/param.dto";
import { CategoryMessage, CommonMessage, ServiceMessage, SubscriptionMessage } from "../../../common/enums/message.enum";
@@ -24,24 +24,67 @@ import { DanakServicesRepository } from "../repositories/danak-services.reposito
@Injectable()
export class DanakServicesService {
// private readonly logger = new Logger(DanakServicesService.name);
private readonly logger = new Logger(DanakServicesService.name);
constructor(
private readonly danakServicesRepository: DanakServicesRepository,
private readonly danakServicesCategoryRepository: DanakServicesCategoryRepository,
private readonly danakServiceReviewRepository: DanakServiceReviewRepository,
private readonly danakServicesImageRepository: DanakServicesImageRepository,
private readonly dataSource: DataSource,
) {}
/******************************************** */
async createCategory(createDto: CreateCategoryDto) {
const existCategory = await this.danakServicesCategoryRepository.findOneByTitle(createDto.title);
if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST);
const category = this.danakServicesCategoryRepository.create(createDto);
await this.danakServicesCategoryRepository.save(category);
return {
message: CommonMessage.CREATED,
category,
};
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const existCategory = await queryRunner.manager.findOne(this.danakServicesCategoryRepository.target, {
where: { title: createDto.title },
});
if (existCategory) {
throw new BadRequestException(CategoryMessage.TITLE_EXIST);
}
const category = queryRunner.manager.create(this.danakServicesCategoryRepository.target, createDto);
await queryRunner.manager.save(this.danakServicesCategoryRepository.target, category);
await this.handleOrderCollision(queryRunner, category);
await queryRunner.commitTransaction();
return {
message: CommonMessage.CREATED,
category,
};
} catch (error) {
await queryRunner.rollbackTransaction();
this.logger.error("Error in create category", error);
throw new BadRequestException(CategoryMessage.CREATION_FAILED);
} finally {
await queryRunner.release();
}
}
//*********************************** */
private async handleOrderCollision(queryRunner: QueryRunner, newCategory: DanakServiceCategory): Promise<void> {
const conflictingCategory = await queryRunner.manager.findOne(this.danakServicesCategoryRepository.target, {
where: {
order: newCategory.order,
id: Not(newCategory.id),
deletedAt: IsNull(),
},
});
if (conflictingCategory) {
const highestOrderCategory = await queryRunner.manager.findOne(this.danakServicesCategoryRepository.target, {
order: { order: "DESC" },
where: { deletedAt: IsNull() },
});
const newOrder = highestOrderCategory ? highestOrderCategory.order + 1 : newCategory.order + 1;
await queryRunner.manager.update(this.danakServicesCategoryRepository.target, conflictingCategory.id, { order: newOrder });
}
}
/******************************************** */
@@ -56,20 +99,42 @@ export class DanakServicesService {
/******************************************** */
async updateCategory(categoryId: string, updateDto: UpdateCategoryDto) {
const category = await this.danakServicesCategoryRepository.findOneById(categoryId);
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
if (updateDto.title) {
const existCategory = await this.danakServicesCategoryRepository.findOneByTitle(updateDto.title, categoryId);
if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST);
try {
const category = await queryRunner.manager.findOne(DanakServiceCategory, { where: { id: categoryId } });
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
if (updateDto.title) {
const existCategory = await queryRunner.manager.findOne(DanakServiceCategory, {
where: { title: updateDto.title, id: Not(categoryId) },
});
if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST);
}
await queryRunner.manager.update(DanakServiceCategory, categoryId, updateDto);
if (updateDto.order !== undefined && updateDto.order !== category.order) {
await this.handleOrderCollision(queryRunner, { ...category, ...updateDto });
}
await queryRunner.commitTransaction();
return {
message: CommonMessage.UPDATE_SUCCESS,
};
} catch (error) {
await queryRunner.rollbackTransaction();
this.logger.error("Error in update category", error);
throw new BadRequestException(CategoryMessage.UPDATE_FAILED);
} finally {
await queryRunner.release();
}
await this.danakServicesCategoryRepository.save({ ...category, ...updateDto });
return {
message: CommonMessage.UPDATE_SUCCESS,
};
}
/******************************************** */
async deleteCategoryById(categoryId: string) {
const category = await this.danakServicesCategoryRepository.findOneById(categoryId);
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
@@ -131,7 +196,7 @@ export class DanakServicesService {
async getCategoriesUserSide() {
const categories = await this.danakServicesCategoryRepository.find({
where: { isActive: true, deletedAt: IsNull() },
order: { createdAt: "DESC" },
order: { order: "DESC" },
});
return {
categories,