Rebuild photo query engine, preferring priority order
This commit is contained in:
parent
4438d0e1ee
commit
32c6260a3b
@ -64,6 +64,7 @@ Installation
|
||||
|
||||
- `NEXT_PUBLIC_PRO_MODE = 1` enables higher quality image storage
|
||||
- `NEXT_PUBLIC_GEO_PRIVACY = 1` disables collection/display of location-based data
|
||||
- `NEXT_PUBLIC_IGNORE_PRIORITY_ORDER = 1` prevents `priority_order` field affecting photo order
|
||||
- `NEXT_PUBLIC_PUBLIC_API = 1` enables public API available at `/api`
|
||||
- `NEXT_PUBLIC_HIDE_REPO_LINK = 1` removes footer link to repo
|
||||
- `NEXT_PUBLIC_HIDE_FILM_SIMULATIONS = 1` prevents Fujifilm simulations showing up in `/grid` sidebar
|
||||
|
||||
1
src/cache/index.ts
vendored
1
src/cache/index.ts
vendored
@ -48,6 +48,7 @@ const getPhotosCacheKeyForOption = (
|
||||
// Primitive keys
|
||||
case 'sortBy':
|
||||
case 'limit':
|
||||
case 'offset':
|
||||
case 'tag':
|
||||
case 'simulation':
|
||||
case 'includeHidden': {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { sql } from '@vercel/postgres';
|
||||
import { db, sql } from '@vercel/postgres';
|
||||
import {
|
||||
PhotoDb,
|
||||
PhotoDbInsert,
|
||||
@ -11,6 +11,7 @@ import { Camera, Cameras, createCameraKey } from '@/camera';
|
||||
import { parameterize } from '@/utility/string';
|
||||
import { Tags } from '@/tag';
|
||||
import { FilmSimulation, FilmSimulations } from '@/simulation';
|
||||
import { PRIORITY_ORDER_ENABLED } from '@/site/config';
|
||||
|
||||
const PHOTO_DEFAULT_LIMIT = 100;
|
||||
|
||||
@ -151,109 +152,6 @@ export const sqlRenamePhotoTagGlobally = (tag: string, updatedTag: string) =>
|
||||
export const sqlDeletePhoto = (id: string) =>
|
||||
sql`DELETE FROM photos WHERE id=${id}`;
|
||||
|
||||
const sqlGetPhotos = (
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
offset = 0,
|
||||
) =>
|
||||
sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE hidden IS NOT TRUE
|
||||
ORDER BY taken_at DESC
|
||||
LIMIT ${limit} OFFSET ${offset}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosIncludingHidden = (
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
offset = 0,
|
||||
) =>
|
||||
sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ${limit} OFFSET ${offset}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosSortedByCreatedAt = (
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
offset = 0,
|
||||
) =>
|
||||
sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE hidden IS NOT TRUE
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ${limit} OFFSET ${offset}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosSortedByPriority = (
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
offset = 0,
|
||||
) =>
|
||||
sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE hidden IS NOT TRUE
|
||||
ORDER BY priority_order ASC, taken_at DESC
|
||||
LIMIT ${limit} OFFSET ${offset}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosByTag = (
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
tag: string,
|
||||
) =>
|
||||
sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE ${tag}=ANY(tags)
|
||||
AND hidden IS NOT TRUE
|
||||
ORDER BY taken_at DESC
|
||||
LIMIT ${limit}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosByCamera = async (
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
make: string,
|
||||
model: string,
|
||||
) => sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE
|
||||
LOWER(make)=${parameterize(make)} AND
|
||||
LOWER(REPLACE(model, ' ', '-'))=${parameterize(model)}
|
||||
ORDER BY taken_at DESC
|
||||
LIMIT ${limit}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosBySimulation = async (
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
simulation: FilmSimulation,
|
||||
) => sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE film_simulation=${simulation}
|
||||
AND hidden IS NOT TRUE
|
||||
ORDER BY taken_at DESC
|
||||
LIMIT ${limit}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosTakenAfterDateInclusive = (
|
||||
takenAt: Date,
|
||||
limit?: number,
|
||||
) =>
|
||||
sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE taken_at <= ${takenAt.toISOString()}
|
||||
AND hidden IS NOT TRUE
|
||||
ORDER BY taken_at DESC
|
||||
LIMIT ${limit}
|
||||
`;
|
||||
|
||||
const sqlGetPhotosTakenBeforeDate = (
|
||||
takenAt: Date,
|
||||
limit?: number,
|
||||
) =>
|
||||
sql<PhotoDb>`
|
||||
SELECT * FROM photos
|
||||
WHERE taken_at > ${takenAt.toISOString()}
|
||||
AND hidden IS NOT TRUE
|
||||
ORDER BY taken_at ASC
|
||||
LIMIT ${limit}
|
||||
`;
|
||||
|
||||
const sqlGetPhoto = (id: string) =>
|
||||
sql<PhotoDb>`SELECT * FROM photos WHERE id=${id} LIMIT 1`;
|
||||
|
||||
@ -367,6 +265,7 @@ const sqlGetUniqueFilmSimulations = async () => sql`
|
||||
export type GetPhotosOptions = {
|
||||
sortBy?: 'createdAt' | 'takenAt' | 'priority'
|
||||
limit?: number
|
||||
offset?: number
|
||||
tag?: string
|
||||
camera?: Camera
|
||||
simulation?: FilmSimulation
|
||||
@ -403,11 +302,11 @@ const safelyQueryPhotos = async <T>(callback: () => Promise<T>): Promise<T> => {
|
||||
return result;
|
||||
};
|
||||
|
||||
// PHOTOS
|
||||
export const getPhotos = async (options: GetPhotosOptions = {}) => {
|
||||
const {
|
||||
sortBy = 'takenAt',
|
||||
limit,
|
||||
sortBy = PRIORITY_ORDER_ENABLED ? 'priority' : 'takenAt',
|
||||
limit = PHOTO_DEFAULT_LIMIT,
|
||||
offset = 0,
|
||||
tag,
|
||||
camera,
|
||||
simulation,
|
||||
@ -416,30 +315,69 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
|
||||
includeHidden,
|
||||
} = options;
|
||||
|
||||
let getPhotosSql = () => sqlGetPhotos(limit);
|
||||
let sql = 'SELECT * FROM photos';
|
||||
|
||||
if (includeHidden) {
|
||||
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, 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);
|
||||
} else if (sortBy === 'priority') {
|
||||
getPhotosSql = () => sqlGetPhotosSortedByPriority(limit);
|
||||
// WHERE
|
||||
let wheres = [] as string[];
|
||||
let values = [] as (string | number)[];
|
||||
let valueNumber = 1;
|
||||
if (!includeHidden) {
|
||||
wheres.push('hidden IS NOT TRUE');
|
||||
}
|
||||
if (takenBefore) {
|
||||
wheres.push(`taken_at > $${valueNumber++}`);
|
||||
values.push(takenBefore.toISOString());
|
||||
}
|
||||
if (takenAfterInclusive) {
|
||||
wheres.push(`taken_at <= $${valueNumber++}`);
|
||||
values.push(takenAfterInclusive.toISOString());
|
||||
}
|
||||
if (tag) {
|
||||
wheres.push(`$${valueNumber++}=ANY(tags)`);
|
||||
values.push(tag);
|
||||
}
|
||||
if (camera) {
|
||||
wheres.push(`LOWER(make)=$${valueNumber++}`);
|
||||
wheres.push(`LOWER(REPLACE(model, ' ', '-'))=$${valueNumber++}`);
|
||||
values.push(parameterize(camera.make));
|
||||
values.push(parameterize(camera.model));
|
||||
}
|
||||
if (simulation) {
|
||||
wheres.push(`film_simulation=$${valueNumber++}`);
|
||||
values.push(simulation);
|
||||
}
|
||||
if (wheres.length > 0) {
|
||||
sql += ` WHERE ${wheres.join(' AND ')}`;
|
||||
}
|
||||
|
||||
return safelyQueryPhotos(getPhotosSql)
|
||||
// ORDER BY
|
||||
switch (sortBy) {
|
||||
case 'createdAt':
|
||||
sql += ' ORDER BY created_at DESC';
|
||||
break;
|
||||
case 'takenAt':
|
||||
sql += ' ORDER BY taken_at DESC';
|
||||
break;
|
||||
case 'priority':
|
||||
sql += ' ORDER BY priority_order ASC, taken_at DESC';
|
||||
break;
|
||||
}
|
||||
|
||||
// LIMIT + OFFSET
|
||||
sql += ` LIMIT $${valueNumber++} OFFSET $${valueNumber++}`;
|
||||
values.push(limit, offset);
|
||||
|
||||
const client = await db.connect();
|
||||
|
||||
console.log({
|
||||
sql,
|
||||
values,
|
||||
});
|
||||
|
||||
return safelyQueryPhotos(() => client.query(sql, values))
|
||||
.then(({ rows }) => rows.map(parsePhotoFromDb));
|
||||
};
|
||||
|
||||
export const getPhoto = async (id: string): Promise<Photo | undefined> => {
|
||||
// Check for photo id forwarding
|
||||
// and convert short ids to uuids
|
||||
|
||||
@ -33,6 +33,7 @@ export default function SiteChecklistClient({
|
||||
showFilmSimulations,
|
||||
isProModeEnabled,
|
||||
isGeoPrivacyEnabled,
|
||||
isPriorityOrderEnabled,
|
||||
isPublicApiEnabled,
|
||||
isOgTextBottomAligned,
|
||||
showRefreshButton,
|
||||
@ -256,6 +257,16 @@ export default function SiteChecklistClient({
|
||||
collection/display of location-based data
|
||||
{renderEnvVars(['NEXT_PUBLIC_GEO_PRIVACY'])}
|
||||
</ChecklistRow>
|
||||
<ChecklistRow
|
||||
title="Priority Order"
|
||||
status={isPriorityOrderEnabled}
|
||||
isPending={isPendingPage}
|
||||
optional
|
||||
>
|
||||
Set environment variable to {'"1"'} to prevent
|
||||
priority order photo field affecting photo order
|
||||
{renderEnvVars(['NEXT_PUBLIC_IGNORE_PRIORITY_ORDER'])}
|
||||
</ChecklistRow>
|
||||
<ChecklistRow
|
||||
title="Public API"
|
||||
status={isPublicApiEnabled}
|
||||
|
||||
@ -49,6 +49,8 @@ export const HAS_AWS_S3_STORAGE =
|
||||
|
||||
export const PRO_MODE_ENABLED = process.env.NEXT_PUBLIC_PRO_MODE === '1';
|
||||
export const GEO_PRIVACY_ENABLED = process.env.NEXT_PUBLIC_GEO_PRIVACY === '1';
|
||||
export const PRIORITY_ORDER_ENABLED =
|
||||
process.env.NEXT_PUBLIC_IGNORE_PRIORITY_ORDER !== '1';
|
||||
export const PUBLIC_API_ENABLED = process.env.NEXT_PUBLIC_PUBLIC_API === '1';
|
||||
export const SHOW_REPO_LINK = process.env.NEXT_PUBLIC_HIDE_REPO_LINK !== '1';
|
||||
export const SHOW_FILM_SIMULATIONS =
|
||||
@ -77,6 +79,7 @@ export const CONFIG_CHECKLIST_STATUS = {
|
||||
showFilmSimulations: SHOW_FILM_SIMULATIONS,
|
||||
isProModeEnabled: PRO_MODE_ENABLED,
|
||||
isGeoPrivacyEnabled: GEO_PRIVACY_ENABLED,
|
||||
isPriorityOrderEnabled: PRIORITY_ORDER_ENABLED,
|
||||
isPublicApiEnabled: PUBLIC_API_ENABLED,
|
||||
isOgTextBottomAligned: OG_TEXT_BOTTOM_ALIGNMENT,
|
||||
gridAspectRatio: GRID_ASPECT_RATIO,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user