cache
This commit is contained in:
@@ -11,9 +11,10 @@ import { Food } from './entities/food.entity';
|
|||||||
import { RestaurantsModule } from '../restaurants/restaurants.module';
|
import { RestaurantsModule } from '../restaurants/restaurants.module';
|
||||||
import { AuthModule } from '../auth/auth.module';
|
import { AuthModule } from '../auth/auth.module';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { UtilsModule } from '../utils/utils.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [MikroOrmModule.forFeature([Food, Category]), RestaurantsModule, AuthModule, JwtModule],
|
imports: [MikroOrmModule.forFeature([Food, Category]), RestaurantsModule, AuthModule, JwtModule, UtilsModule],
|
||||||
controllers: [FoodController, CategoryController],
|
controllers: [FoodController, CategoryController],
|
||||||
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
|
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
|
||||||
exports: [FoodRepository, CategoryRepository],
|
exports: [FoodRepository, CategoryRepository],
|
||||||
|
|||||||
@@ -8,14 +8,19 @@ import { RequiredEntityData } from '@mikro-orm/core';
|
|||||||
import { Food } from '../entities/food.entity';
|
import { Food } from '../entities/food.entity';
|
||||||
import { CategoryMessage, 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';
|
import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository';
|
||||||
|
import { CacheService } from '../../utils/cache.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FoodService {
|
export class FoodService {
|
||||||
|
private readonly FOODS_BY_RESTAURANT_CACHE_KEY_PREFIX = 'foods:restaurant:';
|
||||||
|
private readonly FOODS_CACHE_TTL = 600; // 10 minutes in seconds
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly foodRepository: FoodRepository,
|
private readonly foodRepository: FoodRepository,
|
||||||
private readonly categoryRepository: CategoryRepository,
|
private readonly categoryRepository: CategoryRepository,
|
||||||
private readonly restRepository: RestRepository,
|
private readonly restRepository: RestRepository,
|
||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
|
private readonly cacheService: CacheService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(restId: string, createFoodDto: CreateFoodDto): Promise<Food> {
|
async create(restId: string, createFoodDto: CreateFoodDto): Promise<Food> {
|
||||||
@@ -65,6 +70,10 @@ export class FoodService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.em.persistAndFlush(food);
|
await this.em.persistAndFlush(food);
|
||||||
|
|
||||||
|
// Invalidate cache for the restaurant
|
||||||
|
await this.invalidateRestaurantFoodsCache(restaurant.slug);
|
||||||
|
|
||||||
return food;
|
return food;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,15 +90,37 @@ export class FoodService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findAllByRestaurant(slug: string): Promise<Food[]> {
|
async findAllByRestaurant(slug: string): Promise<Food[]> {
|
||||||
|
const cacheKey = `${this.FOODS_BY_RESTAURANT_CACHE_KEY_PREFIX}${slug}`;
|
||||||
|
|
||||||
|
// Try to get from cache first
|
||||||
|
const cachedFoods = await this.cacheService.get<string>(cacheKey);
|
||||||
|
if (cachedFoods) {
|
||||||
|
try {
|
||||||
|
const parsed: unknown = JSON.parse(cachedFoods);
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
return parsed as Food[];
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// If parsing fails, continue to fetch from DB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not in cache, fetch from database
|
||||||
const restaurant = await this.restRepository.findOne({ slug });
|
const restaurant = await this.restRepository.findOne({ slug });
|
||||||
if (!restaurant) {
|
if (!restaurant) {
|
||||||
throw new NotFoundException(RestMessage.NOT_FOUND);
|
throw new NotFoundException(RestMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
return this.foodRepository.find({ restaurant: { slug }, isActive: true }, { populate: ['category'] });
|
|
||||||
|
const foods = await this.foodRepository.find({ restaurant: { slug }, isActive: true }, { populate: ['category'] });
|
||||||
|
|
||||||
|
// Cache the result
|
||||||
|
await this.cacheService.set(cacheKey, JSON.stringify(foods), this.FOODS_CACHE_TTL);
|
||||||
|
|
||||||
|
return foods;
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, dto: Partial<CreateFoodDto>): Promise<Food> {
|
async update(id: string, dto: Partial<CreateFoodDto>): Promise<Food> {
|
||||||
const food = await this.foodRepository.findOne({ id });
|
const food = await this.foodRepository.findOne({ id }, { populate: ['restaurant'] });
|
||||||
if (!food) {
|
if (!food) {
|
||||||
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
@@ -109,15 +140,32 @@ export class FoodService {
|
|||||||
this.em.assign(food, rest);
|
this.em.assign(food, rest);
|
||||||
|
|
||||||
await this.em.persistAndFlush(food);
|
await this.em.persistAndFlush(food);
|
||||||
|
|
||||||
|
// Invalidate cache for the restaurant
|
||||||
|
await this.invalidateRestaurantFoodsCache(food.restaurant.slug);
|
||||||
|
|
||||||
return food;
|
return food;
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string) {
|
async remove(id: string) {
|
||||||
const food = await this.foodRepository.findOne({ id });
|
const food = await this.foodRepository.findOne({ id }, { populate: ['restaurant'] });
|
||||||
if (!food) {
|
if (!food) {
|
||||||
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const restaurantSlug = food.restaurant.slug;
|
||||||
food.deletedAt = new Date();
|
food.deletedAt = new Date();
|
||||||
await this.em.persistAndFlush(food);
|
await this.em.persistAndFlush(food);
|
||||||
|
|
||||||
|
// Invalidate cache for the restaurant
|
||||||
|
await this.invalidateRestaurantFoodsCache(restaurantSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate cache for restaurant foods
|
||||||
|
*/
|
||||||
|
private async invalidateRestaurantFoodsCache(slug: string): Promise<void> {
|
||||||
|
const cacheKey = `${this.FOODS_BY_RESTAURANT_CACHE_KEY_PREFIX}${slug}`;
|
||||||
|
await this.cacheService.del(cacheKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user