Yimaru-BackEnd/internal/repository/exam_prep_lesson_practices.go
Yared Yemane 12ad59c409 Add draft vs published status for LMS and exam-prep practices.
Expose publish_status on create/update, filter learner-facing lists and gates, and add migration 000060.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 03:57:43 -07:00

145 lines
4.9 KiB
Go

package repository
import (
"context"
"errors"
dbgen "Yimaru-Backend/gen/db"
"Yimaru-Backend/internal/domain"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
func examPrepPracticeFromListRow(r dbgen.ExamPrepListLessonPracticesByLessonIDRow) domain.ExamPrepPractice {
return examPrepPracticeToDomain(dbgen.ExamPrepLessonPractice{
ID: r.ID,
UnitModuleLessonID: r.UnitModuleLessonID,
Title: r.Title,
StoryDescription: r.StoryDescription,
StoryImage: r.StoryImage,
PersonaID: r.PersonaID,
QuestionSetID: r.QuestionSetID,
QuickTips: r.QuickTips,
PublishStatus: r.PublishStatus,
CreatedAt: r.CreatedAt,
UpdatedAt: r.UpdatedAt,
})
}
func examPrepPracticeToDomain(p dbgen.ExamPrepLessonPractice) domain.ExamPrepPractice {
out := domain.ExamPrepPractice{
ID: p.ID,
LessonID: p.UnitModuleLessonID,
Title: p.Title,
QuestionSetID: p.QuestionSetID,
PublishStatus: domain.PracticePublishStatusFromDB(p.PublishStatus),
}
out.StoryDescription = fromPgText(p.StoryDescription)
out.StoryImage = fromPgText(p.StoryImage)
out.QuickTips = fromPgText(p.QuickTips)
out.PersonaID = fromPgInt8ID(p.PersonaID)
out.CreatedAt = p.CreatedAt.Time
if p.UpdatedAt.Valid {
t := p.UpdatedAt.Time
out.UpdatedAt = &t
}
return out
}
func (s *Store) CreateExamPrepLessonPractice(ctx context.Context, lessonID int64, in domain.CreateExamPrepPracticeInput) (domain.ExamPrepPractice, error) {
ps := domain.ParsePracticePublishStatusInput(in.PublishStatus)
p, err := s.queries.ExamPrepCreateLessonPractice(ctx, dbgen.ExamPrepCreateLessonPracticeParams{
UnitModuleLessonID: lessonID,
Title: in.Title,
StoryDescription: toPgText(in.StoryDescription),
StoryImage: toPgText(in.StoryImage),
PersonaID: int64PtrToPg8(in.PersonaID),
QuestionSetID: in.QuestionSetID,
QuickTips: toPgText(in.QuickTips),
PublishStatus: string(ps),
})
if err != nil {
return domain.ExamPrepPractice{}, err
}
return examPrepPracticeToDomain(p), nil
}
func (s *Store) GetExamPrepLessonPracticeByID(ctx context.Context, id int64) (domain.ExamPrepPractice, error) {
p, err := s.queries.ExamPrepGetLessonPracticeByID(ctx, id)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.ExamPrepPractice{}, pgx.ErrNoRows
}
return domain.ExamPrepPractice{}, err
}
return examPrepPracticeToDomain(p), nil
}
// TryGetExamPrepLessonPracticeByQuestionSetID returns false when no row exists.
func (s *Store) TryGetExamPrepLessonPracticeByQuestionSetID(ctx context.Context, questionSetID int64) (domain.ExamPrepPractice, bool, error) {
p, err := s.queries.ExamPrepGetLessonPracticeByQuestionSetID(ctx, questionSetID)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.ExamPrepPractice{}, false, nil
}
return domain.ExamPrepPractice{}, false, err
}
return examPrepPracticeToDomain(p), true, nil
}
func (s *Store) ListExamPrepLessonPracticesByLessonID(ctx context.Context, lessonID int64, publishedOnly bool, limit, offset int32) ([]domain.ExamPrepPractice, int64, error) {
rows, err := s.queries.ExamPrepListLessonPracticesByLessonID(ctx, dbgen.ExamPrepListLessonPracticesByLessonIDParams{
UnitModuleLessonID: lessonID,
PublishedOnly: publishedOnly,
Limit: limit,
Offset: offset,
})
if err != nil {
return nil, 0, err
}
if len(rows) == 0 {
return []domain.ExamPrepPractice{}, 0, nil
}
var total int64
out := make([]domain.ExamPrepPractice, 0, len(rows))
for i, r := range rows {
if i == 0 {
total = r.TotalCount
}
out = append(out, examPrepPracticeFromListRow(r))
}
return out, total, nil
}
func (s *Store) UpdateExamPrepLessonPractice(ctx context.Context, id int64, input domain.UpdateExamPrepPracticeInput) (domain.ExamPrepPractice, error) {
var titleText pgtype.Text
if input.Title != nil {
titleText = pgtype.Text{String: *input.Title, Valid: true}
} else {
titleText = pgtype.Text{Valid: false}
}
qs := optionalInt8UpdateID(input.QuestionSetID)
p, err := s.queries.ExamPrepUpdateLessonPractice(ctx, dbgen.ExamPrepUpdateLessonPracticeParams{
ID: id,
Title: titleText,
StoryDescription: optionalTextUpdate(input.StoryDescription),
StoryImage: optionalTextUpdate(input.StoryImage),
PersonaID: optionalInt8UpdateID(input.PersonaID),
QuestionSetID: qs,
QuickTips: optionalTextUpdate(input.QuickTips),
PublishStatus: optionalPublishStatusUpdate(input.PublishStatus),
})
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.ExamPrepPractice{}, pgx.ErrNoRows
}
return domain.ExamPrepPractice{}, err
}
return examPrepPracticeToDomain(p), nil
}
func (s *Store) DeleteExamPrepLessonPractice(ctx context.Context, id int64) error {
return s.queries.ExamPrepDeleteLessonPractice(ctx, id)
}