Files
PolyMPR/routes/(apps)/students/api/students.ts
T
djalim 9636242b42 refactor(mobility): switch to Drizzle ORM and remove raw SQLite usage
- replace Database with db instance
- use schema imports for tables
- use db.select, db.insert, onConflictDoUpdate
- remove manual connection handling and console logs
- improve type safety and maintainability

refactor(students): migrate to Drizzle ORM and async queries

Replace raw sqlite queries with Drizzle ORM. Remove the connect helper and use the
shared db instance and schema definitions. Convert getItself, getAll and
addStudents to async functions, use eq and lt helpers, and simplify promotion
handling. This improves type safety, maintainability, and allows non‑blocking
database access.
2026-04-03 10:43:29 +02:00

123 lines
3.2 KiB
TypeScript

import { FreshContext, Handlers } from "$fresh/server.ts";
import { db } from "$root/databases/db.ts";
import { promotions, students } from "$root/databases/schema.ts";
import { AuthenticatedState } from "$root/defaults/interfaces.ts";
import { eq, lt } from "npm:drizzle-orm";
async function getItself(
userId: string,
): Promise<{ student: Student | null; promo: Promotion | null }> {
const student = await db
.select()
.from(students)
.where(eq(students.userId, userId))
.limit(1)
.then((rows) => rows[0] ?? null);
if (!student) {
return { student: null, promo: null };
}
const promo = await db
.select()
.from(promotions)
.where(eq(promotions.id, student.promotionId!))
.limit(1)
.then((rows) => rows[0] ?? null);
return { student, promo };
}
async function getAll(): Promise<
{ students: Student[]; promos: Promotion[] }
> {
const rows = await db
.select({
userId: students.userId,
firstName: students.firstName,
lastName: students.lastName,
mail: students.mail,
promotionId: students.promotionId,
})
.from(students)
.innerJoin(promotions, eq(students.promotionId, promotions.id))
.where(lt(promotions.current, 6));
const promos = await db
.select()
.from(promotions)
.where(lt(promotions.current, 6));
return { students: rows as Student[], promos };
}
async function addStudents(
studentList: Student[],
promoId: number,
): Promise<void> {
for (const student of studentList) {
await db
.insert(students)
.values({
userId: student.userId,
firstName: student.firstName,
lastName: student.lastName,
mail: student.mail,
promotionId: promoId,
})
.onConflictDoNothing();
}
}
export const handler: Handlers<null, AuthenticatedState> = {
async GET(
_request: Request,
context: FreshContext<AuthenticatedState>,
): Promise<Response> {
if (context.state.session.eduPersonPrimaryAffiliation == "student") {
return new Response(
JSON.stringify(await getItself(context.state.session.uid)),
{ headers: { "content-type": "application/json" } },
);
}
return new Response(
JSON.stringify(await getAll()),
{ headers: { "content-type": "application/json" } },
);
},
async POST(
request: Request,
_context: FreshContext<AuthenticatedState>,
): Promise<Response> {
const { students: studentList, promo }: {
students: Student[];
promo: string;
} = await request.json();
if (!promo || !promo.match(/^\d{4}-\dA$/) || !Array.isArray(studentList)) {
return new Response(null, { status: 400 });
}
const { endyear, current } = promo.match(
/^(?<endyear>\d{4})-(?<current>\d)A$/,
)?.groups!;
await db
.insert(promotions)
.values({ endyear: Number(endyear), current: Number(current) })
.onConflictDoNothing();
const promo_row = await db
.select()
.from(promotions)
.where(eq(promotions.endyear, Number(endyear)))
.then((rows) => rows.find((r) => r.current === Number(current))!);
await addStudents(studentList, promo_row.id);
return new Response(null, { status: 201 });
},
};