Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catalog fixes: Course, classes, and sections #706

Open
wants to merge 2 commits into
base: gql
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 18 additions & 18 deletions backend/src/generated-types/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type CatalogClass = {

export type CatalogItem = {
__typename?: 'CatalogItem';
classes: Array<Maybe<CatalogClass>>;
classes: Array<CatalogClass>;
description: Scalars['String'];
gradeAverage?: Maybe<Scalars['Float']>;
lastUpdated: Scalars['ISODate'];
Expand All @@ -55,7 +55,7 @@ export type Class = {
number: Scalars['String'];
primarySection: Section;
raw: Scalars['JSONObject'];
sections: Array<Maybe<Section>>;
sections: Array<Section>;
semester: Semester;
session: Scalars['String'];
status: Scalars['String'];
Expand All @@ -70,8 +70,8 @@ export type Class = {
/** Info shared between Classes within and across semesters. */
export type Course = {
__typename?: 'Course';
classes: Array<Maybe<Class>>;
crossListing?: Maybe<Array<Maybe<Course>>>;
classes: Array<Class>;
crossListing?: Maybe<Array<Course>>;
description: Scalars['String'];
fromDate: Scalars['String'];
gradeAverage?: Maybe<Scalars['Float']>;
Expand All @@ -81,7 +81,7 @@ export type Course = {
number: Scalars['String'];
prereqs?: Maybe<Scalars['String']>;
raw: Scalars['JSONObject'];
sections: Array<Maybe<Section>>;
sections: Array<Section>;
subject: Scalars['String'];
subjectName: Scalars['String'];
title: Scalars['String'];
Expand Down Expand Up @@ -202,15 +202,15 @@ export type Query = {
*
* Used primarily in the catalog page.
*/
catalog?: Maybe<Array<Maybe<CatalogItem>>>;
catalog?: Maybe<Array<CatalogItem>>;
class?: Maybe<Class>;
course?: Maybe<Course>;
/**
* Get a list of all course names across all semesters.
*
* Useful for searching for courses.
*/
courseList?: Maybe<Array<Maybe<CourseListItem>>>;
courseList?: Maybe<Array<CourseListItem>>;
grade?: Maybe<Grade>;
/** @deprecated test */
ping: Scalars['String'];
Expand Down Expand Up @@ -310,8 +310,8 @@ export type Section = {
days?: Maybe<Array<Scalars['Boolean']>>;
enrollCount: Scalars['Int'];
enrollMax: Scalars['Int'];
enrollmentHistory?: Maybe<Array<Maybe<EnrollmentDay>>>;
instructors?: Maybe<Array<Maybe<Instructor>>>;
enrollmentHistory?: Maybe<Array<EnrollmentDay>>;
instructors?: Maybe<Array<Instructor>>;
kind: Scalars['String'];
lastUpdated: Scalars['ISODate'];
location?: Maybe<Scalars['String']>;
Expand Down Expand Up @@ -550,7 +550,7 @@ export type CatalogClassResolvers<ContextType = any, ParentType extends Resolver
};

export type CatalogItemResolvers<ContextType = any, ParentType extends ResolversParentTypes['CatalogItem'] = ResolversParentTypes['CatalogItem']> = {
classes?: Resolver<Array<Maybe<ResolversTypes['CatalogClass']>>, ParentType, ContextType>;
classes?: Resolver<Array<ResolversTypes['CatalogClass']>, ParentType, ContextType>;
description?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
gradeAverage?: Resolver<Maybe<ResolversTypes['Float']>, ParentType, ContextType>;
lastUpdated?: Resolver<ResolversTypes['ISODate'], ParentType, ContextType>;
Expand All @@ -569,7 +569,7 @@ export type ClassResolvers<ContextType = any, ParentType extends ResolversParent
number?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
primarySection?: Resolver<ResolversTypes['Section'], ParentType, ContextType>;
raw?: Resolver<ResolversTypes['JSONObject'], ParentType, ContextType>;
sections?: Resolver<Array<Maybe<ResolversTypes['Section']>>, ParentType, ContextType>;
sections?: Resolver<Array<ResolversTypes['Section']>, ParentType, ContextType>;
semester?: Resolver<ResolversTypes['Semester'], ParentType, ContextType>;
session?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
status?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
Expand All @@ -583,8 +583,8 @@ export type ClassResolvers<ContextType = any, ParentType extends ResolversParent
};

export type CourseResolvers<ContextType = any, ParentType extends ResolversParentTypes['Course'] = ResolversParentTypes['Course']> = {
classes?: Resolver<Array<Maybe<ResolversTypes['Class']>>, ParentType, ContextType, Partial<CourseClassesArgs>>;
crossListing?: Resolver<Maybe<Array<Maybe<ResolversTypes['Course']>>>, ParentType, ContextType>;
classes?: Resolver<Array<ResolversTypes['Class']>, ParentType, ContextType, Partial<CourseClassesArgs>>;
crossListing?: Resolver<Maybe<Array<ResolversTypes['Course']>>, ParentType, ContextType>;
description?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
fromDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
gradeAverage?: Resolver<Maybe<ResolversTypes['Float']>, ParentType, ContextType>;
Expand All @@ -594,7 +594,7 @@ export type CourseResolvers<ContextType = any, ParentType extends ResolversParen
number?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
prereqs?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
raw?: Resolver<ResolversTypes['JSONObject'], ParentType, ContextType>;
sections?: Resolver<Array<Maybe<ResolversTypes['Section']>>, ParentType, ContextType, Partial<CourseSectionsArgs>>;
sections?: Resolver<Array<ResolversTypes['Section']>, ParentType, ContextType, Partial<CourseSectionsArgs>>;
subject?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
subjectName?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
title?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
Expand Down Expand Up @@ -666,10 +666,10 @@ export type MutationResolvers<ContextType = any, ParentType extends ResolversPar
};

export type QueryResolvers<ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
catalog?: Resolver<Maybe<Array<Maybe<ResolversTypes['CatalogItem']>>>, ParentType, ContextType, RequireFields<QueryCatalogArgs, 'term'>>;
catalog?: Resolver<Maybe<Array<ResolversTypes['CatalogItem']>>, ParentType, ContextType, RequireFields<QueryCatalogArgs, 'term'>>;
class?: Resolver<Maybe<ResolversTypes['Class']>, ParentType, ContextType, RequireFields<QueryClassArgs, 'classNumber' | 'courseNumber' | 'subject' | 'term'>>;
course?: Resolver<Maybe<ResolversTypes['Course']>, ParentType, ContextType, RequireFields<QueryCourseArgs, 'courseNumber' | 'subject'>>;
courseList?: Resolver<Maybe<Array<Maybe<ResolversTypes['CourseListItem']>>>, ParentType, ContextType>;
courseList?: Resolver<Maybe<Array<ResolversTypes['CourseListItem']>>, ParentType, ContextType>;
grade?: Resolver<Maybe<ResolversTypes['Grade']>, ParentType, ContextType, RequireFields<QueryGradeArgs, 'courseNum' | 'subject'>>;
ping?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
scheduleByID?: Resolver<Maybe<ResolversTypes['Schedule']>, ParentType, ContextType, RequireFields<QueryScheduleByIdArgs, 'id'>>;
Expand Down Expand Up @@ -700,8 +700,8 @@ export type SectionResolvers<ContextType = any, ParentType extends ResolversPare
days?: Resolver<Maybe<Array<ResolversTypes['Boolean']>>, ParentType, ContextType>;
enrollCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
enrollMax?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
enrollmentHistory?: Resolver<Maybe<Array<Maybe<ResolversTypes['EnrollmentDay']>>>, ParentType, ContextType>;
instructors?: Resolver<Maybe<Array<Maybe<ResolversTypes['Instructor']>>>, ParentType, ContextType>;
enrollmentHistory?: Resolver<Maybe<Array<ResolversTypes['EnrollmentDay']>>, ParentType, ContextType>;
instructors?: Resolver<Maybe<Array<ResolversTypes['Instructor']>>, ParentType, ContextType>;
kind?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
lastUpdated?: Resolver<ResolversTypes['ISODate'], ParentType, ContextType>;
location?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
Expand Down
59 changes: 47 additions & 12 deletions backend/src/modules/catalog/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,46 @@ export function getPrimarySection(id: string, term: TermInput, classNumber: stri
}

export function getClassSections(id: string, term: TermInput, classNumber: string) {
// for associated sections with a lecture. Lecture assumed to be of form 00x
return SectionModel
.find({
"class.course.identifiers": matchCsCourseId(id),
"class.session.term.name": termToString(term),
"class.number": classNumber
$or: [
{"class.number": {$regex: new RegExp("^"+classNumber[classNumber.length-1])}},
{"class.number": "999"}
]
})
.lean()
.then(s => s.map(formatSection))
}

export function getCourse(subject: string, courseNumber: string, term?: TermInput | null) {
async function getCourseFromFilter(filter: any, term?: TermInput | null, info?: GraphQLResolveInfo | null) {

const course = await CourseModel
.findOne(filter)
.sort({ fromDate: -1 })
.lean()
.then(c => formatCourse(c, term))

if (info && getChildren(info).includes("gradeAverage")) {

const grades : GradeType[] = []
const gradesQuery = await GradeModel.find({
"CourseSubjectShortNm": course.raw.classSubjectArea?.description ?? course.raw.subjectArea?.description,
"CourseNumber": course.raw.catalogNumber?.formatted
}, {GradeNm: 1, EnrollmentCnt: 1})
for (const grade of gradesQuery) {
grades.push(grade)
}
course.gradeAverage = await getAverage(grades)

}

return course
}

export function getCourse(subject: string, courseNumber: string, term?: TermInput | null, info?: GraphQLResolveInfo) {
const filter: any = {
"classSubjectArea.code": subject,
"catalogNumber.formatted": courseNumber
Expand All @@ -180,11 +209,7 @@ export function getCourse(subject: string, courseNumber: string, term?: TermInpu
filter.fromDate = { $lte: getTermStartMonth(term) }
}

return CourseModel
.findOne(filter)
.sort({ fromDate: -1 })
.lean()
.then(c => formatCourse(c, term))
return getCourseFromFilter(filter, term, info)
}

export function getCourseById(id: string, term?: TermInput | null) {
Expand All @@ -196,11 +221,7 @@ export function getCourseById(id: string, term?: TermInput | null) {
filter.fromDate = { $lte: getTermStartMonth(term) }
}

return CourseModel
.findOne(filter)
.sort({ fromDate: -1 })
.lean()
.then(c => formatCourse(c, term))
return getCourseFromFilter(filter, term)
}

export function getCourseClasses(id: string, term?: TermInput | null) {
Expand All @@ -218,6 +239,20 @@ export function getCourseClasses(id: string, term?: TermInput | null) {
.then(c => c.map(formatClass))
}

export function getCourseSections(id: string, term?: TermInput | null) {
const filter: any = {
"class.course.identifiers": matchCsCourseId(id),
}

if (!isNil(term)) {
filter["class.session.term.name"] = termToString(term)
}
return SectionModel
.find(filter)
.lean()
.then(s => s.map(formatSection))
}

export function getCrossListings(displayNames: string[], term?: TermInput | null) {
return displayNames.map(name => {
const filter: any = {
Expand Down
8 changes: 6 additions & 2 deletions backend/src/modules/catalog/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CatalogModule } from "./generated-types/module-types";
import { getCatalog, getClass, getClassById, getClassSections, getCourse, getCourseById, getCourseClasses, getCourseList, getCrossListings, getPrimarySection, getSection } from "./controller"
import { getCatalog, getClass, getClassById, getClassSections, getCourse, getCourseById, getCourseClasses, getCourseList, getCourseSections, getCrossListings, getPrimarySection, getSection } from "./controller"

const resolvers: CatalogModule.Resolvers = {
Query: {
catalog: (_, args, __, info) => getCatalog(args.term, info),
course: (_, args) => getCourse(args.subject, args.courseNumber, args.term),
course: (_, args, __, info) => getCourse(args.subject, args.courseNumber, args.term, info),
class: (_, args) => getClass(args.subject, args.courseNumber, args.term, args.classNumber),
section: (_, args) => getSection(args.subject, args.courseNumber, args.term, args.classNumber, args.sectionNumber),
courseList: getCourseList,
Expand Down Expand Up @@ -49,6 +49,10 @@ const resolvers: CatalogModule.Resolvers = {
crossListing: (parent) => {
const cl = parent.crossListing as any
return getCrossListings(cl.displayNames, cl.term)
},
sections: (parent, { term }) => {
const c = parent.classes as any
return getCourseSections(c, term)
}
}
}
Expand Down
19 changes: 9 additions & 10 deletions backend/src/modules/catalog/typedefs/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,23 @@ type Query {

Used primarily in the catalog page.
"""
catalog(term: TermInput!): [CatalogItem]
catalog(term: TermInput!): [CatalogItem!]

"""
Get a list of all course names across all semesters.

Useful for searching for courses.
"""
courseList: [CourseListItem]
courseList: [CourseListItem!]
}

"""
Info shared between Classes within and across semesters.
"""
type Course @cacheControl(maxAge: 1) {
classes(term: TermInput): [Class]!
crossListing: [Course]
sections(term: TermInput, primary: Boolean): [Section]!

classes(term: TermInput): [Class!]!
crossListing: [Course!]
sections(term: TermInput, primary: Boolean): [Section!]!
description: String!
fromDate: String!
gradeAverage: Float
Expand All @@ -51,7 +50,7 @@ Data for a specific class in a specific semester. There may be more than one Cla
type Class @cacheControl(maxAge: 1) {
course: Course!
primarySection: Section!
sections: [Section]!
sections: [Section!]!

description: String
enrollCount: Int!
Expand All @@ -77,15 +76,15 @@ Sections are each associated with one Class.
type Section @cacheControl(maxAge: 1) {
class: Class!
course: Course!
enrollmentHistory: [EnrollmentDay]
enrollmentHistory: [EnrollmentDay!]

ccn: Int!
dateEnd: String
dateStart: String
days: [Boolean!]
enrollCount: Int!
enrollMax: Int!
instructors: [Instructor]
instructors: [Instructor!]
kind: String!
location: String
notes: String
Expand Down Expand Up @@ -117,7 +116,7 @@ type CatalogItem @cacheControl(maxAge: 1) {
number: String!
title: String!
description: String!
classes: [CatalogClass]!
classes: [CatalogClass!]!
gradeAverage: Float

lastUpdated: ISODate!
Expand Down
Loading