Generalize nearId photo queries
This commit is contained in:
parent
8bfa078c9d
commit
dcfc04c842
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
132
src/photo/db.ts
132
src/photo/db.ts
@ -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
|
||||
|
||||
@ -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),
|
||||
]);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user