Cache album queries

This commit is contained in:
Sam Becker 2025-11-15 16:31:46 -06:00
parent 64441a12c1
commit 7662465248
7 changed files with 31 additions and 15 deletions

View File

@ -1,5 +1,7 @@
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { import {
getAlbumsWithMetaCached,
getAlbumTitlesForPhotoCached,
getPhotoNoStore, getPhotoNoStore,
getUniqueFilmsCached, getUniqueFilmsCached,
getUniqueRecipesCached, getUniqueRecipesCached,
@ -17,7 +19,6 @@ import {
getOptimizedPhotoUrlForManipulation, getOptimizedPhotoUrlForManipulation,
getStorageUrlsForPhoto, getStorageUrlsForPhoto,
} from '@/photo/storage'; } from '@/photo/storage';
import { getAlbumsWithMeta, getAlbumTitlesForPhoto } from '@/album/query';
export default async function PhotoEditPage({ export default async function PhotoEditPage({
params, params,
@ -35,8 +36,8 @@ export default async function PhotoEditPage({
uniqueFilms, uniqueFilms,
] = await Promise.all([ ] = await Promise.all([
getPhotoNoStore(photoId, true), getPhotoNoStore(photoId, true),
getAlbumTitlesForPhoto(photoId), getAlbumTitlesForPhotoCached(photoId),
getAlbumsWithMeta(), getAlbumsWithMetaCached(),
getUniqueTagsCached(), getUniqueTagsCached(),
getUniqueRecipesCached(), getUniqueRecipesCached(),
getUniqueFilmsCached(), getUniqueFilmsCached(),

View File

@ -1,16 +1,15 @@
import { getStorageUploadUrlsNoStore } from '@/platforms/storage/cache'; import { getStorageUploadUrlsNoStore } from '@/platforms/storage/cache';
import AppGrid from '@/components/AppGrid'; import AppGrid from '@/components/AppGrid';
import { getUniqueTagsCached } from '@/photo/cache'; import { getUniqueTagsCached, getAlbumsWithMetaCached } from '@/photo/cache';
import AdminUploadsClient from '@/admin/AdminUploadsClient'; import AdminUploadsClient from '@/admin/AdminUploadsClient';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { PATH_ADMIN_PHOTOS } from '@/app/path'; import { PATH_ADMIN_PHOTOS } from '@/app/path';
import { getAlbumsWithMeta } from '@/album/query';
export const maxDuration = 60; export const maxDuration = 60;
export default async function AdminUploadsPage() { export default async function AdminUploadsPage() {
const urls = await getStorageUploadUrlsNoStore(); const urls = await getStorageUploadUrlsNoStore();
const uniqueAlbums = await getAlbumsWithMeta(); const uniqueAlbums = await getAlbumsWithMetaCached();
const uniqueTags = await getUniqueTagsCached(); const uniqueTags = await getUniqueTagsCached();
if (urls.length === 0) { if (urls.length === 0) {

View File

@ -4,6 +4,7 @@ import {
getPhotosMostRecentUpdateCached, getPhotosMostRecentUpdateCached,
getUniqueRecipesCached, getUniqueRecipesCached,
getUniqueTagsCached, getUniqueTagsCached,
getAlbumsWithMetaCached,
} from '@/photo/cache'; } from '@/photo/cache';
import { import {
PATH_ADMIN_ALBUMS, PATH_ADMIN_ALBUMS,
@ -14,7 +15,6 @@ import {
} from '@/app/path'; } from '@/app/path';
import AdminNavClient from './AdminNavClient'; import AdminNavClient from './AdminNavClient';
import { getAppText } from '@/i18n/state/server'; import { getAppText } from '@/i18n/state/server';
import { getAlbumsWithMeta } from '@/album/query';
export default async function AdminNav() { export default async function AdminNav() {
const [ const [
@ -34,7 +34,7 @@ export default async function AdminNav() {
console.error(`Error getting blob upload urls: ${e}`); console.error(`Error getting blob upload urls: ${e}`);
return 0; return 0;
}), }),
getAlbumsWithMeta().then(albums => albums.length) getAlbumsWithMetaCached().then(albums => albums.length)
.catch(() => 0), .catch(() => 0),
getUniqueTagsCached().then(tags => tags.length) getUniqueTagsCached().then(tags => tags.length)
.catch(() => 0), .catch(() => 0),

View File

@ -1,13 +1,12 @@
import { getUniqueTagsCached } from '@/photo/cache'; import { getAlbumsWithMetaCached, getUniqueTagsCached } from '@/photo/cache';
import AdminBatchEditPanelClient from './AdminBatchEditPanelClient'; import AdminBatchEditPanelClient from './AdminBatchEditPanelClient';
import { getAlbumsWithMeta } from '@/album/query';
export default async function AdminBatchEditPanel({ export default async function AdminBatchEditPanel({
onBatchActionComplete, onBatchActionComplete,
}: { }: {
onBatchActionComplete?: () => Promise<void> onBatchActionComplete?: () => Promise<void>
}) { }) {
const uniqueAlbums = await getAlbumsWithMeta().catch(() => []); const uniqueAlbums = await getAlbumsWithMetaCached().catch(() => []);
const uniqueTags = await getUniqueTagsCached().catch(() => []); const uniqueTags = await getUniqueTagsCached().catch(() => []);
return ( return (
<AdminBatchEditPanelClient {...{ <AdminBatchEditPanelClient {...{

View File

@ -66,7 +66,7 @@ export const getAlbumFromSlug = (slug: string) =>
safelyQuery(() => sql<Album>` safelyQuery(() => sql<Album>`
SELECT * FROM albums WHERE slug=${slug} SELECT * FROM albums WHERE slug=${slug}
`.then(({ rows }) => rows[0] ? parseAlbumFromDb(rows[0]) : undefined) `.then(({ rows }) => rows[0] ? parseAlbumFromDb(rows[0]) : undefined)
, 'getAlbum'); , 'getAlbumFromSlug');
export const deleteAlbum = (id: string) => export const deleteAlbum = (id: string) =>
safelyQuery(() => sql` safelyQuery(() => sql`
@ -90,7 +90,7 @@ export const getAlbumsWithMeta = () =>
count: parseInt(count, 10), count: parseInt(count, 10),
lastModified: album.updated_at as Date, lastModified: album.updated_at as Date,
}))) })))
, 'getAlbumsWithPhotoCounts'); , 'getAlbumsWithMeta');
export const clearPhotoAlbumIds = (photoId: string) => export const clearPhotoAlbumIds = (photoId: string) =>
safelyQuery(() => sql` safelyQuery(() => sql`
@ -107,7 +107,8 @@ export const addPhotoAlbumIds = (photoIds: string[], albumIds: string[]) => {
INSERT INTO album_photo (album_id, photo_id) INSERT INTO album_photo (album_id, photo_id)
${valueString} ${valueString}
ON CONFLICT (album_id, photo_id) DO NOTHING ON CONFLICT (album_id, photo_id) DO NOTHING
`, values), 'updateAlbumPhoto'); `, values)
, 'addPhotoAlbumIds');
} }
}; };

View File

@ -39,6 +39,7 @@ import {
PREFIX_ALBUM, PREFIX_ALBUM,
} from '@/app/path'; } from '@/app/path';
import { createLensKey } from '@/lens'; import { createLensKey } from '@/lens';
import { getAlbumsWithMeta, getAlbumTitlesForPhoto } from '@/album/query';
// Table key // Table key
export const KEY_PHOTOS = 'photos'; export const KEY_PHOTOS = 'photos';
@ -223,6 +224,18 @@ export const getPhotoCached = (...args: Parameters<typeof getPhoto>) =>
getPhoto, getPhoto,
[KEY_PHOTOS, KEY_PHOTO], [KEY_PHOTOS, KEY_PHOTO],
)(...args).then(photo => photo ? parseCachedPhotoDates(photo) : undefined); )(...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 = export const getUniqueTagsCached =
unstable_cache( unstable_cache(

View File

@ -54,5 +54,8 @@ export const convertUploadToPhoto = async ({
: copyFile(uploadUrl, fileName); : copyFile(uploadUrl, fileName);
} }
// Store optimized photos after original photo is copied/moved // 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;
}; };