feat: newer grades and parameterized queries (#238)

previously, we were using template strings,
which had issues for professors with an apostrophe in their name
This commit is contained in:
Samuel Gunter
2024-09-29 21:15:30 -05:00
committed by GitHub
parent f34dd95d77
commit 75ad4167b6
2 changed files with 37 additions and 17 deletions

View File

@@ -3,6 +3,13 @@ import type { CourseSQLRow, Distribution } from '@shared/types/Distribution';
import { initializeDB } from './initializeDB'; import { initializeDB } from './initializeDB';
type GradeDistributionParams = {
':department_code': string;
':course_number': string;
':instructor_last'?: string;
':semester'?: string;
};
/** /**
* fetches the aggregate distribution of grades for a given course from the course db, and the semesters that we have data for * fetches the aggregate distribution of grades for a given course from the course db, and the semesters that we have data for
* @param course the course to fetch the distribution for * @param course the course to fetch the distribution for
@@ -11,14 +18,14 @@ import { initializeDB } from './initializeDB';
*/ */
export async function queryAggregateDistribution(course: Course): Promise<[Distribution, Semester[], boolean]> { export async function queryAggregateDistribution(course: Course): Promise<[Distribution, Semester[], boolean]> {
const db = await initializeDB(); const db = await initializeDB();
const query = generateQuery(course, null, true); const [query, params] = generateQuery(course, null, true);
let res = db.exec(query)?.[0]; let res = db.exec(query, params)?.[0];
let instructorIncluded = true; let instructorIncluded = true;
if (!res?.columns?.length) { if (!res?.columns?.length) {
instructorIncluded = false; instructorIncluded = false;
const queryWithoutInstructor = generateQuery(course, null, false); const [queryWithoutInstructor, paramsWithoutInstructor] = generateQuery(course, null, false);
res = db.exec(queryWithoutInstructor)?.[0]; res = db.exec(queryWithoutInstructor, paramsWithoutInstructor)?.[0];
if (!res?.columns?.length) { if (!res?.columns?.length) {
throw new NoDataError(course); throw new NoDataError(course);
@@ -87,20 +94,33 @@ export async function queryAggregateDistribution(course: Course): Promise<[Distr
* @param semester the semester to fetch the distribution for OR null if we want the aggregate distribution * @param semester the semester to fetch the distribution for OR null if we want the aggregate distribution
* @returns a SQL query string * @returns a SQL query string
*/ */
function generateQuery(course: Course, semester: Semester | null, includeInstructor: boolean): string { function generateQuery(
const profName = course.instructors[0]?.lastName; course: Course,
semester: Semester | null,
includeInstructor: boolean
): [string, GradeDistributionParams] {
const query = ` const query = `
select * from grade_distributions select * from grade_distributions
where Department_Code = '${course.department}' where Department_Code = :department_code
and Course_Number = '${course.number}' and Course_Number = :course_number
${includeInstructor ? `and Instructor_Last = '${profName}' collate nocase` : ''} ${includeInstructor ? `and Instructor_Last = :instructor_last collate nocase` : ''}
${semester ? `and Semester = '${semester.season} ${semester.year}'` : ''} ${semester ? `and Semester = :semester` : ''}
`; `;
console.log(includeInstructor, { query }); const params: GradeDistributionParams = {
':department_code': course.department,
':course_number': course.number,
};
return query; if (includeInstructor) {
params[':instructor_last'] = course.instructors[0]?.lastName;
}
if (semester) {
params[':semester'] = `${semester.season} ${semester.year}`;
}
return [query, params];
} }
/** /**
@@ -111,14 +131,14 @@ function generateQuery(course: Course, semester: Semester | null, includeInstruc
*/ */
export async function querySemesterDistribution(course: Course, semester: Semester): Promise<[Distribution, boolean]> { export async function querySemesterDistribution(course: Course, semester: Semester): Promise<[Distribution, boolean]> {
const db = await initializeDB(); const db = await initializeDB();
const query = generateQuery(course, semester, true); const [query, params] = generateQuery(course, semester, true);
let res = db.exec(query)?.[0]; let res = db.exec(query, params)?.[0];
let instructorIncluded = true; let instructorIncluded = true;
if (!res?.columns?.length) { if (!res?.columns?.length) {
instructorIncluded = false; instructorIncluded = false;
const queryWithoutInstructor = generateQuery(course, semester, false); const [queryWithoutInstructor, paramsWithoutInstructor] = generateQuery(course, semester, false);
res = db.exec(queryWithoutInstructor)?.[0]; res = db.exec(queryWithoutInstructor, paramsWithoutInstructor)?.[0];
if (!res?.columns?.length) { if (!res?.columns?.length) {
throw new NoDataError(course); throw new NoDataError(course);
} }