/** * The `chat_messages` table: its row type, its guard, and its mapper to the * API's {@link ChatMessage}. * * @module */ import type { SQLOutputValue } from "node:sqlite"; import type { ChatMessage } from "../../shared/chat.ts"; /** * A row of the `chat_messages` table, joined with its author and, when it is * a reply, the replied-to message and its author. */ export interface ChatMessageRow { /** The message's id. */ id: string; /** The author's id. */ user_id: string; /** The message, in Markdown. */ body: string; /** When the message was sent. */ created_at: string; /** When the message was last edited, if ever. */ updated_at: string | null; /** The author's name (joined). */ author_username: string; /** The author's avatar type, null without one (joined). */ author_avatar_mime: string | null; /** * The id of the message this replies to, kept even once that message is * deleted. */ reply_to_id: string | null; /** * The replied-to message's author (joined); null when there's no reply or it * was since deleted. */ reply_to_author: string | null; /** * The start of the replied-to message (joined); null when there's no reply or * it was since deleted. */ reply_to_body: string | null; /** Any other column the query selects. */ [key: string]: SQLOutputValue; } /** Checks whether `obj` is a {@link ChatMessageRow}. */ export function isChatMessageRow(obj: unknown): obj is ChatMessageRow { return !!obj && typeof obj === "object" && "id" in obj && typeof obj.id === "string" && "user_id" in obj && typeof obj.user_id === "string" && "body" in obj && typeof obj.body === "string" && "created_at" in obj && typeof obj.created_at === "string" && "updated_at" in obj && (typeof obj.updated_at === "string" || obj.updated_at === null) && "author_username" in obj && typeof obj.author_username === "string" && "author_avatar_mime" in obj && (typeof obj.author_avatar_mime === "string" || obj.author_avatar_mime === null) && "reply_to_id" in obj && (typeof obj.reply_to_id === "string" || obj.reply_to_id === null) && "reply_to_author" in obj && (typeof obj.reply_to_author === "string" || obj.reply_to_author === null) && "reply_to_body" in obj && (typeof obj.reply_to_body === "string" || obj.reply_to_body === null); } /** Converts a row to the API's {@link ChatMessage}. */ export function chatMessageRowToApi(row: ChatMessageRow): ChatMessage { return { id: row.id, userId: row.user_id, body: row.body, createdAt: new Date(row.created_at), updatedAt: row.updated_at ? new Date(row.updated_at) : undefined, authorUsername: row.author_username, authorAvatarMime: row.author_avatar_mime ?? undefined, replyToId: row.reply_to_id ?? undefined, replyToAuthor: row.reply_to_author ?? undefined, replyToBody: row.reply_to_body ?? undefined, }; }