package repository import ( "Yimaru-Backend/internal/domain" "context" "fmt" "github.com/jackc/pgx/v5/pgtype" ) func (s *Store) GetFullLearningTree(ctx context.Context) ([]domain.TreeCourse, error) { rows, err := s.queries.GetFullLearningTree(ctx) if err != nil { return nil, err } coursesMap := make(map[int64]*domain.TreeCourse) for _, row := range rows { course, ok := coursesMap[row.CourseID] if !ok { course = &domain.TreeCourse{ ID: row.CourseID, Title: row.CourseTitle, SubCourses: []domain.TreeSubCourse{}, } coursesMap[row.CourseID] = course } if row.SubCourseID.Valid { subCourse := domain.TreeSubCourse{ ID: row.SubCourseID.Int64, Title: row.SubCourseTitle.String, Level: row.SubCourseLevel.String, } course.SubCourses = append(course.SubCourses, subCourse) } } courses := make([]domain.TreeCourse, 0, len(coursesMap)) for _, course := range coursesMap { courses = append(courses, *course) } return courses, nil } func (s *Store) GetCourseLearningPath(ctx context.Context, courseID int64) (domain.LearningPath, error) { rows, err := s.queries.GetCourseLearningPath(ctx, courseID) if err != nil { return domain.LearningPath{}, err } if len(rows) == 0 { return domain.LearningPath{}, fmt.Errorf("course not found") } first := rows[0] path := domain.LearningPath{ CourseID: first.CourseID, CourseTitle: first.CourseTitle, Description: ptrString(first.CourseDescription), Thumbnail: ptrString(first.CourseThumbnail), IntroVideoURL: ptrString(first.CourseIntroVideoUrl), CategoryID: first.CategoryID, CategoryName: first.CategoryName, SubCourses: []domain.LearningPathSubCourse{}, } for _, row := range rows { if !row.SubCourseID.Valid { continue } scID := row.SubCourseID.Int64 // Fetch prerequisites, videos, practices for this sub-course prerequisites, _ := s.getSubCoursePrerequisitesForPath(ctx, scID) videos, _ := s.getSubCourseVideosForPath(ctx, scID) practices, _ := s.getSubCoursePracticesForPath(ctx, scID) sc := domain.LearningPathSubCourse{ ID: scID, Title: row.SubCourseTitle.String, Description: ptrString(row.SubCourseDescription), Thumbnail: ptrString(row.SubCourseThumbnail), DisplayOrder: row.SubCourseDisplayOrder.Int32, Level: row.SubCourseLevel.String, PrerequisiteCount: row.PrerequisiteCount, VideoCount: row.VideoCount, PracticeCount: row.PracticeCount, Prerequisites: prerequisites, Videos: videos, Practices: practices, } path.SubCourses = append(path.SubCourses, sc) } return path, nil } func (s *Store) getSubCoursePrerequisitesForPath(ctx context.Context, subCourseID int64) ([]domain.LearningPathPrerequisite, error) { rows, err := s.queries.GetSubCoursePrerequisitesForLearningPath(ctx, subCourseID) if err != nil { return nil, err } result := make([]domain.LearningPathPrerequisite, len(rows)) for i, row := range rows { result[i] = domain.LearningPathPrerequisite{ SubCourseID: row.PrerequisiteSubCourseID, Title: row.Title, Level: row.Level, } } return result, nil } func (s *Store) getSubCourseVideosForPath(ctx context.Context, subCourseID int64) ([]domain.LearningPathVideo, error) { rows, err := s.queries.GetSubCourseVideosForLearningPath(ctx, subCourseID) if err != nil { return nil, err } result := make([]domain.LearningPathVideo, len(rows)) for i, row := range rows { result[i] = domain.LearningPathVideo{ ID: row.ID, Title: row.Title, Description: ptrString(row.Description), VideoURL: row.VideoUrl, Duration: row.Duration, Resolution: ptrString(row.Resolution), DisplayOrder: row.DisplayOrder, VimeoID: ptrString(row.VimeoID), VimeoEmbedURL: ptrString(row.VimeoEmbedUrl), VideoHostProvider: ptrString(row.VideoHostProvider), } } return result, nil } func (s *Store) getSubCoursePracticesForPath(ctx context.Context, subCourseID int64) ([]domain.LearningPathPractice, error) { ownerID := pgtype.Int8{Int64: subCourseID, Valid: true} rows, err := s.queries.GetSubCoursePracticesForLearningPath(ctx, ownerID) if err != nil { return nil, err } result := make([]domain.LearningPathPractice, len(rows)) for i, row := range rows { result[i] = domain.LearningPathPractice{ ID: row.ID, Title: row.Title, Description: ptrString(row.Description), Persona: ptrString(row.Persona), Status: row.Status, QuestionCount: row.QuestionCount, } } return result, nil }