import { Injectable } from '@nestjs/common'; import { EntityManager, EntityRepository } from '@mikro-orm/postgresql'; import { FilterQuery } from '@mikro-orm/core'; import { Review } from '../entities/review.entity'; import { PaginatedResult } from 'src/common/interfaces/pagination.interface'; import { ReviewStatus } from '../enums/review-status.enum'; type FindReviewsOpts = { page?: number; limit?: number; foodId?: string; userId?: string; status?: ReviewStatus; orderBy?: string; restId?: string; order?: 'asc' | 'desc'; parentId?: string; topLevel?: boolean; }; @Injectable() export class ReviewRepository extends EntityRepository { constructor(readonly em: EntityManager) { super(em, Review); } /** * Find reviews with pagination and optional filters. * Supports: foodId, userId, status, ordering. */ async findAllPaginated(opts: FindReviewsOpts = {}): Promise> { const { page = 1, limit = 10, parentId, topLevel, foodId, restId, userId, status, orderBy = 'createdAt', order = 'desc' } = opts; const offset = (page - 1) * limit; // Only list top-level reviews; replies are nested under their parent const where: FilterQuery = {}; if (topLevel) { where.parent = null; } if (parentId) { where.parent = { id: parentId }; } if (foodId) { where.food = { id: foodId }; } if (restId) { where.food = { restaurant: { id: restId } }; } if (userId) { where.user = { id: userId }; } if (status) { where.status = status; } const [data, total] = await this.findAndCount(where, { limit, offset, orderBy: { [orderBy]: order.toLowerCase() as 'asc' | 'desc' }, populate: ['user', 'admin', 'parent', 'parent.user'], }); const totalPages = Math.ceil(total / limit); return { data, meta: { total, page, limit, totalPages, }, }; } }