Generalize nearId photo queries

This commit is contained in:
Sam Becker 2024-05-19 21:27:07 -05:00
parent 8bfa078c9d
commit dcfc04c842
5 changed files with 86 additions and 67 deletions

View File

@ -11,9 +11,13 @@ import {
absolutePathForPhotoImage,
} from '@/site/paths';
import PhotoDetailPage from '@/photo/PhotoDetailPage';
import { getPhotosNearIdCachedCached } from '@/photo/cache';
import { getPhotosNearIdCached } from '@/photo/cache';
import { IS_PRODUCTION, STATICALLY_OPTIMIZED_PAGES } from '@/site/config';
import { GENERATE_STATIC_PARAMS_LIMIT, getPhotoIds } from '@/photo/db';
import { cache } from 'react';
const getPhotosNearIdCachedCached = cache((photoId: string, limit: number) =>
getPhotosNearIdCached(photoId, { limit }));
export let generateStaticParams:
(() => Promise<{ photoId: string }[]>) | undefined = undefined;

View File

@ -21,7 +21,7 @@ import {
deleteStorageUrl,
} from '@/services/storage';
import {
getPhotosCachedCached,
getPhotosCached,
getPhotosTagHiddenMetaCached,
revalidateAdminPaths,
revalidateAllKeysAndPaths,
@ -219,8 +219,8 @@ export const getPhotosAction = async (options: GetPhotosOptions) =>
export const getPhotosCachedAction = async (options: GetPhotosOptions) =>
(options.hidden === 'include' || options.hidden === 'only')
? safelyRunAdminServerAction(() =>
getPhotosCachedCached(options))
: getPhotosCachedCached(options);
getPhotosCached (options))
: getPhotosCached(options);
// Public actions

View File

