Files
website/layers/diary/server/utils/review.ts
T
2026-09-30 19:15:57 +02:00

76 lines
2.4 KiB
TypeScript

import type { H3Event } from 'h3'
interface LookupValue {
value: string | null
}
// title, date and author_or_director are lookups through the `books` link
export interface ReviewRow {
id: number
books: LookupValue[]
title: LookupValue[]
date: LookupValue[]
author_or_director: LookupValue[]
review: string | null
medium: SelectOption | null
}
interface SelectOption {
id: number
value: string
}
interface Field {
name: string
select_options?: SelectOption[]
link_row_table_id?: number
}
const FIELD_CACHE_MS = 10 * 60_000
let reviewFields: { fields: Field[], fetchedAt: number } | null = null
async function fields(event: H3Event): Promise<Field[]> {
if (!reviewFields || Date.now() - reviewFields.fetchedAt > FIELD_CACHE_MS) {
reviewFields = { fields: await listFields<Field>(event, diaryTable(event, 'reviews')), fetchedAt: Date.now() }
}
return reviewFields.fields
}
function toMedium(value: string | undefined): Medium | null {
return MEDIUM_KEYS.find(medium => MEDIUMS[medium].label === value) ?? null
}
export function lookupValues(values: LookupValue[] | null | undefined): string[] {
return (values ?? []).map(({ value }) => value?.trim()).filter((value): value is string => !!value)
}
export function toReview(row: ReviewRow): Review {
return {
id: row.id,
date: lookupValues(row.date)[0] ?? '',
title: lookupValues(row.title).join(' / ') || lookupValues(row.books).join(' / '),
author: lookupValues(row.author_or_director).join(', ') || null,
text: (row.review ?? '').replace(/&nbsp;/g, ' ').trim(),
medium: toMedium(row.medium?.value)
}
}
export async function mediumOptionId(event: H3Event, medium: Medium): Promise<number> {
const options = (await fields(event)).find(field => field.name === 'medium')?.select_options ?? []
const id = options.find(option => toMedium(option.value) === medium)?.id
if (!id) {
throw createError({ statusCode: 500, statusMessage: `The medium field has no "${MEDIUMS[medium].label}" option` })
}
return id
}
/** The books table, taken from the reviews table's `books` link field. */
export async function booksTableId(event: H3Event): Promise<string> {
const id = (await fields(event)).find(field => field.name === 'books')?.link_row_table_id
if (!id) {
throw createError({ statusCode: 500, statusMessage: 'The reviews table has no "books" link field' })
}
return String(id)
}