@@ -66,7 +66,7 @@ func SectionSearch(c *gin.Context) {
6666
6767 optionLimit , err := configs .GetOptionLimit (& query , c )
6868 if err != nil {
69- respond (c , http .StatusBadRequest , "offset is not type integer" , err .Error ())
69+ respond [ string ] (c , http .StatusBadRequest , "offset is not type integer" , err .Error ())
7070 return
7171 }
7272
@@ -84,7 +84,7 @@ func SectionSearch(c *gin.Context) {
8484 }
8585
8686 // return result
87- respond (c , http .StatusOK , "success" , sections )
87+ respond [[]schema. Section ] (c , http .StatusOK , "success" , sections )
8888}
8989
9090// @Id sectionById
@@ -116,7 +116,7 @@ func SectionById(c *gin.Context) {
116116 }
117117
118118 // return result
119- respond (c , http .StatusOK , "success" , section )
119+ respond [schema. Section ] (c , http .StatusOK , "success" , section )
120120}
121121
122122// @Id sectionCourseSearch
@@ -175,77 +175,52 @@ func sectionCourse(flag string, c *gin.Context) {
175175 defer cancel ()
176176
177177 var sectionCourses []schema.Course
178- var sectionQuery bson. M
179- var err error
180- if sectionQuery , err = getSectionQuery ( flag , c ); err != nil {
178+ sectionQuery , err := getSectionQuery ( flag , c )
179+
180+ if err != nil {
181181 return
182182 }
183183
184- paginateMap , err := configs .GetAggregateLimit (& sectionQuery , c )
184+ rawPaginateMap , err := configs .GetAggregateLimit (& sectionQuery , c )
185185 if err != nil {
186186 respond (c , http .StatusBadRequest , "Error offset is not type integer" , err .Error ())
187187 return
188188 }
189189
190- // pipeline of query an array of courses from filtered sections
191- sectionCoursePipeline := mongo.Pipeline {
192- // filter the sections
193- bson.D {{Key : "$match" , Value : sectionQuery }},
194-
195- // paginate the sections before pulling courses from those sections
196- bson.D {{Key : "$skip" , Value : paginateMap ["former_offset" ]}},
197- bson.D {{Key : "$limit" , Value : paginateMap ["limit" ]}},
198-
199- // lookup the course referenced by sections from the course collection
200- bson.D {{Key : "$lookup" , Value : bson.D {
201- {Key : "from" , Value : "courses" },
202- {Key : "localField" , Value : "course_reference" },
203- {Key : "foreignField" , Value : "_id" },
204- {Key : "as" , Value : "course_reference" },
205- }}},
206-
207- // project to remove every other fields except for courses
208- bson.D {{Key : "$project" , Value : bson.D {{Key : "courses" , Value : "$course_reference" }}}},
209-
210- // unwind the courses
211- bson.D {{Key : "$unwind" , Value : bson.D {
212- {Key : "path" , Value : "$courses" },
213- {Key : "preserveNullAndEmptyArrays" , Value : false },
214- }}},
215190
216- // replace the combinations of id and course with courses entirely
217- bson.D {{Key : "$replaceWith" , Value : "$courses" }},
218-
219- // keep order deterministic between calls
220- bson.D {{Key : "$sort" , Value : bson.D {{Key : "_id" , Value : 1 }}}},
221-
222- // paginate the courses
223- bson.D {{Key : "$skip" , Value : paginateMap ["latter_offset" ]}},
224- bson.D {{Key : "$limit" , Value : paginateMap ["limit" ]}},
191+ paginateMap := make (map [string ]int )
192+ for k ,v := range rawPaginateMap {
193+ paginateMap [k ] = int (v )
225194 }
226195
227- cursor , err := sectionCollection .Aggregate (ctx , sectionCoursePipeline )
196+ pipeline := buildSectionPipeline (sectionQuery , paginateMap , "courses" , flag == "ById" )
197+ cursor , err := sectionCollection .Aggregate (ctx , pipeline )
198+
228199 if err != nil {
229200 respondWithInternalError (c , err )
230201 return
231202 }
232-
233- // Parse the array of courses
234- if err = cursor .All (ctx , & sectionCourses ); err != nil {
235- respondWithInternalError (c , err )
236- return
237- }
238-
239- switch flag {
240- case "Search" :
241- respond (c , http .StatusOK , "success" , sectionCourses )
242- case "ById" :
243- // Each section is only referenced by only one course, so returning a single course is ideal
244- // A better way of handling this might be needed in the future
245- respond (c , http .StatusOK , "success" , sectionCourses [0 ])
203+ if flag == "ById" {
204+ var course schema.Course
205+ if cursor .Next (ctx ) {
206+ if err := cursor .Decode (& course ); err != nil {
207+ respondWithInternalError (c ,err )
208+ return
209+ }
210+ respond [* schema.Course ](c , http .StatusOK , "success" , & course )
211+ return
212+ }
213+ respond [interface {}](c , http .StatusOK , "success" , nil )
214+ } else {
215+ if err := cursor .All (ctx , & sectionCourses ); err != nil {
216+ respondWithInternalError (c , err )
217+ return
218+ }
219+ respond [[]schema.Course ](c , http .StatusOK , "success" , sectionCourses )
246220 }
247221}
248222
223+
249224// @Id sectionProfessorSearch
250225// @Router /section/professors [get]
251226// @Description "Returns paginated list of professors of all the sections matching the query's string-typed key-value pairs. See former_offset and latter_offset for pagination details."
@@ -290,72 +265,48 @@ func SectionProfessorSearch() gin.HandlerFunc {
290265// @Success 200 {object} schema.APIResponse[[]schema.Professor] "A list of professors"
291266// @Failure 500 {object} schema.APIResponse[string] "A string describing the error"
292267// @Failure 400 {object} schema.APIResponse[string] "A string describing the error"
268+
293269func SectionProfessorById () gin.HandlerFunc {
294270 return func (c * gin.Context ) {
295271 sectionProfessor ("ById" , c )
296272 }
297273}
298274
299- // Get an array of professors from sections,
275+ // Get an array of professors sections,
300276func sectionProfessor (flag string , c * gin.Context ) {
301277 ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
302278 defer cancel ()
303279
304- var sectionProfessors []schema.Professor
305- var sectionQuery bson.M
306- var err error
307- if sectionQuery , err = getSectionQuery (flag , c ); err != nil {
280+ sectionQuery , err := getSectionQuery (flag , c )
281+
282+ if err != nil {
308283 return
309284 }
310285
311- paginateMap , err := configs .GetAggregateLimit (& sectionQuery , c )
286+ rawPaginateMap , err := configs .GetAggregateLimit (& sectionQuery , c )
312287 if err != nil {
313288 respond (c , http .StatusBadRequest , "Error offset is not type integer" , err .Error ())
314289 return
315290 }
316291
317- // pipeline to query an array of professors from filtered sections
318- sectionProfessorPipeline := mongo.Pipeline {
319- bson.D {{Key : "$match" , Value : sectionQuery }},
320-
321- bson.D {{Key : "$skip" , Value : paginateMap ["former_offset" ]}},
322- bson.D {{Key : "$limit" , Value : paginateMap ["limit" ]}},
323-
324- bson.D {{Key : "$lookup" , Value : bson.D {
325- {Key : "from" , Value : "professors" },
326- {Key : "localField" , Value : "professors" },
327- {Key : "foreignField" , Value : "_id" },
328- {Key : "as" , Value : "professors" },
329- }}},
330-
331- bson.D {{Key : "$project" , Value : bson.D {{Key : "professors" , Value : "$professors" }}}},
332-
333- bson.D {{Key : "$unwind" , Value : bson.D {
334- {Key : "path" , Value : "$professors" },
335- {Key : "preserveNullAndEmptyArrays" , Value : false },
336- }}},
337-
338- bson.D {{Key : "$replaceWith" , Value : "$professors" }},
339-
340- bson.D {{Key : "$sort" , Value : bson.D {{Key : "_id" , Value : 1 }}}},
341-
342- bson.D {{Key : "$skip" , Value : paginateMap ["latter_offset" ]}},
343- bson.D {{Key : "$limit" , Value : paginateMap ["limit" ]}},
292+ paginateMap := make (map [string ]int )
293+ for k , v := range rawPaginateMap {
294+ paginateMap [k ] = int (v )
344295 }
345296
346- cursor , err := sectionCollection .Aggregate (ctx , sectionProfessorPipeline )
297+ pipeline := buildSectionPipeline (sectionQuery , paginateMap , "professors" , flag == "ById" )
298+ cursor , err := sectionCollection .Aggregate (ctx , pipeline )
299+
347300 if err != nil {
348301 respondWithInternalError (c , err )
349302 return
350303 }
351-
352- // Parse the array of courses
304+ var sectionProfessors []schema.Professor
353305 if err = cursor .All (ctx , & sectionProfessors ); err != nil {
354306 respondWithInternalError (c , err )
355307 return
356308 }
357-
358- respond (c , http .StatusOK , "success" , sectionProfessors )
309+ respond [[]schema.Professor ](c , http .StatusOK , "success" , sectionProfessors )
359310}
360311
361312// Determine the query of the section based on parameters passed from context.
@@ -385,3 +336,50 @@ func getSectionQuery(flag string, c *gin.Context) (bson.M, error) {
385336
386337 return sectionQuery , nil
387338}
339+
340+ func buildSectionPipeline (
341+ sectionQuery bson.M ,
342+ paginateMap map [string ]int ,
343+ lookupType string ,
344+ single bool ,
345+ ) mongo.Pipeline {
346+ localField := "course_reference"
347+ field := lookupType
348+
349+ if lookupType == "professors" {
350+ localField = "professor_id"
351+ }
352+ pipeline := mongo.Pipeline {
353+ bson.D {{Key : "$match" , Value : sectionQuery }},
354+ }
355+ if ! single {
356+ pipeline = append (pipeline ,
357+ bson.D {{Key : "$skip" , Value : paginateMap ["former_offset" ]}},
358+ bson.D {{Key : "$limit" , Value : paginateMap ["limit" ]}},
359+ )
360+ }
361+
362+ pipeline = append (pipeline ,
363+ bson.D {{Key : "$lookup" , Value : bson.D {
364+ {Key : "from" , Value : lookupType },
365+ {Key : "localField" , Value : localField },
366+ {Key : "foreignField" , Value : "_id" },
367+ {Key : "as" , Value : field },
368+ }}},
369+ bson.D {{Key : "$project" , Value : bson.D {{Key : field , Value : "$" + field }}}},
370+ )
371+
372+ if ! single {
373+ pipeline = append (pipeline ,
374+ bson.D {{Key : "$unwind" , Value : bson.D {
375+ {Key : "path" , Value : "$" + field },
376+ {Key : "preserveNullAndEmptyArrays" , Value : false },
377+ }}},
378+ bson.D {{Key : "$replaceWith" , Value : "$" + field }},
379+ bson.D {{Key : "$sort" , Value : bson.D {{Key : "_id" , Value : 1 }}}},
380+ bson.D {{Key : "$skip" , Value : paginateMap ["latter_offset" ]}},
381+ bson.D {{Key : "$limit" , Value : paginateMap ["limit" ]}},
382+ )
383+ }
384+ return pipeline
385+ }
0 commit comments