Skip to content

Commit

Permalink
hotfix(courses,instructors): correct batch route precedence (#108)
Browse files Browse the repository at this point in the history
## Description

Fix the issue described below, introduced in #101.

## Related Issue

Fix #107.

## Motivation and Context

we can just debug things

## How Has This Been Tested?

Tested on local deployment

## Screenshots (if appropriate):


![image](https://github.com/user-attachments/assets/15396274-8013-4fd2-aeb5-e2a63b269474)


![Screenshot_20250202_214836](https://github.com/user-attachments/assets/c84820aa-5889-416d-9b5d-6699d5394276)

## Types of changes

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)

## Checklist:

- [ ] My code involves a change to the database schema.
- [ ] My code requires a change to the documentation.
  • Loading branch information
laggycomputer authored Feb 3, 2025
1 parent dc9c248 commit 8e8608b
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 82 deletions.
8 changes: 4 additions & 4 deletions apps/api/src/graphql/resolvers/courses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { GraphQLError } from "graphql/error";

export const coursesResolvers = {
Query: {
batchCourses: async (_: unknown, { ids }: { ids: string[] }, { db }: GraphQLContext) => {
const service = new CoursesService(db);
return await service.batchGetCourses(ids);
},
course: async (_: unknown, { id }: { id: string }, { db }: GraphQLContext) => {
const service = new CoursesService(db);
const res = await service.getCourseById(id);
if (!res)
throw new GraphQLError(`Course '${id}' not found`, { extensions: { code: "NOT_FOUND" } });
return res;
},
batchCourses: async (_: unknown, { ids }: { ids: string[] }, { db }: GraphQLContext) => {
const service = new CoursesService(db);
return await service.batchGetCourses(ids);
},
courses: async (_: unknown, args: { query: unknown }, { db }: GraphQLContext) => {
const service = new CoursesService(db);
return await service.getCourses(coursesQuerySchema.parse(args.query));
Expand Down
16 changes: 8 additions & 8 deletions apps/api/src/graphql/resolvers/instructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import { GraphQLError } from "graphql/error";

export const instructorsResolvers = {
Query: {
batchInstructors: async (
_: unknown,
{ ucinetids }: { ucinetids: string[] },
{ db }: GraphQLContext,
) => {
const service = new InstructorsService(db);
return await service.batchGetInstructors(ucinetids);
},
instructor: async (_: unknown, { ucinetid }: { ucinetid: string }, { db }: GraphQLContext) => {
const service = new InstructorsService(db);
const res = await service.getInstructorByUCInetID(ucinetid);
Expand All @@ -14,14 +22,6 @@ export const instructorsResolvers = {
});
return res;
},
batchInstructors: async (
_: unknown,
{ ucinetids }: { ucinetids: string[] },
{ db }: GraphQLContext,
) => {
const service = new InstructorsService(db);
return await service.batchGetInstructors(ucinetids);
},
instructors: async (_: unknown, args: { query: unknown }, { db }: GraphQLContext) => {
const service = new InstructorsService(db);
return await service.getInstructors(instructorsQuerySchema.parse(args.query));
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/graphql/schema/courses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ input CoursesByCursorQuery {
}
extend type Query {
batchCourses(ids: [String!]!): [Course!]!
course(id: String!): Course!
courses(query: CoursesQuery!): [Course!]!
batchCourses(ids: [String!]!): [Course!]!
coursesByCursor(query: CoursesByCursorQuery!): CoursesByCursor!
}
`;
2 changes: 1 addition & 1 deletion apps/api/src/graphql/schema/instructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ input InstructorsByCursorQuery {
}
extend type Query {
batchInstructors(ucinetids: [String!]!): [Instructor!]!
instructor(ucinetid: String!): Instructor!
instructors(query: InstructorsQuery!): [Instructor!]!
batchInstructors(ucinetids: [String!]!): [Instructor!]!
instructorsByCursor(query: InstructorsByCursorQuery!): InstructorsByCursor!
}
`;
58 changes: 29 additions & 29 deletions apps/api/src/rest/routes/courses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,21 @@ const coursesCursorRouter = new OpenAPIHono<{ Bindings: Env }>({ defaultHook });
coursesRouter.openAPIRegistry.register("prereq", prerequisiteSchema);
coursesRouter.openAPIRegistry.register("prereqTree", prerequisiteTreeSchema);

const courseByIdRoute = createRoute({
summary: "Retrieve a course",
operationId: "courseById",
const batchCoursesRoute = createRoute({
summary: "Retrieve courses with IDs",
operationId: "batchCourses",
tags: ["Courses"],
method: "get",
path: "/{id}",
request: { params: coursesPathSchema },
description: "Retrieves a course by its ID.",
path: "/batch",
request: { query: batchCoursesQuerySchema },
description: "Retrieves courses with the IDs provided",
responses: {
200: {
content: { "application/json": { schema: responseSchema(courseSchema) } },
content: {
"application/json": { schema: responseSchema(courseSchema.array()) },
},
description: "Successful operation",
},
404: {
content: { "application/json": { schema: errorSchema } },
description: "Course not found",
},
422: {
content: { "application/json": { schema: errorSchema } },
description: "Parameters failed validation",
Expand All @@ -50,21 +48,23 @@ const courseByIdRoute = createRoute({
},
});

const batchCoursesRoute = createRoute({
summary: "Retrieve courses with IDs",
operationId: "batchCourses",
const courseByIdRoute = createRoute({
summary: "Retrieve a course",
operationId: "courseById",
tags: ["Courses"],
method: "get",
path: "/batch",
request: { query: batchCoursesQuerySchema },
description: "Retrieves courses with the IDs provided",
path: "/{id}",
request: { params: coursesPathSchema },
description: "Retrieves a course by its ID.",
responses: {
200: {
content: {
"application/json": { schema: responseSchema(courseSchema.array()) },
},
content: { "application/json": { schema: responseSchema(courseSchema) } },
description: "Successful operation",
},
404: {
content: { "application/json": { schema: errorSchema } },
description: "Course not found",
},
422: {
content: { "application/json": { schema: errorSchema } },
description: "Parameters failed validation",
Expand Down Expand Up @@ -133,15 +133,6 @@ coursesRouter.get(
productionCache({ cacheName: "anteater-api", cacheControl: "max-age=86400" }),
);

coursesRouter.openapi(courseByIdRoute, async (c) => {
const { id } = c.req.valid("param");
const service = new CoursesService(database(c.env.DB.connectionString));
const res = await service.getCourseById(id);
return res
? c.json({ ok: true, data: courseSchema.parse(res) }, 200)
: c.json({ ok: false, message: `Course ${id} not found` }, 404);
});

coursesRouter.openapi(batchCoursesRoute, async (c) => {
const { ids } = c.req.valid("query");
const service = new CoursesService(database(c.env.DB.connectionString));
Expand All @@ -154,6 +145,15 @@ coursesRouter.openapi(batchCoursesRoute, async (c) => {
);
});

coursesRouter.openapi(courseByIdRoute, async (c) => {
const { id } = c.req.valid("param");
const service = new CoursesService(database(c.env.DB.connectionString));
const res = await service.getCourseById(id);
return res
? c.json({ ok: true, data: courseSchema.parse(res) }, 200)
: c.json({ ok: false, message: `Course ${id} not found` }, 404);
});

coursesRouter.openapi(coursesByFiltersRoute, async (c) => {
const query = c.req.valid("query");
const service = new CoursesService(database(c.env.DB.connectionString));
Expand Down
58 changes: 29 additions & 29 deletions apps/api/src/rest/routes/instructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,23 @@ const instructorsCursorRouter = new OpenAPIHono<{ Bindings: Env }>({
defaultHook,
});

const instructorByIdRoute = createRoute({
summary: "Retrieve a instructor",
operationId: "instructorById",
const batchInstructorsRoute = createRoute({
summary: "Retrieve instructors with UCINetIDs",
operationId: "batchInstructors",
tags: ["Instructors"],
method: "get",
path: "/{ucinetid}",
request: { params: instructorsPathSchema },
description: "Retrieves an instructor by their UCInetID.",
path: "/batch",
request: { query: batchInstructorsQuerySchema },
description: "Retrieves instructors with the UCINetIDs provided.",
responses: {
200: {
content: {
"application/json": { schema: responseSchema(instructorSchema) },
"application/json": {
schema: responseSchema(instructorSchema.array()),
},
},
description: "Successful operation",
},
404: {
content: { "application/json": { schema: errorSchema } },
description: "Instructor not found",
},
422: {
content: { "application/json": { schema: errorSchema } },
description: "Parameters failed validation",
Expand All @@ -51,23 +49,25 @@ const instructorByIdRoute = createRoute({
},
});

const batchInstructorsRoute = createRoute({
summary: "Retrieve instructors with UCINetIDs",
operationId: "batchInstructors",
const instructorByIdRoute = createRoute({
summary: "Retrieve a instructor",
operationId: "instructorById",
tags: ["Instructors"],
method: "get",
path: "/batch",
request: { query: batchInstructorsQuerySchema },
description: "Retrieves instructors with the UCINetIDs provided.",
path: "/{ucinetid}",
request: { params: instructorsPathSchema },
description: "Retrieves an instructor by their UCInetID.",
responses: {
200: {
content: {
"application/json": {
schema: responseSchema(instructorSchema.array()),
},
"application/json": { schema: responseSchema(instructorSchema) },
},
description: "Successful operation",
},
404: {
content: { "application/json": { schema: errorSchema } },
description: "Instructor not found",
},
422: {
content: { "application/json": { schema: errorSchema } },
description: "Parameters failed validation",
Expand Down Expand Up @@ -138,15 +138,6 @@ instructorsRouter.get(
productionCache({ cacheName: "anteater-api", cacheControl: "max-age=86400" }),
);

instructorsRouter.openapi(instructorByIdRoute, async (c) => {
const { ucinetid } = c.req.valid("param");
const service = new InstructorsService(database(c.env.DB.connectionString));
const res = await service.getInstructorByUCInetID(ucinetid);
return res
? c.json({ ok: true, data: instructorSchema.parse(res) }, 200)
: c.json({ ok: false, message: `Instructor ${ucinetid} not found` }, 404);
});

instructorsRouter.openapi(batchInstructorsRoute, async (c) => {
const { ucinetids } = c.req.valid("query");
const service = new InstructorsService(database(c.env.DB.connectionString));
Expand All @@ -159,6 +150,15 @@ instructorsRouter.openapi(batchInstructorsRoute, async (c) => {
);
});

instructorsRouter.openapi(instructorByIdRoute, async (c) => {
const { ucinetid } = c.req.valid("param");
const service = new InstructorsService(database(c.env.DB.connectionString));
const res = await service.getInstructorByUCInetID(ucinetid);
return res
? c.json({ ok: true, data: instructorSchema.parse(res) }, 200)
: c.json({ ok: false, message: `Instructor ${ucinetid} not found` }, 404);
});

instructorsRouter.openapi(instructorsByFiltersRoute, async (c) => {
const query = c.req.valid("query");
const service = new InstructorsService(database(c.env.DB.connectionString));
Expand Down
8 changes: 4 additions & 4 deletions apps/api/src/services/courses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,14 @@ export class CoursesService {
.then((courses) => courses.map(transformCourse));
}

async getCourseById(id: string): Promise<CoursesServiceOutput | null> {
return this.getCoursesRaw({ where: eq(courseView.id, id) }).then((x) => orNull(x[0]));
}

async batchGetCourses(ids: string[]): Promise<CoursesServiceOutput[]> {
return this.getCoursesRaw({ where: inArray(courseView.id, ids), limit: ids.length });
}

async getCourseById(id: string): Promise<CoursesServiceOutput | null> {
return this.getCoursesRaw({ where: eq(courseView.id, id) }).then((x) => orNull(x[0]));
}

async getCourses(input: CoursesServiceInput): Promise<CoursesServiceOutput[]> {
return this.getCoursesRaw({
where: buildQuery(input),
Expand Down
12 changes: 6 additions & 6 deletions apps/api/src/services/instructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,19 @@ export class InstructorsService {
.limit(limit ?? 1)) as InstructorsServiceOutput[];
}

async getInstructorByUCInetID(ucinetid: string): Promise<InstructorsServiceOutput | null> {
return this.getInstructorsRaw({
where: and(eq(instructorView.ucinetid, ucinetid)),
}).then((xs) => orNull(xs[0]));
}

async batchGetInstructors(ucinetids: string[]): Promise<InstructorsServiceOutput[]> {
return this.getInstructorsRaw({
where: inArray(instructorView.ucinetid, ucinetids),
limit: ucinetids.length,
});
}

async getInstructorByUCInetID(ucinetid: string): Promise<InstructorsServiceOutput | null> {
return this.getInstructorsRaw({
where: and(eq(instructorView.ucinetid, ucinetid)),
}).then((xs) => orNull(xs[0]));
}

async getInstructors(input: InstructorsServiceInput): Promise<InstructorsServiceOutput[]> {
return this.getInstructorsRaw({
where: buildQuery(input),
Expand Down

0 comments on commit 8e8608b

Please sign in to comment.