From 76624652486a97915c36c29463de1b606523f79b Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Nov 2025 16:31:46 -0600 Subject: [PATCH] Cache album queries --- app/admin/photos/[photoId]/edit/page.tsx | 7 ++++--- app/admin/uploads/page.tsx | 5 ++--- src/admin/AdminNav.tsx | 4 ++-- src/admin/select/AdminBatchEditPanel.tsx | 5 ++--- src/album/query.ts | 7 ++++--- src/photo/cache.ts | 13 +++++++++++++ src/photo/storage/server.ts | 5 ++++- 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/app/admin/photos/[photoId]/edit/page.tsx b/app/admin/photos/[photoId]/edit/page.tsx index 109140b5..cee0d533 100644 --- a/app/admin/photos/[photoId]/edit/page.tsx +++ b/app/admin/photos/[photoId]/edit/page.tsx @@ -1,5 +1,7 @@ import { redirect } from 'next/navigation'; import { + getAlbumsWithMetaCached, + getAlbumTitlesForPhotoCached, getPhotoNoStore, getUniqueFilmsCached, getUniqueRecipesCached, @@ -17,7 +19,6 @@ import { getOptimizedPhotoUrlForManipulation, getStorageUrlsForPhoto, } from '@/photo/storage'; -import { getAlbumsWithMeta, getAlbumTitlesForPhoto } from '@/album/query'; export default async function PhotoEditPage({ params, @@ -35,8 +36,8 @@ export default async function PhotoEditPage({ uniqueFilms, ] = await Promise.all([ getPhotoNoStore(photoId, true), - getAlbumTitlesForPhoto(photoId), - getAlbumsWithMeta(), + getAlbumTitlesForPhotoCached(photoId), + getAlbumsWithMetaCached(), getUniqueTagsCached(), getUniqueRecipesCached(), getUniqueFilmsCached(), diff --git a/app/admin/uploads/page.tsx b/app/admin/uploads/page.tsx index 9385bbf3..0f5d08b3 100644 --- a/app/admin/uploads/page.tsx +++ b/app/admin/uploads/page.tsx @@ -1,16 +1,15 @@ import { getStorageUploadUrlsNoStore } from '@/platforms/storage/cache'; import AppGrid from '@/components/AppGrid'; -import { getUniqueTagsCached } from '@/photo/cache'; +import { getUniqueTagsCached, getAlbumsWithMetaCached } from '@/photo/cache'; import AdminUploadsClient from '@/admin/AdminUploadsClient'; import { redirect } from 'next/navigation'; import { PATH_ADMIN_PHOTOS } from '@/app/path'; -import { getAlbumsWithMeta } from '@/album/query'; export const maxDuration = 60; export default async function AdminUploadsPage() { const urls = await getStorageUploadUrlsNoStore(); - const uniqueAlbums = await getAlbumsWithMeta(); + const uniqueAlbums = await getAlbumsWithMetaCached(); const uniqueTags = await getUniqueTagsCached(); if (urls.length === 0) { diff --git a/src/admin/AdminNav.tsx b/src/admin/AdminNav.tsx index d8d071af..da39f228 100644 --- a/src/admin/AdminNav.tsx +++ b/src/admin/AdminNav.tsx @@ -4,6 +4,7 @@ import { getPhotosMostRecentUpdateCached, getUniqueRecipesCached, getUniqueTagsCached, + getAlbumsWithMetaCached, } from '@/photo/cache'; import { PATH_ADMIN_ALBUMS, @@ -14,7 +15,6 @@ import { } from '@/app/path'; import AdminNavClient from './AdminNavClient'; import { getAppText } from '@/i18n/state/server'; -import { getAlbumsWithMeta } from '@/album/query'; export default async function AdminNav() { const [ @@ -34,7 +34,7 @@ export default async function AdminNav() { console.error(`Error getting blob upload urls: ${e}`); return 0; }), - getAlbumsWithMeta().then(albums => albums.length) + getAlbumsWithMetaCached().then(albums => albums.length) .catch(() => 0), getUniqueTagsCached().then(tags => tags.length) .catch(() => 0), diff --git a/src/admin/select/AdminBatchEditPanel.tsx b/src/admin/select/AdminBatchEditPanel.tsx index 442e4ba9..d6e2001d 100644 --- a/src/admin/select/AdminBatchEditPanel.tsx +++ b/src/admin/select/AdminBatchEditPanel.tsx @@ -1,13 +1,12 @@ -import { getUniqueTagsCached } from '@/photo/cache'; +import { getAlbumsWithMetaCached, getUniqueTagsCached } from '@/photo/cache'; import AdminBatchEditPanelClient from './AdminBatchEditPanelClient'; -import { getAlbumsWithMeta } from '@/album/query'; export default async function AdminBatchEditPanel({ onBatchActionComplete, }: { onBatchActionComplete?: () => Promise }) { - const uniqueAlbums = await getAlbumsWithMeta().catch(() => []); + const uniqueAlbums = await getAlbumsWithMetaCached().catch(() => []); const uniqueTags = await getUniqueTagsCached().catch(() => []); return ( safelyQuery(() => sql` SELECT * FROM albums WHERE slug=${slug} `.then(({ rows }) => rows[0] ? parseAlbumFromDb(rows[0]) : undefined) - , 'getAlbum'); + , 'getAlbumFromSlug'); export const deleteAlbum = (id: string) => safelyQuery(() => sql` @@ -90,7 +90,7 @@ export const getAlbumsWithMeta = () => count: parseInt(count, 10), lastModified: album.updated_at as Date, }))) - , 'getAlbumsWithPhotoCounts'); + , 'getAlbumsWithMeta'); export const clearPhotoAlbumIds = (photoId: string) => safelyQuery(() => sql` @@ -107,7 +107,8 @@ export const addPhotoAlbumIds = (photoIds: string[], albumIds: string[]) => { INSERT INTO album_photo (album_id, photo_id) ${valueString} ON CONFLICT (album_id, photo_id) DO NOTHING - `, values), 'updateAlbumPhoto'); + `, values) + , 'addPhotoAlbumIds'); } }; diff --git a/src/photo/cache.ts b/src/photo/cache.ts index 1222ff4a..c6afd4bd 100644 --- a/src/photo/cache.ts +++ b/src/photo/cache.ts @@ -39,6 +39,7 @@ import { PREFIX_ALBUM, } from '@/app/path'; import { createLensKey } from '@/lens'; +import { getAlbumsWithMeta, getAlbumTitlesForPhoto } from '@/album/query'; // Table key export const KEY_PHOTOS = 'photos'; @@ -223,6 +224,18 @@ export const getPhotoCached = (...args: Parameters) => getPhoto, [KEY_PHOTOS, KEY_PHOTO], )(...args).then(photo => photo ? parseCachedPhotoDates(photo) : undefined); + +export const getAlbumTitlesForPhotoCached = + unstable_cache( + getAlbumTitlesForPhoto, + [KEY_PHOTOS, KEY_ALBUMS], + ); + +export const getAlbumsWithMetaCached = + unstable_cache( + getAlbumsWithMeta, + [KEY_PHOTOS, KEY_ALBUMS], + ); export const getUniqueTagsCached = unstable_cache( diff --git a/src/photo/storage/server.ts b/src/photo/storage/server.ts index 3402271b..60ecf6a2 100644 --- a/src/photo/storage/server.ts +++ b/src/photo/storage/server.ts @@ -54,5 +54,8 @@ export const convertUploadToPhoto = async ({ : copyFile(uploadUrl, fileName); } // Store optimized photos after original photo is copied/moved - return promise.then(async url => storeOptimizedPhotos(url, fileBytes)); + const updatedUrl = await promise + .then(async url => storeOptimizedPhotos(url, fileBytes)); + + return updatedUrl; };