From bf5bb1b83a47dd4a55db109ed21f9d9ec43b8b7f Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sun, 5 Nov 2023 20:37:00 -0600 Subject: [PATCH] Add full film simulation postgres queries --- src/cache/index.ts | 47 +++++++++++++++++++++++++++++------- src/services/postgres.ts | 52 +++++++++++++++++++++++++++++++++------- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/cache/index.ts b/src/cache/index.ts index 45e6bb41..2da06f8c 100644 --- a/src/cache/index.ts +++ b/src/cache/index.ts @@ -13,12 +13,15 @@ import { getPhotosCameraDateRange, getUniqueTagsHidden, getUniqueFilmSimulations, + getPhotosFilmSimulationDateRange, + getPhotosFilmSimulationCount, } from '@/services/postgres'; import { parseCachedPhotosDates, parseCachedPhotoDates } from '@/photo'; import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob'; import type { Session } from 'next-auth'; import { Camera, createCameraKey } from '@/camera'; import { PATHS_ADMIN, PATHS_TO_CACHE } from '@/site/paths'; +import { FujifilmSimulation } from '@/vendors/fujifilm'; const KEY_PHOTOS = 'photos'; const KEY_PHOTOS_COUNT = `${KEY_PHOTOS}-count`; @@ -27,8 +30,6 @@ const KEY_TAGS = 'tags'; const KEY_CAMERAS = 'cameras'; const KEY_FILM_SIMULATIONS = 'film-simulations'; const KEY_BLOB = 'blob'; -// Temporary key to clear caches on forked blogs -const KEY_NEW_QUERY = 'new-query'; // eslint-disable-next-line max-len const getPhotosCacheKeyForOption = ( @@ -39,8 +40,8 @@ const getPhotosCacheKeyForOption = ( // Primitive keys case 'sortBy': case 'limit': - case 'offset': case 'tag': + case 'simulation': case 'includeHidden': { const value = options[option]; return value ? `${option}-${value}` : null; @@ -81,12 +82,18 @@ const getPhotoTagCountKey = (tag: string) => const getPhotoCameraCountKey = (camera: Camera) => `${KEY_PHOTOS_COUNT}-${KEY_CAMERAS}-${createCameraKey(camera)}`; +const getPhotoFilmSimulationCountKey = (simulation: FujifilmSimulation) => + `${KEY_PHOTOS_COUNT}-${KEY_FILM_SIMULATIONS}-${simulation}`; + const getPhotoTagDateRangeKey = (tag: string) => `${KEY_PHOTOS_DATE_RANGE}-${KEY_TAGS}-${tag}`; const getPhotoCameraDateRangeKey = (camera: Camera) => `${KEY_PHOTOS_DATE_RANGE}-${KEY_CAMERAS}-${createCameraKey(camera)}`; +const getPhotoFilmSimulationDateRangeKey = (simulation: FujifilmSimulation) => + `${KEY_PHOTOS_DATE_RANGE}-${KEY_FILM_SIMULATIONS}-${simulation}`; + export const revalidatePhotosKey = () => revalidateTag(KEY_PHOTOS); @@ -96,6 +103,9 @@ export const revalidateTagsKey = () => export const revalidateCamerasKey = () => revalidateTag(KEY_CAMERAS); +export const revalidateFilmSimulationsKey = () => + revalidateTag(KEY_FILM_SIMULATIONS); + export const revalidateBlobKey = () => revalidateTag(KEY_BLOB); @@ -108,6 +118,7 @@ export const revalidateAllKeys = () => { revalidatePhotosAndBlobKeys(); revalidateTagsKey(); revalidateCamerasKey(); + revalidateFilmSimulationsKey(); }; 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 export const getPhotosTagDateRangeCached: typeof getPhotosTagDateRange = (...args) => 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) => unstable_cache( () => getPhoto(...args), @@ -190,8 +219,8 @@ export const getPhotoCached: typeof getPhoto = (...args) => export const getUniqueTagsCached: typeof getUniqueTags = (...args) => unstable_cache( () => getUniqueTags(...args), - [KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], { - tags: [KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], + [KEY_PHOTOS, KEY_TAGS], { + tags: [KEY_PHOTOS, KEY_TAGS], } )(); @@ -199,16 +228,16 @@ export const getUniqueTagsCached: typeof getUniqueTags = (...args) => export const getUniqueTagsHiddenCached: typeof getUniqueTagsHidden = (...args) => unstable_cache( () => getUniqueTagsHidden(...args), - [KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], { - tags: [KEY_PHOTOS, KEY_TAGS, KEY_NEW_QUERY], + [KEY_PHOTOS, KEY_TAGS], { + tags: [KEY_PHOTOS, KEY_TAGS], } )(); export const getUniqueCamerasCached: typeof getUniqueCameras = (...args) => unstable_cache( () => getUniqueCameras(...args), - [KEY_PHOTOS, KEY_CAMERAS, KEY_NEW_QUERY], { - tags: [KEY_PHOTOS, KEY_CAMERAS, KEY_NEW_QUERY], + [KEY_PHOTOS, KEY_CAMERAS], { + tags: [KEY_PHOTOS, KEY_CAMERAS], } )(); diff --git a/src/services/postgres.ts b/src/services/postgres.ts index ad409d50..17d430aa 100644 --- a/src/services/postgres.ts +++ b/src/services/postgres.ts @@ -196,7 +196,6 @@ const sqlGetPhotosSortedByPriority = ( const sqlGetPhotosByTag = ( limit = PHOTO_DEFAULT_LIMIT, - offset = 0, tag: string, ) => sql` @@ -204,7 +203,7 @@ const sqlGetPhotosByTag = ( WHERE ${tag}=ANY(tags) AND hidden IS NOT TRUE ORDER BY taken_at ASC - LIMIT ${limit} OFFSET ${offset} + LIMIT ${limit} `; const sqlGetPhotosByCamera = async ( @@ -220,6 +219,17 @@ const sqlGetPhotosByCamera = async ( LIMIT ${limit} `; +const sqlGetPhotosBySimulation = async ( + limit = PHOTO_DEFAULT_LIMIT, + simulation: FujifilmSimulation, +) => sql` + SELECT * FROM photos + WHERE film_simulation=${simulation} + AND hidden IS NOT TRUE + ORDER BY taken_at ASC + LIMIT ${limit} +`; + const sqlGetPhotosTakenAfterDateInclusive = ( takenAt: Date, limit?: number, @@ -270,6 +280,14 @@ const sqlGetPhotosCameraCount = async (camera: Camera) => sql` hidden IS NOT TRUE `.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` SELECT MIN(taken_at_naive) as start, MAX(taken_at_naive) as end FROM photos @@ -286,6 +304,15 @@ const sqlGetPhotosCameraDateRange = async (camera: Camera) => sql` hidden IS NOT TRUE `.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` SELECT DISTINCT unnest(tags) as tag, COUNT(*) FROM photos @@ -334,9 +361,9 @@ const sqlGetUniqueFilmSimulations = async () => sql` export type GetPhotosOptions = { sortBy?: 'createdAt' | 'takenAt' | 'priority' limit?: number - offset?: number tag?: string camera?: Camera + simulation?: FujifilmSimulation takenBefore?: Date takenAfterInclusive?: Date includeHidden?: boolean @@ -375,31 +402,33 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => { const { sortBy = 'takenAt', limit, - offset, tag, camera, + simulation, takenBefore, takenAfterInclusive, includeHidden, } = options; - let getPhotosSql = () => sqlGetPhotos(limit, offset); + let getPhotosSql = () => sqlGetPhotos(limit); if (includeHidden) { - getPhotosSql = () => sqlGetPhotosIncludingHidden(limit, offset); + getPhotosSql = () => sqlGetPhotosIncludingHidden(limit); } else if (takenBefore) { getPhotosSql = () => sqlGetPhotosTakenBeforeDate(takenBefore, limit); } else if (takenAfterInclusive) { // eslint-disable-next-line max-len getPhotosSql = () => sqlGetPhotosTakenAfterDateInclusive(takenAfterInclusive, limit); } else if (tag) { - getPhotosSql = () => sqlGetPhotosByTag(limit, offset, tag); + getPhotosSql = () => sqlGetPhotosByTag(limit, tag); } else if (camera) { getPhotosSql = () => sqlGetPhotosByCamera(limit, camera.make, camera.model); + } else if (simulation) { + getPhotosSql = () => sqlGetPhotosBySimulation(limit, simulation); } else if (sortBy === 'createdAt') { - getPhotosSql = () => sqlGetPhotosSortedByCreatedAt(limit, offset); + getPhotosSql = () => sqlGetPhotosSortedByCreatedAt(limit); } else if (sortBy === 'priority') { - getPhotosSql = () => sqlGetPhotosSortedByPriority(limit, offset); + getPhotosSql = () => sqlGetPhotosSortedByPriority(limit); } return safelyQueryPhotos(getPhotosSql) @@ -439,3 +468,8 @@ export const getPhotosCameraCount = (camera: Camera) => // FILM SIMULATIONS export const getUniqueFilmSimulations = () => safelyQueryPhotos(sqlGetUniqueFilmSimulations); +export const getPhotosFilmSimulationDateRange = + (simulation: FujifilmSimulation) => safelyQueryPhotos(() => + sqlGetPhotosFilmSimulationDateRange(simulation)); +export const getPhotosFilmSimulationCount = (simulation: FujifilmSimulation) => + safelyQueryPhotos(() => sqlGetPhotosFilmSimulationCount(simulation));