refactor(api): modularize assistant router workflow
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import { vi } from "vitest";
|
||||
|
||||
export const TEST_USER_ID = "assistant-test-user";
|
||||
export const TEST_CONVERSATION_ID = "assistant-test-conversation";
|
||||
|
||||
export function createApprovalStoreMock() {
|
||||
const records = new Map<string, {
|
||||
id: string;
|
||||
userId: string;
|
||||
conversationId: string;
|
||||
toolName: string;
|
||||
toolArguments: string;
|
||||
summary: string;
|
||||
status: "PENDING" | "APPROVED" | "CANCELLED" | "EXPIRED";
|
||||
approvedAt: Date | null;
|
||||
cancelledAt: Date | null;
|
||||
createdAt: Date;
|
||||
expiresAt: Date;
|
||||
updatedAt: Date;
|
||||
}>();
|
||||
|
||||
return {
|
||||
assistantApproval: {
|
||||
findFirst: vi.fn(async ({
|
||||
where,
|
||||
orderBy,
|
||||
}: {
|
||||
where: {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
conversationId?: string;
|
||||
status?: "PENDING" | "APPROVED" | "CANCELLED" | "EXPIRED";
|
||||
};
|
||||
orderBy?: { createdAt: "desc" | "asc" };
|
||||
}) => {
|
||||
const matches = [...records.values()]
|
||||
.filter((record) => (
|
||||
(!where.id || record.id === where.id)
|
||||
&& (!where.userId || record.userId === where.userId)
|
||||
&& (!where.conversationId || record.conversationId === where.conversationId)
|
||||
&& (!where.status || record.status === where.status)
|
||||
))
|
||||
.sort((a, b) => (
|
||||
orderBy?.createdAt === "asc"
|
||||
? a.createdAt.getTime() - b.createdAt.getTime()
|
||||
: b.createdAt.getTime() - a.createdAt.getTime()
|
||||
));
|
||||
return matches[0] ?? null;
|
||||
}),
|
||||
findMany: vi.fn(async ({
|
||||
where,
|
||||
orderBy,
|
||||
}: {
|
||||
where: {
|
||||
userId?: string;
|
||||
conversationId?: string;
|
||||
status?: "PENDING" | "APPROVED" | "CANCELLED" | "EXPIRED";
|
||||
expiresAt?: { lte?: Date; gt?: Date };
|
||||
};
|
||||
orderBy?: { createdAt: "desc" | "asc" };
|
||||
}) => (
|
||||
[...records.values()]
|
||||
.filter((record) => (
|
||||
(!where.userId || record.userId === where.userId)
|
||||
&& (!where.conversationId || record.conversationId === where.conversationId)
|
||||
&& (!where.status || record.status === where.status)
|
||||
&& (!where.expiresAt?.lte || record.expiresAt <= where.expiresAt.lte)
|
||||
&& (!where.expiresAt?.gt || record.expiresAt > where.expiresAt.gt)
|
||||
))
|
||||
.sort((a, b) => (
|
||||
orderBy?.createdAt === "asc"
|
||||
? a.createdAt.getTime() - b.createdAt.getTime()
|
||||
: b.createdAt.getTime() - a.createdAt.getTime()
|
||||
))
|
||||
)),
|
||||
create: vi.fn(async ({
|
||||
data,
|
||||
}: {
|
||||
data: {
|
||||
userId: string;
|
||||
conversationId: string;
|
||||
toolName: string;
|
||||
toolArguments: string;
|
||||
summary: string;
|
||||
createdAt: Date;
|
||||
expiresAt: Date;
|
||||
};
|
||||
}) => {
|
||||
const record = {
|
||||
id: `approval-${records.size + 1}`,
|
||||
...data,
|
||||
status: "PENDING" as const,
|
||||
approvedAt: null,
|
||||
cancelledAt: null,
|
||||
updatedAt: data.createdAt,
|
||||
};
|
||||
records.set(record.id, record);
|
||||
return record;
|
||||
}),
|
||||
updateMany: vi.fn(async ({
|
||||
where,
|
||||
data,
|
||||
}: {
|
||||
where: {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
conversationId?: string;
|
||||
status?: "PENDING" | "APPROVED" | "CANCELLED" | "EXPIRED";
|
||||
expiresAt?: { lte?: Date; gt?: Date };
|
||||
};
|
||||
data: Partial<{
|
||||
status: "APPROVED" | "CANCELLED" | "EXPIRED";
|
||||
cancelledAt: Date;
|
||||
approvedAt: Date;
|
||||
}>;
|
||||
}) => {
|
||||
let count = 0;
|
||||
for (const [id, record] of records.entries()) {
|
||||
if (where.id && record.id !== where.id) continue;
|
||||
if (where.userId && record.userId !== where.userId) continue;
|
||||
if (where.conversationId && record.conversationId !== where.conversationId) continue;
|
||||
if (where.status && record.status !== where.status) continue;
|
||||
if (where.expiresAt?.lte && record.expiresAt > where.expiresAt.lte) continue;
|
||||
if (where.expiresAt?.gt && record.expiresAt <= where.expiresAt.gt) continue;
|
||||
records.set(id, {
|
||||
...record,
|
||||
...data,
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
count += 1;
|
||||
}
|
||||
return { count };
|
||||
}),
|
||||
update: vi.fn(async ({
|
||||
where,
|
||||
data,
|
||||
}: {
|
||||
where: { id: string };
|
||||
data: {
|
||||
status: "APPROVED";
|
||||
approvedAt: Date;
|
||||
};
|
||||
}) => {
|
||||
const record = records.get(where.id);
|
||||
if (!record) throw new Error("Record not found");
|
||||
const next = {
|
||||
...record,
|
||||
...data,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
records.set(where.id, next);
|
||||
return next;
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createMissingApprovalTableError() {
|
||||
return Object.assign(
|
||||
new Error("The table `public.assistant_approvals` does not exist in the current database."),
|
||||
{
|
||||
code: "P2021",
|
||||
meta: { table: "public.assistant_approvals" },
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user