Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(scores): drop fk constraint on traces/observations #2014

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- DropForeignKey
ALTER TABLE "scores" DROP CONSTRAINT "scores_observation_id_fkey";

-- DropForeignKey
ALTER TABLE "scores" DROP CONSTRAINT "scores_trace_id_fkey";
4 changes: 0 additions & 4 deletions packages/shared/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ model Trace {
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

scores Score[]
DatasetRunItems DatasetRunItems[]
DatasetItem DatasetItem[]
JobExecution JobExecution[]
Expand Down Expand Up @@ -306,7 +305,6 @@ model Observation {
outputCost Decimal? @map("output_cost")
totalCost Decimal? @map("total_cost")
completionStartTime DateTime? @map("completion_start_time")
scores Score[]
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
derivedDatasetItems DatasetItem[]
datasetRunItems DatasetRunItems[]
Expand Down Expand Up @@ -400,9 +398,7 @@ model Score {
source ScoreSource
comment String?
traceId String @map("trace_id")
trace Trace @relation(fields: [traceId], references: [id], onDelete: Cascade)
observationId String? @map("observation_id")
observation Observation? @relation(fields: [observationId], references: [id], onDelete: SetNull)
JobExecution JobExecution[]

@@unique([id, traceId]) // used for upsert
Expand Down
189 changes: 76 additions & 113 deletions web/src/server/api/routers/scores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { z } from "zod";

import {
createTRPCRouter,
protectedProcedure,
protectedProjectProcedure,
} from "@/src/server/api/trpc";
import { throwIfNoAccess } from "@/src/features/rbac/utils/checkAccess";
Expand Down Expand Up @@ -105,9 +104,7 @@ export const scoresRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
const names = await ctx.prisma.score.groupBy({
where: {
trace: {
projectId: input.projectId,
},
projectId: input.projectId,
},
by: ["name"],
_count: {
Expand All @@ -121,29 +118,32 @@ export const scoresRouter = createTRPCRouter({

return res;
}),
byId: protectedProcedure.input(z.string()).query(({ input, ctx }) =>
ctx.prisma.score.findFirstOrThrow({
where: {
id: input,
...(ctx.session.user.admin === true
? undefined
: {
trace: {
project: {
members: {
some: {
userId: ctx.session.user.id,
},
},
},
},
}),
},
}),
),
createReviewScore: protectedProcedure
// byId: protectedProjectProcedure
// .input(z.object({ id: z.string(), projectId: z.string() }))
// .query(({ input, ctx }) =>
// ctx.prisma.score.findFirstOrThrow({
// where: {
// id: input,
// ...(ctx.session.user.admin === true
// ? undefined
// : {
// trace: {
// project: {
// members: {
// some: {
// userId: ctx.session.user.id,
// },
// },
// },
// },
// }),
// },
// }),
// ),
marcklingen marked this conversation as resolved.
Show resolved Hide resolved
createReviewScore: protectedProjectProcedure
.input(
z.object({
projectId: z.string(),
traceId: z.string(),
value: z.number(),
name: z.string(),
Expand All @@ -152,49 +152,35 @@ export const scoresRouter = createTRPCRouter({
}),
)
.mutation(async ({ input, ctx }) => {
const trace = await ctx.prisma.trace.findFirstOrThrow({
where: {
id: input.traceId,
project: {
members: {
some: {
userId: ctx.session.user.id,
},
},
},
},
});
throwIfNoAccess({
session: ctx.session,
projectId: trace.projectId,
projectId: input.projectId,
scope: "scores:CUD",
});

const trace = await ctx.prisma.trace.findFirst({
where: {
id: input.traceId,
projectId: input.projectId,
},
});
if (!trace) {
throw new Error("No trace with this id in this project.");
}

const score = await ctx.prisma.score.create({
data: {
trace: {
connect: {
id: trace.id,
},
},
...(input.observationId
? {
observation: {
connect: {
id: input.observationId,
},
},
}
: undefined),
projectId: input.projectId,
traceId: input.traceId,
observationId: input.observationId,
value: input.value,
name: input.name,
comment: input.comment,
projectId: trace.projectId,
source: "REVIEW",
},
});
await auditLog({
projectId: trace.projectId,
projectId: input.projectId,
userId: ctx.session.user.id,
userProjectRole: ctx.session.user.projects.find(
(p) => p.id === trace.projectId,
Expand All @@ -206,114 +192,91 @@ export const scoresRouter = createTRPCRouter({
});
return score;
}),
updateReviewScore: protectedProcedure
updateReviewScore: protectedProjectProcedure
.input(
z.object({
projectId: z.string(),
id: z.string(),
value: z.number(),
comment: z.string().optional(),
}),
)
.mutation(async ({ input, ctx }) => {
const score = await ctx.prisma.score.findFirstOrThrow({
throwIfNoAccess({
session: ctx.session,
projectId: input.projectId,
scope: "scores:CUD",
});
const score = await ctx.prisma.score.findFirst({
where: {
id: input.id,
projectId: input.projectId,
source: "REVIEW",
trace: {
project: {
members: {
some: {
userId: ctx.session.user.id,
},
},
},
},
},
include: {
trace: {
select: {
projectId: true,
},
},
},
});
throwIfNoAccess({
session: ctx.session,
projectId: score.trace.projectId,
scope: "scores:CUD",
});
if (!score) {
throw new Error("No review score with this id in this project.");
}

// exclude trace object from audit log
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { trace, ...pureScore } = score;
await auditLog({
projectId: trace.projectId,
projectId: input.projectId,
userId: ctx.session.user.id,
userProjectRole: ctx.session.user.projects.find(
(p) => p.id === trace.projectId,
(p) => p.id === input.projectId,
)?.role as MembershipRole, // throwIfNoAccess ensures this is defined
resourceType: "score",
resourceId: score.id,
action: "update",
after: pureScore,
after: score,
});

return ctx.prisma.score.update({
where: {
id: score.id,
projectId: input.projectId,
},
data: {
value: input.value,
comment: input.comment,
},
});
}),
deleteReviewScore: protectedProcedure
.input(z.string())
deleteReviewScore: protectedProjectProcedure
.input(z.object({ projectId: z.string(), id: z.string() }))
.mutation(async ({ input, ctx }) => {
const score = await ctx.prisma.score.findFirstOrThrow({
where: {
id: input,
source: "REVIEW",
trace: {
project: {
members: {
some: {
userId: ctx.session.user.id,
},
},
},
},
},
include: {
trace: {
select: {
projectId: true,
},
},
},
});
throwIfNoAccess({
session: ctx.session,
projectId: score.trace.projectId,
projectId: input.projectId,
scope: "scores:CUD",
});
const { trace, ...pureScore } = score;

const score = await ctx.prisma.score.findFirst({
where: {
id: input.id,
source: "REVIEW",
projectId: input.projectId,
},
});
if (!score) {
throw new Error("No review score with this id in this project.");
}

await auditLog({
projectId: trace.projectId,
projectId: input.projectId,
userId: ctx.session.user.id,
userProjectRole: ctx.session.user.projects.find(
(p) => p.id === trace.projectId,
(p) => p.id === input.projectId,
)?.role as MembershipRole, // throwIfNoAccess ensures this is defined
resourceType: "score",
resourceId: score.id,
action: "delete",
before: pureScore,
before: score,
});

return ctx.prisma.score.delete({
where: {
id: score.id,
projectId: input.projectId,
},
});
}),
Expand All @@ -332,7 +295,7 @@ const generateScoresQuery = (
${select}
FROM scores s
JOIN traces t ON t.id = s.trace_id LEFT JOIN job_executions je ON je.job_output_score_id = s.id AND je.project_id = ${projectId}
WHERE t.project_id = ${projectId}
WHERE s.project_id = ${projectId} AND t.project_id = ${projectId}
${filterCondition}
${orderCondition}
LIMIT ${limit}
Expand Down