category
This commit is contained in:
@@ -64,8 +64,8 @@ export class FoodController {
|
||||
@ApiParam({ name: 'id', required: true })
|
||||
@ApiOkResponse({ description: 'The food', type: CreateFoodDto })
|
||||
@ApiNotFoundResponse({ description: 'Food not found' })
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.foodsService.findOne(id);
|
||||
findById(@Param('id') id: string) {
|
||||
return this.foodsService.findById(id);
|
||||
}
|
||||
|
||||
@UseGuards(AdminAuthGuard)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { IsBoolean, IsOptional, IsString, IsNumber, IsArray } from 'class-validator';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsBoolean, IsOptional, IsString, IsNumber, IsArray, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class CreateFoodDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty({ example: '123e4567-e89b-12d3-a456-426614174000' })
|
||||
categoryId: string;
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@ApiPropertyOptional({ example: false })
|
||||
@@ -92,7 +96,7 @@ export class CreateFoodDto {
|
||||
@ApiPropertyOptional({ example: true })
|
||||
@Type(() => Boolean)
|
||||
dinner?: boolean;
|
||||
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@@ -128,13 +132,13 @@ export class CreateFoodDto {
|
||||
@ApiPropertyOptional({ example: false })
|
||||
@Type(() => Boolean)
|
||||
pickupServe?: boolean;
|
||||
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@ApiPropertyOptional({ example: 0 })
|
||||
discount?: number;
|
||||
|
||||
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Entity, Property, ManyToMany, Collection } from '@mikro-orm/core';
|
||||
import { Entity, Property, Collection, OneToMany } from '@mikro-orm/core';
|
||||
import { Food } from './food.entity';
|
||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||
|
||||
@@ -7,7 +7,7 @@ export class Category extends BaseEntity {
|
||||
@Property()
|
||||
title!: string;
|
||||
|
||||
@ManyToMany(() => Food, food => food.categories)
|
||||
@OneToMany(() => Food, food => food.category)
|
||||
foods = new Collection<Food>(this);
|
||||
|
||||
@Property({ default: true })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Collection, Entity, ManyToMany, ManyToOne, Property } from '@mikro-orm/core';
|
||||
import { Entity, ManyToOne, Property } from '@mikro-orm/core';
|
||||
import { Category } from './category.entity';
|
||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||
import { Restaurant } from '../../../modules/restaurants/entities/restaurant.entity';
|
||||
@@ -8,8 +8,8 @@ export class Food extends BaseEntity {
|
||||
@ManyToOne(() => Restaurant)
|
||||
restaurant: Restaurant;
|
||||
|
||||
@ManyToMany(() => Category)
|
||||
categories = new Collection<Category>(this);
|
||||
@ManyToOne(() => Category)
|
||||
category!: Category;
|
||||
|
||||
@Property({ nullable: true })
|
||||
title?: string;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { CategoryRepository } from '../repositories/category.repository';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { RequiredEntityData } from '@mikro-orm/core';
|
||||
import { Food } from '../entities/food.entity';
|
||||
import { FoodMessage, RestMessage } from 'src/common/enums/message.enum';
|
||||
import { CategoryMessage, FoodMessage, RestMessage } from 'src/common/enums/message.enum';
|
||||
import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository';
|
||||
|
||||
@Injectable()
|
||||
@@ -19,11 +19,16 @@ export class FoodService {
|
||||
) {}
|
||||
|
||||
async create(restId: string, createFoodDto: CreateFoodDto): Promise<Food> {
|
||||
const { categoryIds, ...rest } = createFoodDto;
|
||||
const { categoryId, ...rest } = createFoodDto;
|
||||
const restaurant = await this.restRepository.findOne({ id: restId });
|
||||
if (!restaurant) {
|
||||
throw new NotFoundException(RestMessage.NOT_FOUND);
|
||||
}
|
||||
const category = await this.categoryRepository.findOne({ id: categoryId });
|
||||
if (!category) {
|
||||
throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
||||
}
|
||||
|
||||
// prepare data with defaults for required fields so repository.create typing is satisfied
|
||||
const data: RequiredEntityData<Food> = {
|
||||
// boolean/day flags
|
||||
@@ -49,6 +54,7 @@ export class FoodService {
|
||||
prepareTime: rest.prepareTime ?? 0,
|
||||
images: rest.images ?? undefined,
|
||||
restaurant: restaurant,
|
||||
category: category
|
||||
};
|
||||
|
||||
const food = this.foodRepository.create(data);
|
||||
@@ -56,12 +62,6 @@ export class FoodService {
|
||||
throw new Error('Failed to create food entity');
|
||||
}
|
||||
|
||||
// attach categories if provided
|
||||
if (categoryIds && categoryIds.length) {
|
||||
const categories = await this.categoryRepository.find({ id: { $in: categoryIds } });
|
||||
categories.forEach(cat => food.categories.add(cat));
|
||||
}
|
||||
|
||||
await this.em.persistAndFlush(food);
|
||||
return food;
|
||||
}
|
||||
@@ -70,40 +70,36 @@ export class FoodService {
|
||||
return this.foodRepository.findAllPaginated(restId, dto);
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<Food> {
|
||||
const food = await this.foodRepository.findOne({ id }, { populate: ['category'] });
|
||||
if (!food) {
|
||||
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||
}
|
||||
return food;
|
||||
}
|
||||
|
||||
async findAllByRestaurant(slug: string): Promise<Food[]> {
|
||||
const restaurant = await this.restRepository.findOne({ slug });
|
||||
if (!restaurant) {
|
||||
throw new NotFoundException(RestMessage.NOT_FOUND);
|
||||
}
|
||||
return this.foodRepository.find({ restaurant: { slug } });
|
||||
}
|
||||
|
||||
findOne(id: string) {
|
||||
return this.foodRepository.findOne({ id }, { populate: ['categories'] });
|
||||
return this.foodRepository.find({ restaurant: { slug }, isActive: true }, { populate: ['category'] });
|
||||
}
|
||||
|
||||
async update(id: string, dto: Partial<CreateFoodDto>): Promise<Food> {
|
||||
const food = await this.foodRepository.findOne({ id });
|
||||
|
||||
if (!food) {
|
||||
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||
}
|
||||
|
||||
const { categoryIds, ...rest } = dto;
|
||||
|
||||
// assign scalar fields
|
||||
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) {
|
||||
const categories = await this.categoryRepository.find({ id: { $in: categoryIds } });
|
||||
if (dto.categoryId) {
|
||||
const category = await this.categoryRepository.findOne({ id: dto.categoryId });
|
||||
|
||||
food.categories.removeAll();
|
||||
if (!category) {
|
||||
throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
||||
}
|
||||
|
||||
categories.forEach(cat => {
|
||||
// Collection.add will ignore duplicates
|
||||
food.categories.add(cat);
|
||||
});
|
||||
this.em.assign(food, { category: category });
|
||||
}
|
||||
|
||||
await this.em.persistAndFlush(food);
|
||||
|
||||
@@ -48,7 +48,7 @@ export class FoodRepository extends EntityRepository<Food> {
|
||||
limit,
|
||||
offset,
|
||||
orderBy: { [orderBy]: order.toLowerCase() as 'asc' | 'desc' },
|
||||
populate: ['categories'],
|
||||
populate: ['category'],
|
||||
});
|
||||
|
||||
const totalPages = Math.ceil(total / limit);
|
||||
|
||||
Reference in New Issue
Block a user