Canvas: Persistent log storage
Change-Id: I3eac705329e6d68d8e4b9a371c6e9b9807f357ec
diff --git a/apps/canvas/back/src/log.ts b/apps/canvas/back/src/log.ts
new file mode 100644
index 0000000..68dc005
--- /dev/null
+++ b/apps/canvas/back/src/log.ts
@@ -0,0 +1,51 @@
+import { Prisma, PrismaClient } from "@prisma/client";
+import { LogItem } from "./project_monitor";
+
+type LogRecord = LogItem & {
+ id: number;
+};
+
+class LogStore {
+ constructor(private prisma: PrismaClient) {}
+
+ async store(projectId: number, serviceName: string, workerId: string, logs: LogItem[]) {
+ await this.prisma.log.createMany({
+ data: logs.map((log) => ({
+ projectId,
+ serviceName,
+ workerId,
+ runId: log.runId,
+ commit: log.commit ?? undefined,
+ contents: log.contents,
+ timestampMilli: log.timestampMilli,
+ })),
+ });
+ }
+
+ async get(
+ projectId: number,
+ serviceName: string,
+ workerId: string,
+ afterId?: number,
+ numRecords?: number,
+ ): Promise<LogRecord[]> {
+ const where: Prisma.LogWhereInput = { projectId, serviceName, workerId };
+ if (afterId) {
+ where.id = { gt: afterId };
+ }
+ const logs = await this.prisma.log.findMany({
+ where,
+ orderBy: { timestampMilli: "asc" },
+ take: numRecords ?? 100,
+ });
+ return logs.map((log) => ({
+ id: log.id,
+ timestampMilli: Number(log.timestampMilli),
+ contents: log.contents,
+ runId: log.runId,
+ commit: log.commit ?? undefined,
+ }));
+ }
+}
+
+export default LogStore;