import { db, recipePhotos, recipeBatchDishes, favorites, inArray, eq, and } from "@epicure/db"; export type CardExtras = { photos: { storageKey: string; isCover: boolean }[]; dishCount: number; isFavorited: boolean; }; /** Batches the photo/batch-dish/favorite lookups a recipe grid card needs, for * list endpoints whose main query selects individual recipe columns rather * than going through `db.query.recipes.findMany`'s relational loader. */ export async function attachCardExtras( recipeList: T[], viewerId?: string ): Promise<(T & CardExtras)[]> { const ids = recipeList.map((r) => r.id); if (ids.length === 0) return []; const [photoRows, dishRows, favoritedRows] = await Promise.all([ db .select({ recipeId: recipePhotos.recipeId, storageKey: recipePhotos.storageKey, isCover: recipePhotos.isCover }) .from(recipePhotos) .where(inArray(recipePhotos.recipeId, ids)), db .select({ recipeId: recipeBatchDishes.recipeId }) .from(recipeBatchDishes) .where(inArray(recipeBatchDishes.recipeId, ids)), viewerId ? db .select({ recipeId: favorites.recipeId }) .from(favorites) .where(and(eq(favorites.userId, viewerId), inArray(favorites.recipeId, ids))) : Promise.resolve([]), ]); const photosByRecipe = new Map(); for (const p of photoRows) { const arr = photosByRecipe.get(p.recipeId) ?? []; arr.push({ storageKey: p.storageKey, isCover: p.isCover }); photosByRecipe.set(p.recipeId, arr); } const dishCountByRecipe = new Map(); for (const d of dishRows) dishCountByRecipe.set(d.recipeId, (dishCountByRecipe.get(d.recipeId) ?? 0) + 1); const favoritedSet = new Set(favoritedRows.map((f) => f.recipeId)); return recipeList.map((r) => ({ ...r, photos: photosByRecipe.get(r.id) ?? [], dishCount: dishCountByRecipe.get(r.id) ?? 0, isFavorited: favoritedSet.has(r.id), })); }