This commit is contained in:
2025-11-15 09:14:32 +03:30
parent 53ef6220c1
commit 84163f6c8c
7 changed files with 25 additions and 22 deletions
+1 -2
View File
@@ -3,10 +3,9 @@ import { ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
export class CreateCategoryDto {
@IsOptional()
@IsString()
@ApiPropertyOptional({ example: 'Beverages' })
title?: string;
title!: string;
@IsOptional()
@IsBoolean()
@@ -1,14 +1,14 @@
import { Entity, Property, ManyToMany, Collection } from '@mikro-orm/core';
import { Foods } from './food.entity';
import { Food } from './food.entity';
import { BaseEntity } from '../../../common/entities/base.entity';
@Entity({ tableName: 'categories' })
export class Category extends BaseEntity {
@Property({ nullable: true })
title?: string;
@Property()
title!: string;
@ManyToMany(() => Foods, food => food.categories)
foods = new Collection<Foods>(this);
@ManyToMany(() => Food, food => food.categories)
foods = new Collection<Food>(this);
@Property({ default: true })
isActive: boolean = true;
+1 -1
View File
@@ -3,7 +3,7 @@ import { Category } from './category.entity';
import { BaseEntity } from '../../../common/entities/base.entity';
@Entity({ tableName: 'foods' })
export class Foods extends BaseEntity {
export class Food extends BaseEntity {
@ManyToMany(() => Category)
categories = new Collection<Category>(this);
+4
View File
@@ -5,8 +5,12 @@ import { CategorysController } from './controllers/categorys.controller';
import { CategoryService } from './providers/category.service';
import { FoodRepository } from './repositories/food.repository';
import { CategoryRepository } from './repositories/category.repository';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { Category } from './entities/category.entity';
import { Food } from './entities/food.entity';
@Module({
imports: [MikroOrmModule.forFeature([Food, Category])],
controllers: [FoodController, CategorysController],
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
exports: [FoodRepository, CategoryRepository],
@@ -15,12 +15,12 @@ export class CategoryService {
) {}
async create(dto: CreateCategoryDto): Promise<Category> {
const data = {
const data: RequiredEntityData<Category> = {
title: dto.title,
isActive: dto.isActive ?? true,
restId: dto.restId,
avatarUrl: dto.avatarUrl,
} as RequiredEntityData<Category>;
};
const category = this.categoryRepository.create(data);
await this.em.persistAndFlush(category);
+6 -6
View File
@@ -5,7 +5,7 @@ import { FoodRepository } from '../repositories/food.repository';
import { CategoryRepository } from '../repositories/category.repository';
import { EntityManager } from '@mikro-orm/postgresql';
import { RequiredEntityData } from '@mikro-orm/core';
import { Foods } from '../entities/food.entity';
import { Food } from '../entities/food.entity';
import { FoodMessage } from 'src/common/enums/message.enum';
@Injectable()
@@ -16,11 +16,11 @@ export class FoodService {
private readonly em: EntityManager,
) {}
async create(createFoodDto: CreateFoodDto): Promise<Foods> {
async create(createFoodDto: CreateFoodDto): Promise<Food> {
const { categoryIds, ...rest } = createFoodDto;
// prepare data with defaults for required fields so repository.create typing is satisfied
const data: RequiredEntityData<Foods> = {
const data: RequiredEntityData<Food> = {
// boolean/day flags
sat: rest.sat ?? false,
sun: rest.sun ?? false,
@@ -45,7 +45,7 @@ export class FoodService {
points: rest.points ?? 0,
prepareTime: rest.prepareTime ?? 0,
images: rest.images ?? undefined,
} as RequiredEntityData<Foods>;
} as RequiredEntityData<Food>;
const food = this.foodRepository.create(data);
@@ -67,7 +67,7 @@ export class FoodService {
return this.foodRepository.findOne({ id }, { populate: ['categories'] });
}
async update(id: string, dto: Partial<CreateFoodDto>): Promise<Foods> {
async update(id: string, dto: Partial<CreateFoodDto>): Promise<Food> {
const food = await this.foodRepository.findOne({ id });
if (!food) {
@@ -77,7 +77,7 @@ export class FoodService {
const { categoryIds, ...rest } = dto;
// assign scalar fields
this.em.assign(food, rest as Partial<Foods>);
this.em.assign(food, rest as Partial<Food>);
// attach new categories if provided (adds, does not attempt to preserve/remove existing ones)
if (Array.isArray(categoryIds) && categoryIds.length) {
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
import { FilterQuery } from '@mikro-orm/core';
import { Foods } from '../entities/food.entity';
import { Food } from '../entities/food.entity';
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
type FindFoodsOpts = {
@@ -15,20 +15,20 @@ type FindFoodsOpts = {
};
@Injectable()
export class FoodRepository extends EntityRepository<Foods> {
export class FoodRepository extends EntityRepository<Food> {
constructor(readonly em: EntityManager) {
super(em, Foods);
super(em, Food);
}
/**
* Find foods with pagination and optional filters.
* Supports: search (title/content), categoryId, isActive, ordering.
*/
async findAllPaginated(opts: FindFoodsOpts = {}): Promise<PaginatedResult<Foods>> {
async findAllPaginated(opts: FindFoodsOpts = {}): Promise<PaginatedResult<Food>> {
const { page = 1, limit = 10, search, orderBy = 'createdAt', order = 'desc', categoryId, isActive } = opts;
const offset = (page - 1) * limit;
const where: FilterQuery<Foods> = {};
const where: FilterQuery<Food> = {};
if (typeof isActive === 'boolean') {
where.isActive = isActive;
@@ -41,7 +41,7 @@ export class FoodRepository extends EntityRepository<Foods> {
if (categoryId) {
// filter by related categories (typed via FilterQuery)
Object.assign(where, { categories: { id: categoryId } } as unknown as FilterQuery<Foods>);
Object.assign(where, { categories: { id: categoryId } } as unknown as FilterQuery<Food>);
}
const [data, total] = await this.findAndCount(where, {