Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
5336574
refactored RuleBase type to have a nullable proxyAdvice
HwijungK Jan 28, 2026
70da258
added degreeworksSpecRequirment to schema
HwijungK Jan 28, 2026
1a05141
added ifElsePart property to RuleBase
HwijungK Jan 28, 2026
bddc87a
push DWSpecRequirement when encountering match in ruleArrayToReq
HwijungK Jan 28, 2026
a761de2
added requireSpec to schema
HwijungK Jan 28, 2026
480abb6
migrated db and did some pg testing
HwijungK Jan 29, 2026
6359bdb
updated pnpm
HwijungK Jan 29, 2026
cf4e1a0
added requireSpec field to graphql schema
HwijungK Jan 29, 2026
9b396a7
made requireSpec a nonnullable type
HwijungK Jan 29, 2026
5bcd14e
remigrated db after making requireSpec nonNullable
HwijungK Jan 29, 2026
e8f271c
added comments for evaluating spec req
HwijungK Feb 1, 2026
02106bb
filtered out DegreeworksSpecRequirement when adding to db to reduce r…
HwijungK Feb 7, 2026
b1744ff
removed 2 migrations so that we could redo
HwijungK Feb 7, 2026
50e0f4f
reran migration with --name flag
HwijungK Feb 7, 2026
ba20f4f
refactored parsedPrograms to store majorDegrees of (major, spec) pairs
HwijungK Feb 10, 2026
c7c3997
save found major, spec pairs when finding specs
HwijungK Feb 10, 2026
c561897
temp commit, upserting is currently broken
HwijungK Feb 10, 2026
ae555a4
Merge branch 'main' into polymorphic-majors
HwijungK Feb 13, 2026
a32e91a
encoded parsed Program key into a string instead of a list so that ma…
HwijungK Feb 14, 2026
a42d151
saved spec_id in major_requirement in coorect - format to match with …
HwijungK Feb 14, 2026
c44cba0
feat: changed schema to contain major_spec_pair_to_requirement table …
HwijungK Feb 14, 2026
11c23a5
Auogenerate id in major_spec_pair_to_requirement table
HwijungK Feb 15, 2026
f9e8b26
db migration
HwijungK Feb 15, 2026
0fbcf18
deleted outdated numbered migration files
HwijungK Feb 15, 2026
e621ebf
Merge branch 'main' into optional-spec
HwijungK Feb 15, 2026
97f7985
re-migrated
HwijungK Feb 15, 2026
bd47eaa
made specRequirement a subtype of markerRequirement
HwijungK Feb 15, 2026
2b81a70
hard coded setting ChemE to have opitonal Specs
HwijungK Feb 15, 2026
1a56be0
refactored major_requirement table to use hashed json as its primary key
HwijungK Feb 15, 2026
b67922f
removed debug logs used during testing
HwijungK Feb 15, 2026
950864c
reran migration
HwijungK Feb 15, 2026
d4171d3
seperated parsing of specialization requirement to different function
HwijungK Feb 21, 2026
c236259
added requiresSpecialization member to Degree Works Program Type
HwijungK Feb 21, 2026
0dd2141
refactored index to get requiredSpecialization data from the Degreeor…
HwijungK Feb 21, 2026
8393667
removed DegreeWorksRequireSpecialization type
HwijungK Feb 21, 2026
b363c76
refactored hard coding requirespec to false for chemE major
HwijungK Feb 21, 2026
d56e89c
removed migrations for merge
HwijungK Feb 21, 2026
4c21532
Merge branch 'main' into optional-spec
HwijungK Feb 21, 2026
5fcca0a
reverted packaageManager update
HwijungK Feb 21, 2026
fd8a69b
renamed require_spec to specialization_required
HwijungK Feb 21, 2026
b203d33
set specializationRequired to false if the program doesn't have any s…
HwijungK Feb 21, 2026
6155d8a
renamed function in Audit parser
HwijungK Feb 21, 2026
47adb63
cleaned code in checking for required specs
HwijungK Feb 21, 2026
3c23a25
cleaned code for filtering out 0 spec programs with specializationReq…
HwijungK Feb 21, 2026
88ef8cf
updated comment in schema
HwijungK Feb 21, 2026
587cba2
updated comment in schema
HwijungK Feb 21, 2026
d7b193d
fixed bug in pushing to specs from spec-cache
HwijungK Feb 22, 2026
0e377e9
Merge branch 'optional-spec' of github.com:icssc/anteater-api into op…
HwijungK Feb 22, 2026
68960ee
Merge branch 'optional-spec' of github.com:icssc/anteater-api into op…
HwijungK Feb 22, 2026
b3cc6e0
refactored spec-cache type to store major as a programRequirement ins…
HwijungK Feb 22, 2026
efef8b5
Merge branch 'optional-spec' of github.com:icssc/anteater-api into op…
HwijungK Feb 22, 2026
6f593b3
update comments
HwijungK Feb 22, 2026
e83d798
update comments
HwijungK Feb 22, 2026
2f07907
removed redundant parsing of programs in post-proccessing step
HwijungK Feb 22, 2026
e0d6f52
Merge branch 'optional-spec' of github.com:icssc/anteater-api into op…
HwijungK Feb 22, 2026
715875a
Merge branch 'optional-spec' into polymorphic-majors
HwijungK Feb 15, 2026
43e193b
Merge branch 'optional-spec' into polymorphic-majors
HwijungK Feb 23, 2026
063f3a2
still push specs into programs
HwijungK Feb 23, 2026
43c6aa6
moved specCodes into MajorProgram type
HwijungK Feb 23, 2026
517606c
Revert "still push specs into programs"
HwijungK Feb 23, 2026
7ad24f3
Revert "moved specCodes into MajorProgram type"
HwijungK Feb 23, 2026
f3ff2d2
Revert "Revert "still push specs into programs""
HwijungK Feb 23, 2026
38d60a8
converted programTriplets into programQuadruplets by adding spec code
HwijungK Feb 23, 2026
1fc8bb6
refacotred MajorProgram type to be an object with added specId property
HwijungK Feb 23, 2026
edc450e
added specId to MajorProgram
HwijungK Feb 23, 2026
00ef310
moved hard coding of chemE optional spec into audit parser instead of…
HwijungK Feb 23, 2026
9cc6e46
added specialization id parameter to rest endpoint for major req
HwijungK Feb 23, 2026
5dfa44a
refactored service to not cause compile error
HwijungK Feb 23, 2026
fa72438
implemented graphql endpoints
HwijungK Feb 24, 2026
df9425c
clearer description for specializationID parameter
HwijungK Feb 24, 2026
1dc6b07
reorganized conditional structure of services
HwijungK Feb 24, 2026
1d6dd56
reset delay on DW client to 1000
HwijungK Feb 24, 2026
fbd2fe4
removed debugging comments from dw index
HwijungK Feb 24, 2026
eff2c3d
changed 'spec' into 'specCode'
HwijungK Feb 24, 2026
046230d
updated comments in scraper
HwijungK Feb 24, 2026
34c0db8
moved chemE optional specialization special case handling into AP
HwijungK Feb 24, 2026
9f56859
renamed regex into screaming snake case
HwijungK Feb 24, 2026
7a292e6
fixed typo
HwijungK Feb 24, 2026
8077783
migration
HwijungK Feb 27, 2026
10e8e99
goldylocks
HwijungK Mar 1, 2026
afce1a0
spellcheck TT
HwijungK Mar 1, 2026
bc58c62
merged optional specs into polymorphic majors
HwijungK Mar 1, 2026
00b64ac
cleaned up comment in schema for MajorProgram Type
HwijungK Mar 1, 2026
f3f4092
graphql specializationId is optional
HwijungK Mar 2, 2026
493da8f
fixed schoolRequirement typo
HwijungK Mar 2, 2026
b2d1778
changed response for when a major spec pair is not found
HwijungK Mar 2, 2026
1825709
converted key of parsedPrograms into a template literal type
HwijungK Mar 5, 2026
9fd770f
refactored programQuadruplet into ProgramCodes type
HwijungK Mar 5, 2026
22b77a8
push found programs with spec into existing parsedPrograms list
HwijungK Mar 5, 2026
0230efd
made docs for major and major requirement endpoint clearer
HwijungK Mar 5, 2026
4771309
make program service more 'drizzle-onic'
HwijungK Mar 5, 2026
c92cee7
logging stuff
HwijungK Mar 5, 2026
19cb482
used asmajorSpecId to create parsedProgram keys where originally missed
HwijungK Mar 5, 2026
3e78581
merged main into polymorphic majors
HwijungK Mar 9, 2026
ac7051f
doc changes
HwijungK Mar 9, 2026
730e009
minor doc and cleaning changes
HwijungK Mar 9, 2026
19cc8d4
Update apps/api/src/rest/routes/programs.ts
HwijungK Mar 9, 2026
847e2e3
removed local sql file
HwijungK Mar 9, 2026
8c6b5e7
Merge branch 'polymorphic-majors' of github.com:icssc/anteater-api in…
HwijungK Mar 9, 2026
54e5d89
yet additional doc changes. bless me with english TT
HwijungK Mar 9, 2026
a4bd0ad
better error logs on graphql logs and delete migration to sync with main
HwijungK Mar 16, 2026
7947166
Merge branch 'main' into polymorphic-majors
HwijungK Mar 16, 2026
e1c9ddb
remigrate and fix dwClient majorAudit bug
HwijungK Mar 22, 2026
bd21520
final i hope
HwijungK Mar 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions apps/api/src/graphql/resolvers/programs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ export const programResolvers = {
const service = new ProgramsService(db);
const res = await service.getMajorRequirements(parsedArgs);
if (!res)
throw new GraphQLError(`Major ${parsedArgs.programId} not found`, {
extensions: { code: "NOT_FOUND" },
});
throw new GraphQLError(
`No requirements found for major ${parsedArgs.programId}${parsedArgs.specializationId ? ` with specialization ${parsedArgs.specializationId}` : ""}.`,
{
extensions: { code: "NOT_FOUND" },
},
);
return res;
},
minor: async (_: unknown, args: { query?: unknown }, { db }: GraphQLContext) => {
Expand Down
7 changes: 6 additions & 1 deletion apps/api/src/graphql/schema/programs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ type UgradRequirements @cacheControl(maxAge: 86400) {
requirements: [ProgramRequirement!]!,
}

input MajorRequirementsQuery {
programId: String!
specializationId: String
}

input ProgramRequirementsQuery {
programId: String!
}
Expand All @@ -130,7 +135,7 @@ extend type Query {
majors(query: MajorsQuery): [MajorPreview!]!
minors(query: MinorsQuery): [MinorPreview!]!
specializations(query: SpecializationsQuery): [SpecializationPreview!]!
major(query: ProgramRequirementsQuery!): Major!
major(query: MajorRequirementsQuery!): Major!
minor(query: ProgramRequirementsQuery!): Minor!
specialization(query: ProgramRequirementsQuery!): Specialization!
ugradRequirements(query: UgradRequrementsQuery!): UgradRequirements!
Expand Down
7 changes: 3 additions & 4 deletions apps/api/src/rest/routes/programs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ const majorRequirements = createRoute({
tags: ["Programs"],
method: "get",
path: "/major",
description:
"Retrieve course requirements for a major in UCI's current catalogue. Note that these are the requirements for the major itself; " +
"if this major has specializations, then one is mandatory and its requirements apply as well.",
description: "Retrieve course requirements for a major in UCI's current catalogue.",
request: { query: majorRequirementsQuerySchema },
responses: {
200: response200(majorRequirementsResponseSchema),
Expand Down Expand Up @@ -190,7 +188,8 @@ programsRouter.openapi(majorRequirements, async (c) => {
: c.json(
{
ok: false,
message: "Couldn't find this major; check your ID?",
message:
"Couldn't find major requirements associated with this major and specialization; check your IDs?",
},
404,
);
Expand Down
8 changes: 6 additions & 2 deletions apps/api/src/schema/programs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export const majorRequirementsQuerySchema = z.object({
description: "A major ID to query requirements for",
example: "BS-201",
}),
specializationId: programIdBase.optional().openapi({
description:
"if provided, fetch major requirements given this specialization; providing no specialization when one is required has unspecified behavior",
example: "BS-201A",
}),
});

export const minorRequirementsQuerySchema = z.object({
Expand Down Expand Up @@ -200,8 +205,7 @@ export const majorsResponseSchema = z.array(
description: "Whether a specialization must be completed to complete this degree",
}),
specializations: z.array(z.string()).openapi({
description:
"The ID(s) of specialization(s) associated with this major; if any are present, one is mandatory for this major.",
description: "The ID(s) of specialization(s) associated with this major",
example: [
"BS-201A",
"BS-201B",
Expand Down
60 changes: 39 additions & 21 deletions apps/api/src/services/programs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import type {
ugradRequirementsQuerySchema,
} from "$schema";
import type { database } from "@packages/db";
import { eq, sql } from "@packages/db/drizzle";
import { and, eq, sql } from "@packages/db/drizzle";
import {
catalogProgram,
collegeRequirement,
degree,
major,
majorRequirement,
majorSpecializationToRequirement,
minor,
sampleProgramVariation,
schoolRequirement,
Expand Down Expand Up @@ -102,32 +104,48 @@ export class ProgramsService {
programType: "specialization";
query: z.infer<typeof specializationRequirementsQuerySchema>;
}) {
if (programType === "major") {
const [got] = await this.db
.select({
id: major.id,
name: major.name,
requirements: majorRequirement.requirements,
schoolRequirements: {
name: collegeRequirement.name,
requirements: collegeRequirement.requirements,
},
})
.from(major)
.where(
and(
eq(major.id, query.programId),
query.specializationId
? eq(majorSpecializationToRequirement.specId, query.specializationId)
: undefined,
),
)
.leftJoin(collegeRequirement, eq(major.collegeRequirement, collegeRequirement.id))
.leftJoin(
majorSpecializationToRequirement,
eq(major.id, majorSpecializationToRequirement.majorId),
)
.leftJoin(
majorRequirement,
eq(majorSpecializationToRequirement.requirementId, majorRequirement.id),
)
.limit(1);
return orNull(got);
}

const table = {
major,
minor,
specialization,
}[programType];

const [got] = await (programType !== "major"
? this.db
.select({ id: table.id, name: table.name, requirements: table.requirements })
.from(table)
: this.db
.select({
id: major.id,
name: major.name,
requirements: major.requirements,
schoolRequirements: {
name: collegeRequirement.name,
requirements: collegeRequirement.requirements,
},
})
.from(major)
.leftJoin(collegeRequirement, eq(major.collegeRequirement, collegeRequirement.id))
)
const [got] = await this.db
.select({ id: table.id, name: table.name, requirements: table.requirements })
.from(table)
.where(eq(table.id, query.programId))
.limit(1);

return orNull(got);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@ export class DegreeworksClient {
* @param degree a degree code, e.g. "BS"
* @param school this corresponds to the UCI notion of division, e.g. "U" or "G"
* @param majorCode a major code
* @param specCode a specialization code
* @param college this corresponds to the UCI notion of school, e.g. 55 for the school of bio sci
*/
async getMajorAudit(
degree: string,
school: string,
majorCode: string,
specCode?: string,
Comment on lines 104 to +107
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More than one optional argument gets a little messy, especially if we add/reorder them. Do you want to pass in some kind of object instead? We could also leave this in if you don't care enough

college?: string,
): Promise<
| {
Expand All @@ -122,6 +124,7 @@ export class DegreeworksClient {
goals: [
{ code: "MAJOR", value: majorCode },
...(college ? [{ code: "COLLEGE", value: college }] : []),
...(specCode ? [{ code: "SPEC", value: specCode }] : []),
],
}),
headers: this.headers,
Expand Down
Loading
Loading