package repository import ( dbgen "Yimaru-Backend/gen/db" "Yimaru-Backend/internal/domain" "Yimaru-Backend/internal/ports" "context" "errors" "time" "github.com/jackc/pgx/v5" ) func NewProgressionStore(s *Store) ports.ProgressionStore { return s } func (s *Store) AddSubCoursePrerequisite(ctx context.Context, subCourseID, prerequisiteSubCourseID int64) error { _, err := s.queries.AddSubCoursePrerequisite(ctx, dbgen.AddSubCoursePrerequisiteParams{ SubCourseID: subCourseID, PrerequisiteSubCourseID: prerequisiteSubCourseID, }) return err } func (s *Store) RemoveSubCoursePrerequisite(ctx context.Context, subCourseID, prerequisiteSubCourseID int64) error { return s.queries.RemoveSubCoursePrerequisite(ctx, dbgen.RemoveSubCoursePrerequisiteParams{ SubCourseID: subCourseID, PrerequisiteSubCourseID: prerequisiteSubCourseID, }) } func (s *Store) GetSubCoursePrerequisites(ctx context.Context, subCourseID int64) ([]domain.SubCoursePrerequisite, error) { rows, err := s.queries.GetSubCoursePrerequisites(ctx, subCourseID) if err != nil { return nil, err } prereqs := make([]domain.SubCoursePrerequisite, len(rows)) for i, row := range rows { prereqs[i] = domain.SubCoursePrerequisite{ ID: row.ID, SubCourseID: row.SubCourseID, PrerequisiteSubCourseID: row.PrerequisiteSubCourseID, CreatedAt: row.CreatedAt.Time, PrerequisiteTitle: row.PrerequisiteTitle, PrerequisiteLevel: row.PrerequisiteLevel, PrerequisiteDisplayOrder: row.PrerequisiteDisplayOrder, } } return prereqs, nil } func (s *Store) GetSubCourseDependents(ctx context.Context, prerequisiteSubCourseID int64) ([]domain.SubCourseDependent, error) { rows, err := s.queries.GetSubCourseDependents(ctx, prerequisiteSubCourseID) if err != nil { return nil, err } deps := make([]domain.SubCourseDependent, len(rows)) for i, row := range rows { deps[i] = domain.SubCourseDependent{ ID: row.ID, SubCourseID: row.SubCourseID, PrerequisiteSubCourseID: row.PrerequisiteSubCourseID, CreatedAt: row.CreatedAt.Time, DependentTitle: row.DependentTitle, DependentLevel: row.DependentLevel, } } return deps, nil } func (s *Store) CountUnmetPrerequisites(ctx context.Context, subCourseID, userID int64) (int64, error) { return s.queries.CountUnmetPrerequisites(ctx, dbgen.CountUnmetPrerequisitesParams{ SubCourseID: subCourseID, UserID: userID, }) } func (s *Store) DeleteAllPrerequisitesForSubCourse(ctx context.Context, subCourseID int64) error { return s.queries.DeleteAllPrerequisitesForSubCourse(ctx, subCourseID) } func (s *Store) StartSubCourseProgress(ctx context.Context, userID, subCourseID int64) (domain.UserSubCourseProgress, error) { row, err := s.queries.StartSubCourseProgress(ctx, dbgen.StartSubCourseProgressParams{ UserID: userID, SubCourseID: subCourseID, }) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return s.GetUserSubCourseProgress(ctx, userID, subCourseID) } return domain.UserSubCourseProgress{}, err } return mapUserSubCourseProgress(row), nil } func (s *Store) UpdateSubCourseProgress(ctx context.Context, userID, subCourseID int64, percentage int16) error { return s.queries.UpdateSubCourseProgress(ctx, dbgen.UpdateSubCourseProgressParams{ ProgressPercentage: percentage, UserID: userID, SubCourseID: subCourseID, }) } func (s *Store) CompleteSubCourse(ctx context.Context, userID, subCourseID int64) error { return s.queries.CompleteSubCourse(ctx, dbgen.CompleteSubCourseParams{ UserID: userID, SubCourseID: subCourseID, }) } func (s *Store) GetUserSubCourseProgress(ctx context.Context, userID, subCourseID int64) (domain.UserSubCourseProgress, error) { row, err := s.queries.GetUserSubCourseProgress(ctx, dbgen.GetUserSubCourseProgressParams{ UserID: userID, SubCourseID: subCourseID, }) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return domain.UserSubCourseProgress{}, domain.ErrProgressNotFound } return domain.UserSubCourseProgress{}, err } return mapUserSubCourseProgress(row), nil } func (s *Store) GetUserCourseProgress(ctx context.Context, userID, courseID int64) ([]domain.UserCourseProgressItem, error) { rows, err := s.queries.GetUserCourseProgress(ctx, dbgen.GetUserCourseProgressParams{ UserID: userID, CourseID: courseID, }) if err != nil { return nil, err } items := make([]domain.UserCourseProgressItem, len(rows)) for i, row := range rows { var startedAt, completedAt *time.Time if row.StartedAt.Valid { startedAt = &row.StartedAt.Time } if row.CompletedAt.Valid { completedAt = &row.CompletedAt.Time } var updatedAt *time.Time if row.UpdatedAt.Valid { updatedAt = &row.UpdatedAt.Time } items[i] = domain.UserCourseProgressItem{ ID: row.ID, UserID: row.UserID, SubCourseID: row.SubCourseID, Status: domain.ProgressStatus(row.Status), ProgressPercentage: row.ProgressPercentage, StartedAt: startedAt, CompletedAt: completedAt, CreatedAt: row.CreatedAt.Time, UpdatedAt: updatedAt, SubCourseTitle: row.SubCourseTitle, SubCourseLevel: row.SubCourseLevel, SubCourseDisplayOrder: row.SubCourseDisplayOrder, } } return items, nil } func (s *Store) GetSubCoursesWithProgressByCourse(ctx context.Context, userID, courseID int64) ([]domain.SubCourseWithProgress, error) { rows, err := s.queries.GetSubCoursesWithProgressByCourse(ctx, dbgen.GetSubCoursesWithProgressByCourseParams{ UserID: userID, CourseID: courseID, }) if err != nil { return nil, err } items := make([]domain.SubCourseWithProgress, len(rows)) for i, row := range rows { var startedAt, completedAt *time.Time if row.StartedAt.Valid { startedAt = &row.StartedAt.Time } if row.CompletedAt.Valid { completedAt = &row.CompletedAt.Time } items[i] = domain.SubCourseWithProgress{ SubCourseID: row.SubCourseID, Title: row.Title, Description: ptrText(row.Description), Thumbnail: ptrText(row.Thumbnail), DisplayOrder: row.DisplayOrder, Level: row.Level, IsActive: row.IsActive, ProgressStatus: domain.ProgressStatus(row.ProgressStatus), ProgressPercentage: row.ProgressPercentage, StartedAt: startedAt, CompletedAt: completedAt, UnmetPrerequisitesCount: row.UnmetPrerequisitesCount, IsLocked: row.UnmetPrerequisitesCount > 0, } } return items, nil } func mapUserSubCourseProgress(row dbgen.UserSubCourseProgress) domain.UserSubCourseProgress { var startedAt, completedAt *time.Time if row.StartedAt.Valid { startedAt = &row.StartedAt.Time } if row.CompletedAt.Valid { completedAt = &row.CompletedAt.Time } var updatedAt *time.Time if row.UpdatedAt.Valid { updatedAt = &row.UpdatedAt.Time } return domain.UserSubCourseProgress{ ID: row.ID, UserID: row.UserID, SubCourseID: row.SubCourseID, Status: domain.ProgressStatus(row.Status), ProgressPercentage: row.ProgressPercentage, StartedAt: startedAt, CompletedAt: completedAt, CreatedAt: row.CreatedAt.Time, UpdatedAt: updatedAt, } }