@ -35,7 +35,6 @@ import {
PREFIX_TAG,
pathForPhoto,
} from '@/site/paths';
import { cache } from 'react';
// Table key
const KEY_PHOTOS = 'photos';
@ -137,9 +136,8 @@ export const getPhotosCached = (
getPhotos,
[KEY_PHOTOS, ...getPhotosCacheKeys(...args)],
)(...args).then(parseCachedPhotosDates);
export const getPhotosCachedCached = cache(getPhotosCached);
const getPhotosNearIdCached = (
export const getPhotosNearIdCached = (
...args: Parameters<typeof getPhotosNearId>
) => unstable_cache(
getPhotosNearId,
@ -148,7 +146,6 @@ const getPhotosNearIdCached = (
photos: parseCachedPhotosDates(photos),
photo: photo ? parseCachedPhotoDates(photo) : undefined,
}));
export const getPhotosNearIdCachedCached = cache(getPhotosNearIdCached);
export const getPhotosDateRangeCached =
unstable_cache(

View File

@ -358,26 +358,20 @@ const safelyQueryPhotos = async <T>(
return result;
};
export const getPhotos = async (options: GetPhotosOptions = {}) => {
const getWheresFromOptions = (options: GetPhotosOptions) => {
const {
sortBy = PRIORITY_ORDER_ENABLED ? 'priority' : 'takenAt',
limit = PHOTO_DEFAULT_LIMIT,
offset = 0,
query: queryOption,
hidden = 'exclude',
takenBefore,
takenAfterInclusive,
query,
tag,
camera,
simulation,
takenBefore,
takenAfterInclusive,
hidden = 'exclude',
} = options;
let sql = ['SELECT * FROM photos'];
let values = [] as (string | number)[];
let valueIndex = 1;
// WHERE
let wheres = [] as string[];
const wheres = [] as string[];
const values = [] as (string | number)[];
let valuesIndex = 1;
switch (hidden) {
case 'exclude':
@ -388,35 +382,56 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
break;
}
if (takenBefore) {
wheres.push(`taken_at > $${valueIndex++}`);
wheres.push(`taken_at > $${valuesIndex++}`);
values.push(takenBefore.toISOString());
}
if (takenAfterInclusive) {
wheres.push(`taken_at <= $${valueIndex++}`);
wheres.push(`taken_at <= $${valuesIndex++}`);
values.push(takenAfterInclusive.toISOString());
}
if (queryOption) {
if (query) {
// eslint-disable-next-line max-len
wheres.push(`CONCAT(title, ' ', caption, ' ', semantic_description) ILIKE $${valueIndex++}`);
values.push(`%${queryOption.toLocaleLowerCase()}%`);
wheres.push(`CONCAT(title, ' ', caption, ' ', semantic_description) ILIKE $${valuesIndex++}`);
values.push(`%${query.toLocaleLowerCase()}%`);
}
if (tag) {
wheres.push(`$${valueIndex++}=ANY(tags)`);
wheres.push(`$${valuesIndex++}=ANY(tags)`);
values.push(tag);
}
if (camera) {
wheres.push(`LOWER(REPLACE(make, ' ', '-'))=$${valueIndex++}`);
wheres.push(`LOWER(REPLACE(model, ' ', '-'))=$${valueIndex++}`);
wheres.push(`LOWER(REPLACE(make, ' ', '-'))=$${valuesIndex++}`);
wheres.push(`LOWER(REPLACE(model, ' ', '-'))=$${valuesIndex++}`);
values.push(parameterize(camera.make, true));
values.push(parameterize(camera.model, true));
}
if (simulation) {
wheres.push(`film_simulation=$${valueIndex++}`);
wheres.push(`film_simulation=$${valuesIndex++}`);
values.push(simulation);
}
if (wheres.length > 0) {
sql.push(`WHERE ${wheres.join(' AND ')}`);
}
return {
wheres: wheres.length > 0
? `WHERE ${wheres.join(' AND ')}`
: '',
values,
lastValuesIndex: valuesIndex,
};
};
export const getPhotos = async (options: GetPhotosOptions = {}) => {
const {
sortBy = PRIORITY_ORDER_ENABLED ? 'priority' : 'takenAt',
limit = PHOTO_DEFAULT_LIMIT,
offset = 0,
} = options;
let sql = ['SELECT * FROM photos'];
const { wheres, values, lastValuesIndex } = getWheresFromOptions(options);
let valuesIndex = lastValuesIndex;
if (wheres) { sql.push(wheres); }
// ORDER BY
switch (sortBy) {
@ -432,7 +447,7 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
}
// LIMIT + OFFSET
sql.push(`LIMIT $${valueIndex++} OFFSET $${valueIndex++}`);
sql.push(`LIMIT $${valuesIndex++} OFFSET $${valuesIndex++}`);
values.push(limit, offset);
return safelyQueryPhotos(async () => {
@ -442,40 +457,43 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
};
export const getPhotosNearId = async (
id: string,
limit: number,
onlyHidden?: boolean,
) => {
photoId: string,
options: GetPhotosOptions,
) => safelyQueryPhotos(async () => {
const { limit } = options;
const orderBy = PRIORITY_ORDER_ENABLED
? 'ORDER BY priority_order ASC, taken_at DESC'
: 'ORDER BY taken_at DESC';
return safelyQueryPhotos(async () => {
return query(
`
WITH twi AS (
SELECT *, row_number()
OVER (${orderBy}) as row_number
FROM photos
WHERE hidden is ${onlyHidden ? 'TRUE' : '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]
);
}, `getPhotosNearId: ${id}`)
.then(({ rows }) => {
const photos = rows.map(parsePhotoFromDb);
return {
photos,
photo: photos.find(photo => photo.id === id),
};
});
};
const { wheres, values, lastValuesIndex } = getWheresFromOptions(options);
let valuesIndex = lastValuesIndex;
return query(
`
WITH twi AS (
SELECT *, row_number()
OVER (${orderBy}) as row_number
FROM photos
${wheres}
),
current AS (SELECT row_number FROM twi WHERE id = $${valuesIndex++})
SELECT twi.*
FROM twi, current
WHERE twi.row_number >= current.row_number - 1
LIMIT $${valuesIndex++}
`,
[...values, photoId, limit]
);
}, `getPhotosNearId: ${photoId}`)
.then(({ rows }) => {
const photos = rows.map(parsePhotoFromDb);
return {
photos,
photo: photos.find(photo => photo.id === photoId),
};
});
export const getPhotoIds = async ({ limit }: { limit?: number }) => {
return safelyQueryPhotos(() => limit

View File

@ -1,5 +1,5 @@
import {
getPhotosCachedCached,
getPhotosCached,
getPhotosTagMetaCached,
} from '@/photo/cache';
@ -11,7 +11,7 @@ export const getPhotosTagDataCached = ({
limit?: number,
}) =>
Promise.all([
getPhotosCachedCached({ tag, limit }),
getPhotosCached({ tag, limit }),
getPhotosTagMetaCached(tag),
]);