import { sql } from "drizzle-orm"; import { messages } from "~~/drizzle/schema"; import { db } from "~~/server/lib/db"; import { topicEvents } from "~~/server/utils/events"; async function deeplyDeleteMessage(messageId: string, topicId: string, userId: string) { const children = await db.query.messages.findMany({ where: { parentMessageId: messageId, userId, } } as any); for (const child of children) { await deeplyDeleteMessage(child.id, topicId, userId); } await db.delete(messages).where(sql`${messages.id} = ${messageId} AND ${messages.userId} = ${userId}`); topicEvents.emit(topicId, { type: 'MESSAGE_DELETED', payload: { id: messageId }, }); } export default defineEventHandler(async (event) => { await protectRoute(event); const userId = event.context.user!.id; const messageId = getRouterParam(event, 'messageId')!; const message = await db.query.messages.findFirst({ where: { id: messageId, userId, } } as any); if (!message) { throw createError({ statusCode: 400, statusMessage: 'Invalid message', }); } const topicId = message.topicId; const allTopicMessages = await db.query.messages.findMany({ where: { topicId, userId, }, orderBy: { createdAt: 'asc', }, }); const messagesMap = new Map(allTopicMessages.map(m => [m.id, { ...m, children: [] as typeof m[] }])); for (const msg of messagesMap.values()) { if (msg.parentMessageId && messagesMap.has(msg.parentMessageId)) { messagesMap.get(msg.parentMessageId)!.children.push(msg); } } const rootMessage = messagesMap.get(messageId); if (!rootMessage) { throw createError({ statusCode: 400, statusMessage: 'Invalid message', }); } if (rootMessage.role === 'user') { await deeplyDeleteMessage(rootMessage.id, topicId, userId); return { ok: true }; } if (rootMessage.deleted === true) { const childMessage = rootMessage.children[rootMessage.focusedIndex!]; if (!childMessage) { console.error('Message not found'); return { ok: false }; } await deeplyDeleteMessage(childMessage.id, topicId, userId); const remainingChildren = rootMessage.children.filter(child => child!.id !== childMessage.id); if (remainingChildren.length === 0) { await deeplyDeleteMessage(rootMessage.id, topicId, userId); } else { const newFocusedIndex = rootMessage.focusedIndex && rootMessage.focusedIndex > 0 ? Math.min(rootMessage.focusedIndex - 1, remainingChildren.length - 1) : 0; await db.update(messages).set({ focusedIndex: newFocusedIndex }).where(sql`${messages.id} = ${rootMessage.id} AND ${messages.userId} = ${userId}`); topicEvents.emit(topicId, { type: 'MESSAGE_UPDATED', payload: { ...rootMessage, focusedIndex: newFocusedIndex }, }); } return { ok: true }; } if ( (rootMessage.focusedIndex !== undefined && rootMessage.focusedIndex !== null) && rootMessage.focusedIndex > 0 && rootMessage.children.length > 0 ) { const childMessage = rootMessage.children[rootMessage.focusedIndex - 1]; if (!childMessage) { console.error('Message not found'); return { ok: false }; } await deeplyDeleteMessage(childMessage.id, topicId, userId); const remainingChildren = rootMessage.children.filter(child => child!.id !== childMessage.id); const newFocusedIndex = remainingChildren.length > 0 ? Math.min(rootMessage.focusedIndex - 1, remainingChildren.length - 1) : 0; await db.update(messages).set({ focusedIndex: newFocusedIndex }).where(sql`${messages.id} = ${rootMessage.id} AND ${messages.userId} = ${userId}`); topicEvents.emit(topicId, { type: 'MESSAGE_UPDATED', payload: { ...rootMessage, focusedIndex: newFocusedIndex }, }); return { ok: true }; } if (rootMessage.children.length === 0) { await deeplyDeleteMessage(rootMessage.id, topicId, userId); return { ok: true }; } await db.update(messages).set({ deleted: true }).where(sql`${messages.id} = ${rootMessage.id} AND ${messages.userId} = ${userId}`); topicEvents.emit(topicId, { type: 'MESSAGE_UPDATED', payload: { ...rootMessage, deleted: true }, }); return { ok: true }; });