SPB Git
2.4 KB · 26 lines typescript
1/** Experiments service (params/metrics jsonb, status planned|running|done|failed). */2import { and, asc, eq } from "drizzle-orm";3import { db, schema } from "@/db";4import { HttpError } from "@/lib/auth/guard";5const E = schema.experiments;6export type ExperimentRow = typeof E.$inferSelect;7export const EXPERIMENT_STATUSES = ["planned", "running", "done", "failed"] as const;8export type ExperimentStatus = (typeof EXPERIMENT_STATUSES)[number];9export interface ExperimentInput { pageId?: string | null; name: string; status?: ExperimentStatus; params?: Record<string, unknown>; metrics?: Record<string, unknown>; datasetRef?: string | null; repoUrl?: string | null; notes?: string | null }1011export async function listExperiments(wsId: string, pageId?: string | null) {12  return db.select().from(E).where(and(eq(E.workspaceId, wsId), pageId ? eq(E.pageId, pageId) : undefined)).orderBy(asc(E.createdAt));13}14export async function createExperiment(wsId: string, input: ExperimentInput) {15  const [e] = await db.insert(E).values({ workspaceId: wsId, pageId: input.pageId ?? null, name: input.name.trim() || "Experiment", status: input.status ?? "planned", params: input.params ?? {}, metrics: input.metrics ?? {}, datasetRef: input.datasetRef ?? null, repoUrl: input.repoUrl ?? null, notes: input.notes ?? null, startedAt: input.status === "running" ? new Date() : null }).returning();16  return e;17}18export async function updateExperiment(wsId: string, id: string, patch: Partial<ExperimentInput>) {19  const [prev] = await db.select().from(E).where(and(eq(E.id, id), eq(E.workspaceId, wsId))); if (!prev) throw new HttpError(404, "Experiment not found");20  const set: Partial<ExperimentRow> = { updatedAt: new Date() };21  for (const k of ["pageId", "name", "status", "params", "metrics", "datasetRef", "repoUrl", "notes"] as const) if (patch[k] !== undefined) (set as any)[k] = patch[k];22  if (patch.status && patch.status !== prev.status) { if (patch.status === "running" && !prev.startedAt) set.startedAt = new Date(); if (patch.status === "done" || patch.status === "failed") set.finishedAt = new Date(); if (patch.status === "planned") { set.startedAt = null; set.finishedAt = null; } }23  const [e] = await db.update(E).set(set).where(eq(E.id, id)).returning(); return e;24}25export async function deleteExperiment(wsId: string, id: string) { await db.delete(E).where(and(eq(E.id, id), eq(E.workspaceId, wsId))); }26
Files · main
Menu

Theme