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 { if (!reviewFields || Date.now() - reviewFields.fetchedAt > FIELD_CACHE_MS) { reviewFields = { fields: await listFields(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(/ /g, ' ').trim(), medium: toMedium(row.medium?.value) } } export async function mediumOptionId(event: H3Event, medium: Medium): Promise { 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 { 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) }