Skip to content

Commit

Permalink
Migrate get evaluations query to Drizzle on API Frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
haikalvidya committed Nov 5, 2024
1 parent ab3580f commit dc9eb13
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -1,22 +1,82 @@
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { fetcher } from '@/lib/utils';
import { isCurrentUserMemberOfProject } from '@/lib/db/utils';
import { db } from '@/lib/db/drizzle';
import {
evaluationResults,
evaluations,
evaluationScores
} from '@/lib/db/schema';
import { and, asc, eq, sql } from 'drizzle-orm';

export async function GET(
req: Request,
{ params }: { params: { projectId: string; evaluationId: string } }
): Promise<Response> {
const projectId = params.projectId;
const evaluationId = params.evaluationId;
const session = await getServerSession(authOptions);
const user = session!.user;

return await fetcher(`/projects/${projectId}/evaluations/${evaluationId}`, {
method: 'GET',
headers: {
Authorization: `Bearer ${user.apiKey}`
}
});
if (!(await isCurrentUserMemberOfProject(projectId))) {
return new Response(
JSON.stringify({ error: 'User is not a member of the project' }),
{ status: 403 }
);
}

const getEvaluation = db
.select()
.from(evaluations)
.where(
and(
eq(evaluations.id, evaluationId),
eq(evaluations.projectId, projectId)
)
);

const subQueryScoreCte = db.$with('scores').as(
db
.select({
resultId: evaluationScores.resultId,
scores: sql`jsonb_object_agg(${evaluationScores.name}, ${evaluationScores.score})`
})
.from(evaluationScores)
.groupBy(evaluationScores.resultId)
);

const getEvaluationResults = db
.select({
id: evaluationResults.id,
createdAt: evaluationResults.createdAt,
evaluationId: evaluationResults.evaluationId,
data: evaluationResults.data,
target: evaluationResults.target,
executorOutput: evaluationResults.executorOutput,
scores: subQueryScoreCte.scores,
traceId: evaluationResults.traceId
})
.from(evaluationResults)
.leftJoin(
subQueryScoreCte,
eq(evaluationResults.id, subQueryScoreCte.resultId)
)
.where(eq(evaluationResults.evaluationId, evaluationId))
.orderBy(
asc(evaluationResults.createdAt),
asc(evaluationResults.indexInBatch)
);

const [evaluation, results] = await Promise.all([
getEvaluation,
getEvaluationResults
]);

const result = {
evaluation: evaluation[0],
results
};

return Response.json(result);
}

export async function DELETE(
Expand Down
54 changes: 37 additions & 17 deletions frontend/app/api/projects/[projectId]/evaluations/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,41 @@ export async function GET(
): Promise<Response> {
const projectId = params.projectId;

const { searchParams } = new URL(req.url);
const groupId = searchParams.get('groupId');

if (!(await isCurrentUserMemberOfProject(projectId))) {
return new Response(JSON.stringify({ error: "User is not a member of the project" }), { status: 403 });
return new Response(
JSON.stringify({ error: 'User is not a member of the project' }),
{ status: 403 }
);
}

const baseQuery = db.$with(
"base"
).as(
db
if (groupId && !groupId.trim()) {
const result = await db
.select()
.from(evaluations)
);
.where(
and(
eq(evaluations.projectId, projectId),
eq(evaluations.groupId, groupId)
)
);

const result = await paginatedGet<any, Evaluation>({
table: evaluations,
baseFilters: [eq(sql`project_id`, projectId)],
filters: [],
baseQuery,
orderBy: desc(sql`created_at`),
});
return Response.json(result);
} else {
const baseQuery = db.$with('base').as(db.select().from(evaluations));

return Response.json(result);
const result = await paginatedGet<any, Evaluation>({
table: evaluations,
baseFilters: [eq(sql`project_id`, projectId)],
filters: [],
baseQuery,
orderBy: desc(sql`created_at`)
});

return Response.json(result);
}
}

export async function DELETE(
Expand All @@ -40,18 +54,24 @@ export async function DELETE(
const projectId = params.projectId;

if (!(await isCurrentUserMemberOfProject(projectId))) {
return new Response(JSON.stringify({ error: "User is not a member of the project" }), { status: 403 });
return new Response(
JSON.stringify({ error: 'User is not a member of the project' }),
{ status: 403 }
);
}

const { searchParams } = new URL(req.url);
const evaluationIds = searchParams.get('evaluationIds')?.split(',');

if (!evaluationIds) {
return new Response('At least one Evaluation ID is required', { status: 400 });
return new Response('At least one Evaluation ID is required', {
status: 400
});
}

try {
await db.delete(evaluations)
await db
.delete(evaluations)
.where(
and(
inArray(evaluations.id, evaluationIds),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { authOptions } from '@/lib/auth';
import { getServerSession } from 'next-auth';
import { redirect } from 'next/navigation';
import { Metadata } from 'next';
import { fetcherJSON } from '@/lib/utils';
import Evaluation from '@/components/evaluation/evaluation';
import {
Evaluation as EvaluationType,
EvaluationResultsInfo
} from '@/lib/evaluation/types';

export const metadata: Metadata = {
title: 'Evaluation results'
Expand All @@ -19,33 +22,18 @@ export default async function EvaluationPage({
redirect('/sign-in');
}

const user = session.user;

const getEvaluationInfo = fetcherJSON(
`/projects/${params.projectId}/evaluations/${params.evaluationId}`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${user.apiKey}`
}
}
const evaluationInfoRes = await fetch(
`/api/projects/${params.projectId}/evaluations/${params.evaluationId}`
);

// Expect backend to return only evaluations from the current group based on the current evaluation id
const getEvaluations = fetcherJSON(
`/projects/${params.projectId}/evaluations?currentEvaluationId=${params.evaluationId}`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${user.apiKey}`
}
}
const evaluationInfo =
(await evaluationInfoRes.json()) as EvaluationResultsInfo;

const evaluationsRes = await fetch(
`/api/projects/${params.projectId}/evaluations?groupId=${evaluationInfo.evaluation.groupId}`
);

const [evaluationInfo, evaluations] = await Promise.all([
getEvaluationInfo,
getEvaluations
]);
const evaluations = (await evaluationsRes.json()) as EvaluationType[];

return (
<Evaluation evaluationInfo={evaluationInfo} evaluations={evaluations} />
Expand Down

0 comments on commit dc9eb13

Please sign in to comment.