diff --git a/src/cache/cache.keys.ts b/src/cache/cache.keys.ts index 91d246b..a9698a7 100644 --- a/src/cache/cache.keys.ts +++ b/src/cache/cache.keys.ts @@ -1,7 +1,12 @@ export const keys = { restaurantBySlug: (slug: string) => `restaurant:slug:${slug}`, - restaurantCategories: (restaurantId: string) => `restaurant:${restaurantId}:categories`, + restaurantById: (id: string) => `restaurant:id:${id}`, + restaurantCategories: (restaurantId: string) => + `restaurant:${restaurantId}:categories`, restaurantItems: (restaurantId: string) => `restaurant:${restaurantId}:items`, + userRestaurants: (ownerId: string) => `user:${ownerId}:restaurants`, category: (categoryId: string) => `category:${categoryId}`, + categoryItems: (categoryId: string) => `category:${categoryId}:items`, item: (itemId: string) => `item:${itemId}`, + user: (userId: string) => `user:${userId}`, }; diff --git a/src/category/category.service.ts b/src/category/category.service.ts index c244032..ed53e8e 100644 --- a/src/category/category.service.ts +++ b/src/category/category.service.ts @@ -16,22 +16,31 @@ export class CategoryService { ) {} async _getCategorie(categoryId: string) { - const category = await this.prisma.category.findFirstOrThrow({ - where: { id: categoryId }, - include: { items: true, restaurant: true }, - }).catch(() => { - throw new NotFoundException('Category not found'); - }); + const cacheKey = keys.category(categoryId); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const category = await this.prisma.category + .findFirstOrThrow({ + where: { id: categoryId }, + include: { items: true, restaurant: true }, + }) + .catch(() => { + throw new NotFoundException('Category not found'); + }); + + await this.cache.set(cacheKey, category, 600); return category; } async create(dto: CreateCategoryDto, userId: string) { - const restaurant = await this.prisma.restaurant.findUniqueOrThrow({ - where: { id: dto.restaurantId }, - }).catch(() => { - throw new NotFoundException('Restaurant not found'); - }); + const restaurant = await this.prisma.restaurant + .findUniqueOrThrow({ + where: { id: dto.restaurantId }, + }) + .catch(() => { + throw new NotFoundException('Restaurant not found'); + }); await this.restaurantService.verifyOwnership(userId, restaurant.id); @@ -51,19 +60,31 @@ export class CategoryService { async findAllForRestaurant(restaurantId: string, userId: string) { await this.restaurantService.verifyOwnership(userId, restaurantId); - + + const cacheKey = keys.restaurantCategories(restaurantId); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const categories = await this.prisma.category.findMany({ where: { restaurantId }, include: { items: true }, }); - return categories.map(CategoryDto.fromEntity); + const result = categories.map(CategoryDto.fromEntity); + await this.cache.set(cacheKey, result, 300); + return result; } async findOne(id: string) { - const category = await this._getCategorie(id); + const cacheKey = keys.category(id); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; - return CategoryDto.fromEntity(category); + const category = await this._getCategorie(id); + const result = CategoryDto.fromEntity(category); + + await this.cache.set(cacheKey, result, 600); + return result; } async update(id: string, dto: UpdateCategoryDto, userId: string) { diff --git a/src/item/item.service.ts b/src/item/item.service.ts index ad631f2..ac72019 100644 --- a/src/item/item.service.ts +++ b/src/item/item.service.ts @@ -36,33 +36,54 @@ export class ItemService { await this.cache.del(keys.restaurantBySlug(category.restaurant.slug)); } await this.cache.del(keys.restaurantCategories(category.restaurantId)); + await this.cache.del(keys.restaurantItems(category.restaurantId)); + await this.cache.del(keys.categoryItems(category.id)); + await this.cache.del(keys.category(category.id)); return MenuItemDto.fromEntity(item); } async findAllByCategory(categoryId: string) { + const cacheKey = keys.categoryItems(categoryId); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const items = await this.prisma.menuItem.findMany({ where: { categoryId }, orderBy: { createdAt: 'desc' }, }); - return items.map(MenuItemDto.fromEntity); + const result = items.map(MenuItemDto.fromEntity); + await this.cache.set(cacheKey, result, 300); + return result; } async findAllForRestaurant(restaurantId: string) { + const cacheKey = keys.restaurantItems(restaurantId); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const items = await this.prisma.menuItem.findMany({ where: { restaurantId }, orderBy: { createdAt: 'desc' }, }); - return items.map(MenuItemDto.fromEntity); + const result = items.map(MenuItemDto.fromEntity); + await this.cache.set(cacheKey, result, 300); + return result; } async findOne(id: string) { + const cacheKey = keys.item(id); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const item = await this.prisma.menuItem.findUnique({ where: { id } }); if (!item) throw new NotFoundException('Menu item not found'); - return MenuItemDto.fromEntity(item); + const result = MenuItemDto.fromEntity(item); + await this.cache.set(cacheKey, result, 600); + return result; } async update(id: string, dto: UpdateItemDto, userId: string) { @@ -89,6 +110,16 @@ export class ItemService { await this.cache.del(keys.restaurantBySlug(category.restaurant.slug)); } await this.cache.del(keys.restaurantCategories(category.restaurantId)); + await this.cache.del(keys.restaurantItems(category.restaurantId)); + await this.cache.del(keys.categoryItems(category.id)); + await this.cache.del(keys.category(category.id)); + await this.cache.del(keys.item(id)); + + // If category changed, invalidate old category caches too + if (dto.categoryId && dto.categoryId !== item.categoryId) { + await this.cache.del(keys.categoryItems(item.categoryId)); + await this.cache.del(keys.category(item.categoryId)); + } return MenuItemDto.fromEntity(updated); } @@ -106,6 +137,10 @@ export class ItemService { await this.cache.del(keys.restaurantBySlug(category.restaurant.slug)); } await this.cache.del(keys.restaurantCategories(category.restaurantId)); + await this.cache.del(keys.restaurantItems(category.restaurantId)); + await this.cache.del(keys.categoryItems(category.id)); + await this.cache.del(keys.category(category.id)); + await this.cache.del(keys.item(id)); return deleted; } diff --git a/src/restaurant/restaurant.service.ts b/src/restaurant/restaurant.service.ts index 0efdbbb..a4de7ae 100644 --- a/src/restaurant/restaurant.service.ts +++ b/src/restaurant/restaurant.service.ts @@ -40,15 +40,23 @@ export class RestaurantService { }, }); + await this.cache.del(keys.userRestaurants(ownerId)); + return RestaurantDto.fromEntity(restaurant); } async findByOwner(ownerId: string) { + const cacheKey = keys.userRestaurants(ownerId); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const restaurants = await this.prisma.restaurant.findMany({ where: { ownerId }, }); - return restaurants.map(RestaurantDto.fromEntity); + const result = restaurants.map(RestaurantDto.fromEntity); + await this.cache.set(cacheKey, result, 300); + return result; } async findAll() { @@ -57,6 +65,10 @@ export class RestaurantService { } async findOne(id: string) { + const cacheKey = keys.restaurantById(id); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const restaurant = await this.prisma.restaurant.findUnique({ where: { id }, }); @@ -65,7 +77,9 @@ export class RestaurantService { throw new NotFoundException('Restaurant not found'); } - return RestaurantDto.fromEntity(restaurant); + const result = RestaurantDto.fromEntity(restaurant); + await this.cache.set(cacheKey, result, 600); + return result; } async findMyRestaurant(id: string, userId: string) { @@ -113,8 +127,10 @@ export class RestaurantService { // Invalidate cache by slug and by id await this.cache.del(keys.restaurantBySlug(updated.slug)); + await this.cache.del(keys.restaurantById(updated.id)); await this.cache.del(keys.restaurantCategories(updated.id)); await this.cache.del(keys.restaurantItems(updated.id)); + await this.cache.del(keys.userRestaurants(userId)); return RestaurantDto.fromEntity(updated); } @@ -125,8 +141,10 @@ export class RestaurantService { // invalidate await this.cache.del(keys.restaurantBySlug(deleted.slug)); + await this.cache.del(keys.restaurantById(deleted.id)); await this.cache.del(keys.restaurantCategories(deleted.id)); await this.cache.del(keys.restaurantItems(deleted.id)); + await this.cache.del(keys.userRestaurants(userId)); return deleted; } diff --git a/src/user/user.module.ts b/src/user/user.module.ts index 371f70e..03ae12d 100644 --- a/src/user/user.module.ts +++ b/src/user/user.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { UserController } from './user.controller'; import { UserService } from './user.service'; import { PrismaModule } from 'src/prisma/prisma.module'; +import { CacheModule } from 'src/cache/cache.module'; @Module({ - imports: [PrismaModule], + imports: [PrismaModule, CacheModule], controllers: [UserController], providers: [UserService], }) diff --git a/src/user/user.service.ts b/src/user/user.service.ts index b4f2198..31cae4d 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -1,9 +1,14 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; +import { CacheService } from 'src/cache/cache.service'; +import { keys } from 'src/cache/cache.keys'; @Injectable() export class UserService { - constructor(private readonly prisma: PrismaService) {} + constructor( + private readonly prisma: PrismaService, + private readonly cache: CacheService, + ) {} async getAllUsers() { return this.prisma.user.findMany({ @@ -12,11 +17,17 @@ export class UserService { } async getUserById(id: string) { + const cacheKey = keys.user(id); + const cached = await this.cache.get(cacheKey); + if (cached) return cached; + const user = await this.prisma.user.findUnique({ where: { id }, include: { accounts: true, sessions: true, restaurants: true }, }); if (!user) throw new NotFoundException('User not found'); + + await this.cache.set(cacheKey, user, 600); return user; } @@ -25,7 +36,14 @@ export class UserService { await this.prisma.session.deleteMany({ where: { userId: id } }); await this.prisma.account.deleteMany({ where: { userId: id } }); await this.prisma.restaurant.deleteMany({ where: { ownerId: id } }); - return this.prisma.user.delete({ where: { id } }); + + const deleted = await this.prisma.user.delete({ where: { id } }); + + // Invalidate caches + await this.cache.del(keys.user(id)); + await this.cache.del(keys.userRestaurants(id)); + + return deleted; } async getSessionsByUserId(id: string) {