import { dbGlobal } from "drizzle-pkg/lib/db"; import { quickNotes } from "drizzle-pkg/lib/schema/content"; import { eq } from "drizzle-orm"; import { nextIntegerId } from "../../utils/sqlite-id"; export const QUICK_NOTE_MAX_LENGTH = 200000; export function normalizeQuickNoteContent(content: string): string { return content.replaceAll("\r\n", "\n"); } export function validateQuickNoteContentLength(content: string) { if (content.length > QUICK_NOTE_MAX_LENGTH) { throw createError({ statusCode: 400, statusMessage: "速记内容过长" }); } } export function isQuickNoteUniqueViolation(error: unknown): boolean { const message = error instanceof Error ? error.message : String(error ?? ""); if (!message.includes("UNIQUE constraint failed")) { return false; } return message.includes("quick_notes.user_id") || message.includes("quick_notes_user_id_unique"); } export async function getQuickNoteByUserId(userId: number) { const [row] = await dbGlobal .select() .from(quickNotes) .where(eq(quickNotes.userId, userId)) .limit(1); return row ?? null; } export async function upsertQuickNoteByUserId(userId: number, content: string) { const normalizedContent = normalizeQuickNoteContent(content); validateQuickNoteContentLength(normalizedContent); const existing = await getQuickNoteByUserId(userId); if (!existing) { try { const id = await nextIntegerId(quickNotes, quickNotes.id); await dbGlobal.insert(quickNotes).values({ id, userId, content: normalizedContent, }); } catch (error) { // 处理并发下“先查后插”触发的唯一键冲突:回退为 update。 if (!isQuickNoteUniqueViolation(error)) { throw error; } await dbGlobal .update(quickNotes) .set({ content: normalizedContent }) .where(eq(quickNotes.userId, userId)); } const inserted = await getQuickNoteByUserId(userId); if (!inserted) { throw new Error(`速记写入失败:userId=${userId}`); } return inserted; } await dbGlobal .update(quickNotes) .set({ content: normalizedContent }) .where(eq(quickNotes.userId, userId)); const updated = await getQuickNoteByUserId(userId); if (!updated) { throw new Error(`速记更新失败:userId=${userId}`); } return updated; }