167 lines
5.0 KiB
TypeScript
167 lines
5.0 KiB
TypeScript
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" },
|
|
},
|
|
);
|
|
}
|