diff --git a/routes/(apps)/mobility/api/insert_mobility.ts b/routes/(apps)/mobility/api/insert_mobility.ts index 90f228f..0452d26 100644 --- a/routes/(apps)/mobility/api/insert_mobility.ts +++ b/routes/(apps)/mobility/api/insert_mobility.ts @@ -1,55 +1,36 @@ import { Handlers } from "$fresh/server.ts"; -import { Database } from "@db/sqlite"; +import { db } from "$root/databases/db.ts"; +import { mobility, promotions, students } from "$root/databases/schema.ts"; +import { eq } from "npm:drizzle-orm"; export const handler: Handlers = { - // deno-lint-ignore require-await async GET() { try { - console.log("Connecting to mobility database..."); - const connection = new Database("databases/data/mobility.db", { - create: false, - }); - connection.run( - "ATTACH DATABASE 'databases/data/students.db' AS students", - ); - console.log("Connected to databases."); + const studentRows = await db + .select({ + id: students.userId, + firstName: students.firstName, + lastName: students.lastName, + promotionId: students.promotionId, + endyear: promotions.endyear, + current: promotions.current, + }) + .from(students) + .leftJoin(promotions, eq(students.promotionId, promotions.id)); - const students = connection.prepare( - `SELECT - students.userId AS id, - students.firstName, - students.lastName, - students.promotionId AS promotionId, - promotions.name AS promotionName - FROM students.students - LEFT JOIN students.promotions ON students.promotionId = promotions.id`, - ).all(); + const mobilityRows = await db.select().from(mobility); - const mobilities = connection.prepare( - `SELECT - mobility.id, - mobility.studentId, - mobility.startDate, - mobility.endDate, - mobility.weeksCount, - mobility.destinationCountry, - mobility.destinationName, - mobility.mobilityStatus - FROM mobility`, - ).all(); - - const promotions = connection.prepare( - `SELECT id, name FROM students.promotions`, - ).all(); - - connection.close(); + const promotionRows = await db + .select({ id: promotions.id, endyear: promotions.endyear, current: promotions.current }) + .from(promotions); return new Response( - JSON.stringify({ mobilities, students, promotions }), - { - status: 200, - headers: { "Content-Type": "application/json" }, - }, + JSON.stringify({ + mobilities: mobilityRows, + students: studentRows, + promotions: promotionRows, + }), + { status: 200, headers: { "Content-Type": "application/json" } }, ); } catch (error) { console.error("Error fetching mobility data:", error); @@ -58,8 +39,6 @@ export const handler: Handlers = { }, async POST(request) { - console.log("API /mobility/api/insert_mobility POST called"); - try { const body = await request.json(); const { data } = body; @@ -67,32 +46,8 @@ export const handler: Handlers = { if (!Array.isArray(data)) { throw new Error("Invalid request body"); } - console.log("Connecting to mobility database..."); - const connection = new Database("databases/data/mobility.db", { - create: false, - }); - console.log("Attaching students database..."); - connection.run( - "ATTACH DATABASE 'databases/data/students.db' AS students", - ); - console.log("Students database attached successfully."); - - const insertQuery = connection.prepare( - `INSERT INTO mobility ( - id, studentId, startDate, endDate, weeksCount, destinationCountry, destinationName, mobilityStatus - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(id) DO UPDATE SET - startDate = excluded.startDate, - endDate = excluded.endDate, - weeksCount = excluded.weeksCount, - destinationCountry = excluded.destinationCountry, - destinationName = excluded.destinationName, - mobilityStatus = excluded.mobilityStatus`, - ); - - for (const mobility of data) { + for (const entry of data) { const { id, studentId, @@ -102,19 +57,16 @@ export const handler: Handlers = { destinationCountry, destinationName, mobilityStatus = "N/A", - } = mobility; + } = entry; - console.log("Processing mobility data:", mobility); + const studentExists = await db + .select({ userId: students.userId }) + .from(students) + .where(eq(students.userId, studentId)) + .limit(1) + .then((rows) => rows.length > 0); - const studentExists = connection - .prepare( - `SELECT COUNT(*) AS count FROM students.students WHERE userId = ?`, - ) - .get(studentId); - - console.log(`Student ${studentId} exists:`, studentExists.count > 0); - - if (studentExists.count === 0) { + if (!studentExists) { console.warn(`Skipping mobility for unknown studentId: ${studentId}`); continue; } @@ -123,43 +75,39 @@ export const handler: Handlers = { if (startDate && endDate) { const start = new Date(startDate); const end = new Date(endDate); - if (start <= end) { - calculatedWeeksCount = Math.ceil( + calculatedWeeksCount = start <= end + ? Math.ceil( (end.getTime() - start.getTime()) / (7 * 24 * 60 * 60 * 1000), - ); - } else { - calculatedWeeksCount = null; - } + ) + : null; } - console.log("Executing SQL insert/update query for:", { - id, - studentId, - startDate, - endDate, - calculatedWeeksCount, - destinationCountry, - destinationName, - mobilityStatus, - }); - - insertQuery.run( - id, - studentId, - startDate, - endDate, - calculatedWeeksCount, - destinationCountry, - destinationName, - mobilityStatus, - ); + await db + .insert(mobility) + .values({ + id, + studentId, + startDate, + endDate, + weeksCount: calculatedWeeksCount, + destinationCountry, + destinationName, + mobilityStatus, + }) + .onConflictDoUpdate({ + target: mobility.id, + set: { + startDate, + endDate, + weeksCount: calculatedWeeksCount, + destinationCountry, + destinationName, + mobilityStatus, + }, + }); } - connection.close(); - console.log("Mobility data inserted/updated successfully."); - return new Response("Data inserted/updated successfully", { - status: 200, - }); + return new Response("Data inserted/updated successfully", { status: 200 }); } catch (error) { console.error("Error inserting mobility data:", error); return new Response("Failed to insert/update data", { status: 500 }); diff --git a/routes/(apps)/students/api/students.ts b/routes/(apps)/students/api/students.ts index 157299f..b71e8e6 100644 --- a/routes/(apps)/students/api/students.ts +++ b/routes/(apps)/students/api/students.ts @@ -1,150 +1,121 @@ import { FreshContext, Handlers } from "$fresh/server.ts"; -import connect from "$root/databases/connect.ts"; +import { db } from "$root/databases/db.ts"; +import { promotions, students } from "$root/databases/schema.ts"; import { AuthenticatedState } from "$root/defaults/interfaces.ts"; -import { Database } from "@db/sqlite"; +import { eq, lt } from "npm:drizzle-orm"; -/** - * Gets itself from the database. - * @param database The database connection - * @param userId The user ID. - * @returns Itself from the database. - */ -function getItself( - database: Database, +async function getItself( userId: string, -): { student: Student | null; promo: Promotion | null } { - const studentQuery = "select * from students where userId = ?"; - const student: Student | undefined = database.prepare(studentQuery).get( - userId, - ); +): 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 promoQuery = "select * from promotions where id = ?"; - const promo: Promotion | undefined = database.prepare(promoQuery).get( - student.promotionId, - ); + const promo = await db + .select() + .from(promotions) + .where(eq(promotions.id, student.promotionId!)) + .limit(1) + .then((rows) => rows[0] ?? null); - return { student, promo: promo ?? null }; + return { student, promo }; } -/** - * Gets itself from the database. - * @param database The database connexion - * @param userId The user ID. - * @returns Itself from the database. - */ -function getAll( - database: Database, -): { students: Student[]; promos: Promotion[] } { - const studentsQuery = ` - select userId, firstName, lastName, mail, promotionId - from students inner join promotions - on students.promotionId = promotions.id - where promotions.current < 6`; - const students: Student[] = database.prepare(studentsQuery).all(); +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 promosQuery = "select * from promotions where promotions.current < 6"; - const promos: Promotion[] | undefined = database.prepare(promosQuery).all(); + const promos = await db + .select() + .from(promotions) + .where(lt(promotions.current, 6)); - return { students, promos }; + return { students: rows as Student[], promos }; } -/** - * Add users to the database. - * @param database The database connexion - * @param students The students to add - * @param promoId The promotion id. - */ -function addStudents(database: Database, students: Student[], promoId: string) { - const query = ` - INSERT INTO students - (userId, firstName, lastName, mail, promotionId) - VALUES (?, ?, ?, ?, ?)`; - - const statement = database.prepare(query); - - for (const student of students) { - statement.run( - student.userId, - student.firstName, - student.lastName, - student.mail, - promoId, - ); +async function addStudents( + studentList: Student[], + promoId: number, +): Promise { + 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 = { - /** - * The students the user can see. - * @param _request The HTTP request. - * @param _context The context with authenticated state. - * @returns All students our user can see. - */ - // deno-lint-ignore require-await async GET( _request: Request, context: FreshContext, ): Promise { - using connection = connect("students"); - const database = connection.database; - if (context.state.session.eduPersonPrimaryAffiliation == "student") { return new Response( - JSON.stringify(getItself(database, context.state.session.uid)), - { - headers: { - "content-type": "application/json", - }, - }, + JSON.stringify(await getItself(context.state.session.uid)), + { headers: { "content-type": "application/json" } }, ); } return new Response( - JSON.stringify(getAll(database)), - { - headers: { - "content-type": "application/json", - }, - }, + JSON.stringify(await getAll()), + { headers: { "content-type": "application/json" } }, ); }, - /** - * Add students in the database. - * @param request The HTTP request. - * @param _context The Fresh context. - * @returns HTTP 201 on successful insert. - */ + async POST( request: Request, _context: FreshContext, ): Promise { - const { students, promo }: { students: Student[]; promo: string } = - await request.json(); + const { students: studentList, promo }: { + students: Student[]; + promo: string; + } = await request.json(); - if (!promo || !promo.match(/^\d{4}-\dA$/) || !Array.isArray(students)) { + if (!promo || !promo.match(/^\d{4}-\dA$/) || !Array.isArray(studentList)) { return new Response(null, { status: 400 }); } - using connection = connect("students"); - const database = connection.database; - const { endyear, current } = promo.match( /^(?\d{4})-(?\d)A$/, )?.groups!; - database.prepare( - "insert or ignore into promotions (endyear, current) values (?, ?)", - ).run(endyear, current); + await db + .insert(promotions) + .values({ endyear: Number(endyear), current: Number(current) }) + .onConflictDoNothing(); - const { id: promoId }: { id: string } = database - .prepare("select id from promotions where endyear = ? and current = ?") - .get(endyear, current)!; + const promo_row = await db + .select() + .from(promotions) + .where(eq(promotions.endyear, Number(endyear))) + .then((rows) => rows.find((r) => r.current === Number(current))!); - addStudents(database, students, promoId); + await addStudents(studentList, promo_row.id); return new Response(null, { status: 201 }); },