Finalize photo near id query for photo thumbnails
This commit is contained in:
parent
996339e4ac
commit
fa998b6dc2
@ -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
35
src/cache/index.ts
vendored
@ -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,
|
||||
|
||||
@ -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));
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user