Files
OpenPipe-llm/app/src/server/api/routers/scenarioVariables.router.ts
arcticfly d9db6d80ea Update external types (#137)
* Separate server and frontend error logic

* Update types in external api
2023-08-11 15:02:14 -07:00

144 lines
4.4 KiB
TypeScript

import { type TemplateVariable } from "@prisma/client";
import { sql } from "kysely";
import { z } from "zod";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "~/server/api/trpc";
import { kysely, prisma } from "~/server/db";
import { error, success } from "~/utils/errorHandling/standardResponses";
import { requireCanModifyExperiment, requireCanViewExperiment } from "~/utils/accessControl";
export const scenarioVarsRouter = createTRPCRouter({
create: protectedProcedure
.input(z.object({ experimentId: z.string(), label: z.string() }))
.mutation(async ({ input, ctx }) => {
await requireCanModifyExperiment(input.experimentId, ctx);
// Make sure there isn't an existing variable with the same name
const existingVariable = await prisma.templateVariable.findFirst({
where: {
experimentId: input.experimentId,
label: input.label,
},
});
if (existingVariable) {
return error(`A variable named ${input.label} already exists.`);
}
await prisma.templateVariable.create({
data: {
experimentId: input.experimentId,
label: input.label,
},
});
return success();
}),
rename: protectedProcedure
.input(z.object({ id: z.string(), label: z.string() }))
.mutation(async ({ input, ctx }) => {
const templateVariable = await prisma.templateVariable.findUniqueOrThrow({
where: { id: input.id },
});
await requireCanModifyExperiment(templateVariable.experimentId, ctx);
// Make sure there isn't an existing variable with the same name
const existingVariable = await prisma.templateVariable.findFirst({
where: {
experimentId: templateVariable.experimentId,
label: input.label,
},
});
if (existingVariable) {
return error(`A variable named ${input.label} already exists.`);
}
await renameTemplateVariable(templateVariable, input.label);
return success();
}),
delete: protectedProcedure
.input(z.object({ id: z.string() }))
.mutation(async ({ input, ctx }) => {
const { experimentId } = await prisma.templateVariable.findUniqueOrThrow({
where: { id: input.id },
});
await requireCanModifyExperiment(experimentId, ctx);
await prisma.templateVariable.delete({ where: { id: input.id } });
}),
list: publicProcedure
.input(z.object({ experimentId: z.string() }))
.query(async ({ input, ctx }) => {
await requireCanViewExperiment(input.experimentId, ctx);
return await prisma.templateVariable.findMany({
where: {
experimentId: input.experimentId,
},
orderBy: {
createdAt: "asc",
},
select: {
id: true,
label: true,
},
});
}),
});
export const renameTemplateVariable = async (
templateVariable: TemplateVariable,
newLabel: string,
) => {
const { experimentId } = templateVariable;
await kysely.transaction().execute(async (trx) => {
await trx
.updateTable("TemplateVariable")
.set({
label: newLabel,
})
.where("id", "=", templateVariable.id)
.execute();
await sql`
CREATE TEMP TABLE "TempTestScenario" AS
SELECT *
FROM "TestScenario"
WHERE "experimentId" = ${experimentId}
-- Only copy the rows that actually have a value for the variable, no reason to churn the rest and simplifies the update.
AND "variableValues"->${templateVariable.label} IS NOT NULL
`.execute(trx);
await sql`
UPDATE "TempTestScenario"
SET "variableValues" = jsonb_set(
"variableValues",
${`{${newLabel}}`},
"variableValues"->${templateVariable.label}
) - ${templateVariable.label},
"updatedAt" = NOW(),
"id" = uuid_generate_v4()
`.execute(trx);
// Print the contents of the temp table
const results = await sql`SELECT * FROM "TempTestScenario"`.execute(trx);
console.log(results.rows);
await trx
.updateTable("TestScenario")
.set({
visible: false,
})
.where("experimentId", "=", experimentId)
.execute();
await sql`
INSERT INTO "TestScenario" (id, "variableValues", "uiId", visible, "sortIndex", "experimentId", "createdAt", "updatedAt")
SELECT * FROM "TempTestScenario";
`.execute(trx);
});
};