Add full film simulation postgres queries

This commit is contained in:
Sam Becker 2023-11-05 20:37:00 -06:00
parent 503ef6ca7c
commit bf5bb1b83a
2 changed files with 81 additions and 18 deletions

47
src/cache/index.ts vendored
View File

@ -13,12 +13,15 @@ import {
getPhotosCameraDateRange, getPhotosCameraDateRange,
getUniqueTagsHidden, getUniqueTagsHidden,
getUniqueFilmSimulations, getUniqueFilmSimulations,
getPhotosFilmSimulationDateRange,
getPhotosFilmSimulationCount,
} from '@/services/postgres'; } from '@/services/postgres';
import { parseCachedPhotosDates, parseCachedPhotoDates } from '@/photo'; import { parseCachedPhotosDates, parseCachedPhotoDates } from '@/photo';
import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob'; import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob';
import type { Session } from 'next-auth'; import type { Session } from 'next-auth';
import { Camera, createCameraKey } from '@/camera'; import { Camera, createCameraKey } from '@/camera';
import { PATHS_ADMIN, PATHS_TO_CACHE } from '@/site/paths'; import { PATHS_ADMIN, PATHS_TO_CACHE } from '@/site/paths';
import { FujifilmSimulation } from '@/vendors/fujifilm';
const KEY_PHOTOS = 'photos'; const KEY_PHOTOS = 'photos';
const KEY_PHOTOS_COUNT = `${KEY_PHOTOS}-count`; const KEY_PHOTOS_COUNT = `${KEY_PHOTOS}-count`;
@ -27,8 +30,6 @@ const KEY_TAGS = 'tags';
const KEY_CAMERAS = 'cameras'; const KEY_CAMERAS = 'cameras';
const KEY_FILM_SIMULATIONS = 'film-simulations'; const KEY_FILM_SIMULATIONS = 'film-simulations';
const KEY_BLOB = 'blob'; const KEY_BLOB = 'blob';
// Temporary key to clear caches on forked blogs
const KEY_NEW_QUERY = 'new-query';
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const getPhotosCacheKeyForOption = ( const getPhotosCacheKeyForOption = (
@ -39,8 +40,8 @@ const getPhotosCacheKeyForOption = (
// Primitive keys // Primitive keys
case 'sortBy': case 'sortBy':
case 'limit': case 'limit':
case 'offset':
case 'tag': case 'tag':
case 'simulation':
case 'includeHidden': { case 'includeHidden': {
const value = options[option]; const value = options[option];
return value ? `${option}-${value}` : null; return value ? `${option}-${value}` : null;
@ -81,12 +82,18 @@ const getPhotoTagCountKey = (tag: string) =>
const getPhotoCameraCountKey = (camera: Camera) => const getPhotoCameraCountKey = (camera: Camera) =>
`${KEY_PHOTOS_COUNT}-${KEY_CAMERAS}-${createCameraKey(camera)}`; `${KEY_PHOTOS_COUNT}-${KEY_CAMERAS}-${createCameraKey(camera)}`;
const getPhotoFilmSimulationCountKey = (simulation: FujifilmSimulation) =>
`${KEY_PHOTOS_COUNT}-${KEY_FILM_SIMULATIONS}-${simulation}`;
const getPhotoTagDateRangeKey = (tag: string) => const getPhotoTagDateRangeKey = (tag: string) =>
`${KEY_PHOTOS_DATE_RANGE}-${KEY_TAGS}-${tag}`; `${KEY_PHOTOS_DATE_RANGE}-${KEY_TAGS}-${tag}`;
const getPhotoCameraDateRangeKey = (camera: Camera) => const getPhotoCameraDateRangeKey = (camera: Camera) =>
`${KEY_PHOTOS_DATE_RANGE}-${KEY_CAMERAS}-${createCameraKey(camera)}`; `${KEY_PHOTOS_DATE_RANGE}-${KEY_CAMERAS}-${createCameraKey(camera)}`;
const getPhotoFilmSimulationDateRangeKey = (simulation: FujifilmSimulation) =>
`${KEY_PHOTOS_DATE_RANGE}-${KEY_FILM_SIMULATIONS}-${simulation}`;
export const revalidatePhotosKey = () => export const revalidatePhotosKey = () =>
revalidateTag(KEY_PHOTOS); revalidateTag(KEY_PHOTOS);
@ -96,6 +103,9 @@ export const revalidateTagsKey = () =>
export const revalidateCamerasKey = () => export const revalidateCamerasKey = () =>
revalidateTag(KEY_CAMERAS); revalidateTag(KEY_CAMERAS);
export const revalidateFilmSimulationsKey = () =>
revalidateTag(KEY_FILM_SIMULATIONS);
export const revalidateBlobKey = () => export const revalidateBlobKey = () =>
revalidateTag(KEY_BLOB); revalidateTag(KEY_BLOB);
@ -108,6 +118,7 @@ export const revalidateAllKeys = () => {
revalidatePhotosAndBlobKeys(); revalidatePhotosAndBlobKeys();
revalidateTagsKey(); revalidateTagsKey();
revalidateCamerasKey(); revalidateCamerasKey();
revalidateFilmSimulationsKey();
}; };
export const revalidateAllKeysAndPaths = () => { export const revalidateAllKeysAndPaths = () => {
@ -161,6 +172,15 @@ export const getPhotosCameraCountCached: typeof getPhotosCameraCount = (...args)
} }
)(); )();
// eslint-disable-next-line max-len
export const getPhotosFilmSimulationCountCached: typeof getPhotosFilmSimulationCount = (...args) =>
unstable_cache(
() => getPhotosFilmSimulationCount(...args),
[KEY_PHOTOS, getPhotoFilmSimulationCountKey(...args)], {
tags: [KEY_PHOTOS, getPhotoFilmSimulationCountKey(...args)],
}
)();
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
export const getPhotosTagDateRangeCached: typeof getPhotosTagDateRange = (...args) => export const getPhotosTagDateRangeCached: typeof getPhotosTagDateRange = (...args) =>
unstable_cache( unstable_cache(
@ -179,6 +199,15 @@ export const getPhotosCameraDateRangeCached: typeof getPhotosCameraDateRange = (
} }
)(); )();
// eslint-disable-next-line max-len
export const getPhotosFilmSimulationDateRangeCached: typeof getPhotosFilmSimulationDateRange = (...args) =>
unstable_cache(
() => getPhotosFilmSimulationDateRange(...args),
[KEY_PHOTOS, getPhotoFilmSimulationDateRangeKey(...args)], {
tags: [KEY_PHOTOS, getPhotoFilmSimulationDateRangeKey(...args)],
}
)();
export const getPhotoCached: typeof getPhoto = (...args) => export const getPhotoCached: typeof getPhoto = (...args) =>
unstable_cache( unstable_cache(
() => getPhoto(...args), () => getPhoto(...args),
@ -190,8 +219,8 @@ export const getPhotoCached: typeof getPhoto = (...args) =>
export const getUniqueTagsCached: typeof getUniqueTags = (...args) => export const getUniqueTagsCached: typeof getUniqueTags = (...args) =>
unstable_cache( unstable_cache(
() => getUniqueTags(...args), () => getUniqueTags(...args),
[KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], { [KEY_PHOTOS, KEY_TAGS], {
tags: [KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], tags: [KEY_PHOTOS, KEY_TAGS],
} }
)(); )();
@ -199,16 +228,16 @@ export const getUniqueTagsCached: typeof getUniqueTags = (...args) =>
export const getUniqueTagsHiddenCached: typeof getUniqueTagsHidden = (...args) => export const getUniqueTagsHiddenCached: typeof getUniqueTagsHidden = (...args) =>
unstable_cache( unstable_cache(
() => getUniqueTagsHidden(...args), () => getUniqueTagsHidden(...args),
[KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], { [KEY_PHOTOS, KEY_TAGS], {
tags: [KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], tags: [KEY_PHOTOS, KEY_TAGS],
} }
)(); )();
export const getUniqueCamerasCached: typeof getUniqueCameras = (...args) => export const getUniqueCamerasCached: typeof getUniqueCameras = (...args) =>
unstable_cache( unstable_cache(
() => getUniqueCameras(...args), () => getUniqueCameras(...args),
[KEY_PHOTOS, KEY_CAMERAS, KEY_NEW_QUERY], { [KEY_PHOTOS, KEY_CAMERAS], {
tags: [KEY_PHOTOS, KEY_CAMERAS, KEY_NEW_QUERY], tags: [KEY_PHOTOS, KEY_CAMERAS],
} }
)(); )();

View File

@ -196,7 +196,6 @@ const sqlGetPhotosSortedByPriority = (
const sqlGetPhotosByTag = ( const sqlGetPhotosByTag = (
limit = PHOTO_DEFAULT_LIMIT, limit = PHOTO_DEFAULT_LIMIT,
offset = 0,
tag: string, tag: string,
) => ) =>
sql<PhotoDb>` sql<PhotoDb>`
@ -204,7 +203,7 @@ const sqlGetPhotosByTag = (
WHERE ${tag}=ANY(tags) WHERE ${tag}=ANY(tags)
AND hidden IS NOT TRUE AND hidden IS NOT TRUE
ORDER BY taken_at ASC ORDER BY taken_at ASC
LIMIT ${limit} OFFSET ${offset} LIMIT ${limit}
`; `;
const sqlGetPhotosByCamera = async ( const sqlGetPhotosByCamera = async (
@ -220,6 +219,17 @@ const sqlGetPhotosByCamera = async (
LIMIT ${limit} LIMIT ${limit}
`; `;
const sqlGetPhotosBySimulation = async (
limit = PHOTO_DEFAULT_LIMIT,
simulation: FujifilmSimulation,
) => sql<PhotoDb>`
SELECT * FROM photos
WHERE film_simulation=${simulation}
AND hidden IS NOT TRUE
ORDER BY taken_at ASC
LIMIT ${limit}
`;
const sqlGetPhotosTakenAfterDateInclusive = ( const sqlGetPhotosTakenAfterDateInclusive = (
takenAt: Date, takenAt: Date,
limit?: number, limit?: number,
@ -270,6 +280,14 @@ const sqlGetPhotosCameraCount = async (camera: Camera) => sql`
hidden IS NOT TRUE hidden IS NOT TRUE
`.then(({ rows }) => parseInt(rows[0].count, 10)); `.then(({ rows }) => parseInt(rows[0].count, 10));
const sqlGetPhotosFilmSimulationCount = async (
simulation: FujifilmSimulation,
) => sql`
SELECT COUNT(*) FROM photos
WHERE film_simulation=${simulation} AND
hidden IS NOT TRUE
`.then(({ rows }) => parseInt(rows[0].count, 10));
const sqlGetPhotosTagDateRange = async (tag: string) => sql` const sqlGetPhotosTagDateRange = async (tag: string) => sql`
SELECT MIN(taken_at_naive) as start, MAX(taken_at_naive) as end SELECT MIN(taken_at_naive) as start, MAX(taken_at_naive) as end
FROM photos FROM photos
@ -286,6 +304,15 @@ const sqlGetPhotosCameraDateRange = async (camera: Camera) => sql`
hidden IS NOT TRUE hidden IS NOT TRUE
`.then(({ rows }) => rows[0] as PhotoDateRange); `.then(({ rows }) => rows[0] as PhotoDateRange);
const sqlGetPhotosFilmSimulationDateRange = async (
simulation: FujifilmSimulation,
) => sql`
SELECT MIN(taken_at_naive) as start, MAX(taken_at_naive) as end
FROM photos
WHERE film_simulation=${simulation} AND
hidden IS NOT TRUE
`.then(({ rows }) => rows[0] as PhotoDateRange);
const sqlGetUniqueTags = async () => sql` const sqlGetUniqueTags = async () => sql`
SELECT DISTINCT unnest(tags) as tag, COUNT(*) SELECT DISTINCT unnest(tags) as tag, COUNT(*)
FROM photos FROM photos
@ -334,9 +361,9 @@ const sqlGetUniqueFilmSimulations = async () => sql`
export type GetPhotosOptions = { export type GetPhotosOptions = {
sortBy?: 'createdAt' | 'takenAt' | 'priority' sortBy?: 'createdAt' | 'takenAt' | 'priority'
limit?: number limit?: number
offset?: number
tag?: string tag?: string
camera?: Camera camera?: Camera
simulation?: FujifilmSimulation
takenBefore?: Date takenBefore?: Date
takenAfterInclusive?: Date takenAfterInclusive?: Date
includeHidden?: boolean includeHidden?: boolean
@ -375,31 +402,33 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
const { const {
sortBy = 'takenAt', sortBy = 'takenAt',
limit, limit,
offset,
tag, tag,
camera, camera,
simulation,
takenBefore, takenBefore,
takenAfterInclusive, takenAfterInclusive,
includeHidden, includeHidden,
} = options; } = options;
let getPhotosSql = () => sqlGetPhotos(limit, offset); let getPhotosSql = () => sqlGetPhotos(limit);
if (includeHidden) { if (includeHidden) {
getPhotosSql = () => sqlGetPhotosIncludingHidden(limit, offset); getPhotosSql = () => sqlGetPhotosIncludingHidden(limit);
} else if (takenBefore) { } else if (takenBefore) {
getPhotosSql = () => sqlGetPhotosTakenBeforeDate(takenBefore, limit); getPhotosSql = () => sqlGetPhotosTakenBeforeDate(takenBefore, limit);
} else if (takenAfterInclusive) { } else if (takenAfterInclusive) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
getPhotosSql = () => sqlGetPhotosTakenAfterDateInclusive(takenAfterInclusive, limit); getPhotosSql = () => sqlGetPhotosTakenAfterDateInclusive(takenAfterInclusive, limit);
} else if (tag) { } else if (tag) {
getPhotosSql = () => sqlGetPhotosByTag(limit, offset, tag); getPhotosSql = () => sqlGetPhotosByTag(limit, tag);
} else if (camera) { } else if (camera) {
getPhotosSql = () => sqlGetPhotosByCamera(limit, camera.make, camera.model); getPhotosSql = () => sqlGetPhotosByCamera(limit, camera.make, camera.model);
} else if (simulation) {
getPhotosSql = () => sqlGetPhotosBySimulation(limit, simulation);
} else if (sortBy === 'createdAt') { } else if (sortBy === 'createdAt') {
getPhotosSql = () => sqlGetPhotosSortedByCreatedAt(limit, offset); getPhotosSql = () => sqlGetPhotosSortedByCreatedAt(limit);
} else if (sortBy === 'priority') { } else if (sortBy === 'priority') {
getPhotosSql = () => sqlGetPhotosSortedByPriority(limit, offset); getPhotosSql = () => sqlGetPhotosSortedByPriority(limit);
} }
return safelyQueryPhotos(getPhotosSql) return safelyQueryPhotos(getPhotosSql)
@ -439,3 +468,8 @@ export const getPhotosCameraCount = (camera: Camera) =>
// FILM SIMULATIONS // FILM SIMULATIONS
export const getUniqueFilmSimulations = () => export const getUniqueFilmSimulations = () =>
safelyQueryPhotos(sqlGetUniqueFilmSimulations); safelyQueryPhotos(sqlGetUniqueFilmSimulations);
export const getPhotosFilmSimulationDateRange =
(simulation: FujifilmSimulation) => safelyQueryPhotos(() =>
sqlGetPhotosFilmSimulationDateRange(simulation));
export const getPhotosFilmSimulationCount = (simulation: FujifilmSimulation) =>
safelyQueryPhotos(() => sqlGetPhotosFilmSimulationCount(simulation));