Finalize photo near id query for photo thumbnails

This commit is contained in:
Sam Becker 2023-12-24 15:21:58 -05:00
parent 996339e4ac
commit fa998b6dc2
3 changed files with 60 additions and 58 deletions

View File

@ -11,8 +11,7 @@ import {
absolutePathForPhotoImage,
} from '@/site/paths';
import PhotoDetailPage from '@/photo/PhotoDetailPage';
import { getPhotoCached, getPhotosCached } from '@/cache';
import { PRIORITY_ORDER_ENABLED } from '@/site/config';
import { getPhotoCached, getPhotosNearIdCached } from '@/cache';
interface PhotoProps {
params: { photoId: string }
@ -51,38 +50,24 @@ export async function generateMetadata({
export default async function PhotoPage({
params: { photoId },
children,
}:
PhotoProps & { children: React.ReactNode }) {
const photo = await getPhotoCached(photoId);
}: PhotoProps & { children: React.ReactNode }) {
const photos = await getPhotosNearIdCached(
photoId,
GRID_THUMBNAILS_TO_SHOW_MAX + 2,
);
const photo = photos.find(p => p.id === photoId);
if (!photo) { redirect(PATH_ROOT); }
const [
photosBefore,
photosAfter,
] = await Promise.all([
getPhotosCached({
...(PRIORITY_ORDER_ENABLED && photo.priorityOrder !== null)
? { beforePriorityOrder: photo.priorityOrder }
: { takenBefore: photo.takenAt },
limit: 1,
}),
getPhotosCached({
...(PRIORITY_ORDER_ENABLED && photo.priorityOrder !== null)
? { afterPriorityOrderInclusive: photo.priorityOrder }
: { takenAfterInclusive: photo.takenAt },
limit: GRID_THUMBNAILS_TO_SHOW_MAX + 1,
}),
]);
const photos = photosBefore.concat(photosAfter);
const index = photos.findIndex(p => p.id === photoId);
return <>
{children}
<PhotoDetailPage
photo={photo}
photos={photos}
photosGrid={photosAfter.slice(1)}
photosGrid={photos.slice(index === 0 ? 1 : 2)}
/>
</>;
}

35
src/cache/index.ts vendored
View File

@ -21,6 +21,7 @@ import {
getPhotosFilmSimulationDateRange,
getPhotosFilmSimulationCount,
getPhotosDateRange,
getPhotosNearId,
} from '@/services/vercel-postgres';
import { parseCachedPhotoDates, parseCachedPhotosDates } from '@/photo';
import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob';
@ -45,29 +46,20 @@ const getPhotosCacheKeyForOption = (
option: keyof GetPhotosOptions,
): string | null => {
switch (option) {
// Primitive keys
case 'sortBy':
case 'limit':
case 'offset':
case 'tag':
case 'simulation':
case 'beforePriorityOrder':
case 'afterPriorityOrderInclusive':
case 'includeHidden': {
const value = options[option];
return value !== undefined ? `${option}-${value}` : null;
}
// Date keys
case 'takenBefore':
case 'takenAfterInclusive': {
const value = options[option];
return value ? `${option}-${value.toISOString()}` : null;
}
// Complex keys
case 'camera': {
const value = options[option];
return value ? `${option}-${createCameraKey(value)}` : null;
}
case 'takenBefore':
case 'takenAfterInclusive': {
const value = options[option];
return value ? `${option}-${value.toISOString()}` : null;
}
// Primitive keys
default:
const value = options[option];
return value !== undefined ? `${option}-${value}` : null;
}
};
@ -122,6 +114,13 @@ export const getPhotosCached = (
[KEY_PHOTOS, ...getPhotosCacheKeys(...args)],
)(...args).then(parseCachedPhotosDates);
export const getPhotosNearIdCached = (
...args: Parameters<typeof getPhotosNearId>
) => unstable_cache(
getPhotosNearId,
[KEY_PHOTOS],
)(...args).then(parseCachedPhotosDates);
export const getPhotosDateRangeCached =
unstable_cache(
getPhotosDateRange,

View File

@ -271,8 +271,6 @@ export type GetPhotosOptions = {
simulation?: FilmSimulation
takenBefore?: Date
takenAfterInclusive?: Date
beforePriorityOrder?: number
afterPriorityOrderInclusive?: number
includeHidden?: boolean
}
@ -314,8 +312,6 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
simulation,
takenBefore,
takenAfterInclusive,
beforePriorityOrder,
afterPriorityOrderInclusive,
includeHidden,
} = options;
@ -350,15 +346,6 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
wheres.push(`film_simulation=$${valueIndex++}`);
values.push(simulation);
}
if (beforePriorityOrder !== undefined) {
wheres.push(`priority_order < $${valueIndex++}`);
values.push(beforePriorityOrder);
}
if (afterPriorityOrderInclusive !== undefined) {
// eslint-disable-next-line max-len
wheres.push(`priority_order >= $${valueIndex++} OR priority_order IS NULL`);
values.push(afterPriorityOrderInclusive);
}
if (wheres.length > 0) {
sql.push(`WHERE ${wheres.join(' AND ')}`);
}
@ -380,9 +367,40 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
sql.push(`LIMIT $${valueIndex++} OFFSET $${valueIndex++}`);
values.push(limit, offset);
const client = await db.connect();
return safelyQueryPhotos(async () => {
const client = await db.connect();
return client.query(sql.join(' '), values);
})
.then(({ rows }) => rows.map(parsePhotoFromDb));
};
return safelyQueryPhotos(() => client.query(sql.join(' '), values))
export const getPhotosNearId = async (
id: string,
limit: number,
) => {
const orderBy = PRIORITY_ORDER_ENABLED
? 'ORDER BY priority_order ASC, taken_at DESC'
: 'ORDER BY taken_at DESC';
return safelyQueryPhotos(async () => {
const client = await db.connect();
return client.query(
`
WITH twi AS (
SELECT *, row_number()
OVER (${orderBy}) as row_number
FROM photos
WHERE hidden IS NOT TRUE
),
current AS (SELECT row_number FROM twi WHERE id = $1)
SELECT twi.*
FROM twi, current
WHERE twi.row_number >= current.row_number - 1
LIMIT $2
`,
[id, limit]
);
})
.then(({ rows }) => rows.map(parsePhotoFromDb));
};