Add legacy hierarchy fallback for pre-migration databases.
Handle missing course_sub_categories table by serving hierarchy data from legacy categories/courses queries so content pages keep loading until unified hierarchy migration is applied. Made-with: Cursor
This commit is contained in:
parent
69d3d440d0
commit
d9783310d1
|
|
@ -74,6 +74,15 @@ type createSubModulePracticeReq struct {
|
||||||
IsActive *bool `json:"is_active"`
|
IsActive *bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type legacyHierarchyRow struct {
|
||||||
|
CategoryID int64 `json:"category_id"`
|
||||||
|
CategoryName string `json:"category_name"`
|
||||||
|
SubCategoryID *int64 `json:"sub_category_id"`
|
||||||
|
SubCategoryName *string `json:"sub_category_name"`
|
||||||
|
CourseID *int64 `json:"course_id"`
|
||||||
|
CourseTitle *string `json:"course_title"`
|
||||||
|
}
|
||||||
|
|
||||||
func toText(v *string) pgtype.Text {
|
func toText(v *string) pgtype.Text {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return pgtype.Text{Valid: false}
|
return pgtype.Text{Valid: false}
|
||||||
|
|
@ -113,6 +122,13 @@ func intOrNil(v *int32) interface{} {
|
||||||
func (h *Handler) UnifiedHierarchy(c *fiber.Ctx) error {
|
func (h *Handler) UnifiedHierarchy(c *fiber.Ctx) error {
|
||||||
rows, err := h.analyticsDB.GetCoursesWithHierarchy(c.Context())
|
rows, err := h.analyticsDB.GetCoursesWithHierarchy(c.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isMissingCourseSubCategoryTableErr(err) {
|
||||||
|
legacyRows, legacyErr := h.buildLegacyHierarchyRows(c)
|
||||||
|
if legacyErr != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load hierarchy", Error: legacyErr.Error()})
|
||||||
|
}
|
||||||
|
return c.JSON(domain.Response{Message: "Unified hierarchy retrieved successfully", Data: legacyRows})
|
||||||
|
}
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load hierarchy", Error: err.Error()})
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load hierarchy", Error: err.Error()})
|
||||||
}
|
}
|
||||||
return c.JSON(domain.Response{Message: "Unified hierarchy retrieved successfully", Data: rows})
|
return c.JSON(domain.Response{Message: "Unified hierarchy retrieved successfully", Data: rows})
|
||||||
|
|
@ -135,11 +151,88 @@ func (h *Handler) UnifiedHierarchyByCourse(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
rows, err := h.analyticsDB.GetFullHierarchyByCourseID(c.Context(), courseID)
|
rows, err := h.analyticsDB.GetFullHierarchyByCourseID(c.Context(), courseID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isMissingCourseSubCategoryTableErr(err) {
|
||||||
|
course, getCourseErr := h.analyticsDB.GetCourseByID(c.Context(), courseID)
|
||||||
|
if getCourseErr != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load course hierarchy", Error: getCourseErr.Error()})
|
||||||
|
}
|
||||||
|
return c.JSON(domain.Response{
|
||||||
|
Message: "Course hierarchy retrieved successfully",
|
||||||
|
Data: []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"course_id": course.ID,
|
||||||
|
"course_title": course.Title,
|
||||||
|
"level_id": nil,
|
||||||
|
"cefr_level": nil,
|
||||||
|
"module_id": nil,
|
||||||
|
"module_title": nil,
|
||||||
|
"sub_module_id": nil,
|
||||||
|
"sub_module_title": nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load course hierarchy", Error: err.Error()})
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load course hierarchy", Error: err.Error()})
|
||||||
}
|
}
|
||||||
return c.JSON(domain.Response{Message: "Course hierarchy retrieved successfully", Data: rows})
|
return c.JSON(domain.Response{Message: "Course hierarchy retrieved successfully", Data: rows})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isMissingCourseSubCategoryTableErr(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.Contains(strings.ToLower(err.Error()), "relation \"course_sub_categories\" does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) buildLegacyHierarchyRows(c *fiber.Ctx) ([]legacyHierarchyRow, error) {
|
||||||
|
categories, err := h.analyticsDB.GetAllCourseCategories(c.Context(), dbgen.GetAllCourseCategoriesParams{
|
||||||
|
Offset: pgtype.Int4{Int32: 0, Valid: true},
|
||||||
|
Limit: pgtype.Int4{Int32: 10000, Valid: true},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]legacyHierarchyRow, 0, len(categories))
|
||||||
|
for _, cat := range categories {
|
||||||
|
courses, courseErr := h.analyticsDB.GetCoursesByCategory(c.Context(), dbgen.GetCoursesByCategoryParams{
|
||||||
|
CategoryID: cat.ID,
|
||||||
|
Offset: pgtype.Int4{Int32: 0, Valid: true},
|
||||||
|
Limit: pgtype.Int4{Int32: 10000, Valid: true},
|
||||||
|
})
|
||||||
|
if courseErr != nil {
|
||||||
|
return nil, courseErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(courses) == 0 {
|
||||||
|
out = append(out, legacyHierarchyRow{
|
||||||
|
CategoryID: cat.ID,
|
||||||
|
CategoryName: cat.Name,
|
||||||
|
SubCategoryID: nil,
|
||||||
|
SubCategoryName: nil,
|
||||||
|
CourseID: nil,
|
||||||
|
CourseTitle: nil,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, course := range courses {
|
||||||
|
courseID := course.ID
|
||||||
|
courseTitle := course.Title
|
||||||
|
out = append(out, legacyHierarchyRow{
|
||||||
|
CategoryID: cat.ID,
|
||||||
|
CategoryName: cat.Name,
|
||||||
|
SubCategoryID: nil,
|
||||||
|
SubCategoryName: nil,
|
||||||
|
CourseID: &courseID,
|
||||||
|
CourseTitle: &courseTitle,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateCourseSubCategory godoc
|
// CreateCourseSubCategory godoc
|
||||||
// @Summary Create course sub-category
|
// @Summary Create course sub-category
|
||||||
// @Description Creates a sub-category under a course category
|
// @Description Creates a sub-category under a course category
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user