Files
veridian/server/api/messages/[messageId]/index.delete.ts
T

170 lines
6.1 KiB
TypeScript

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 targetMessage = messagesMap.get(messageId);
if (!targetMessage) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid message',
});
}
if (targetMessage.role === 'user') {
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
return { ok: true };
}
if (targetMessage.parentMessageId && messagesMap.has(targetMessage.parentMessageId)) {
const parent = messagesMap.get(targetMessage.parentMessageId)!;
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
const remainingChildren = parent.children.filter((child) => {
return child.id !== targetMessage.id;
});
if (parent.deleted === true && remainingChildren.length === 0) {
await deeplyDeleteMessage(parent.id, topicId, userId);
} else if (parent.activeChildId === targetMessage.id) {
const nextActiveChildId = remainingChildren.length > 0
? (parent.deleted ? remainingChildren[0]!.id : remainingChildren[remainingChildren.length - 1]!.id)
: null;
await db.update(messages).set({ activeChildId: nextActiveChildId }).where(sql`${messages.id} = ${parent.id} AND ${messages.userId} = ${userId}`);
topicEvents.emit(topicId, {
type: 'MESSAGE_UPDATED',
payload: { ...parent, activeChildId: nextActiveChildId },
});
}
return { ok: true };
}
if (targetMessage.deleted === true) {
const childMessage = targetMessage.activeChildId
? targetMessage.children.find((c) => { return c.id === targetMessage.activeChildId; })
: targetMessage.children[0];
if (childMessage) {
await deeplyDeleteMessage(childMessage.id, topicId, userId);
const remainingChildren = targetMessage.children.filter((child) => {
return child.id !== childMessage.id;
});
if (remainingChildren.length === 0) {
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
} else if (targetMessage.activeChildId === childMessage.id) {
const nextActiveChildId = remainingChildren[0]!.id;
await db.update(messages).set({ activeChildId: nextActiveChildId }).where(sql`${messages.id} = ${targetMessage.id} AND ${messages.userId} = ${userId}`);
topicEvents.emit(topicId, {
type: 'MESSAGE_UPDATED',
payload: { ...targetMessage, activeChildId: nextActiveChildId },
});
}
} else {
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
}
return { ok: true };
}
if (
targetMessage.activeChildId
&& targetMessage.children.length > 0
) {
const childMessage = targetMessage.children.find((c) => {
return c.id === targetMessage.activeChildId;
});
if (childMessage) {
await deeplyDeleteMessage(childMessage.id, topicId, userId);
const remainingChildren = targetMessage.children.filter((child) => {
return child.id !== childMessage.id;
});
const nextActiveChildId = remainingChildren.length > 0
? remainingChildren[remainingChildren.length - 1]!.id
: null;
await db.update(messages).set({ activeChildId: nextActiveChildId }).where(sql`${messages.id} = ${targetMessage.id} AND ${messages.userId} = ${userId}`);
topicEvents.emit(topicId, {
type: 'MESSAGE_UPDATED',
payload: { ...targetMessage, activeChildId: nextActiveChildId },
});
return { ok: true };
}
}
if (targetMessage.children.length === 0) {
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
return { ok: true };
}
const nextActiveChildId = targetMessage.children[0]?.id ?? null;
await db.update(messages).set({
deleted: true,
activeChildId: nextActiveChildId,
}).where(sql`${messages.id} = ${targetMessage.id} AND ${messages.userId} = ${userId}`);
topicEvents.emit(topicId, {
type: 'MESSAGE_UPDATED',
payload: { ...targetMessage, deleted: true, activeChildId: nextActiveChildId },
});
return { ok: true };
});