up
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, {
|
||||
|
||||
Reference in New Issue
Block a user