unique quiz constraint
This commit is contained in:
@@ -12,11 +12,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrQuizNotFound = errors.New("quiz not found")
|
||||
ErrQuizNotStarted = errors.New("start the quiz first")
|
||||
ErrQuizNotCurrent = errors.New("that isn't the current question")
|
||||
ErrQuizBadOption = errors.New("that option isn't part of this question")
|
||||
ErrQuizChoiceCount = errors.New("choose one option, or at least one where several apply")
|
||||
ErrQuizNotFound = errors.New("quiz not found")
|
||||
ErrQuizNotStarted = errors.New("start the quiz first")
|
||||
ErrQuizNotCurrent = errors.New("that isn't the current question")
|
||||
ErrQuizBadOption = errors.New("that option isn't part of this question")
|
||||
ErrQuizChoiceCount = errors.New("choose one option, or at least one where several apply")
|
||||
// ErrQuizTargetTaken: that chapter, lecture or conversation already has a
|
||||
// quiz (enforced by the quizzes_one_per_target index).
|
||||
ErrQuizTargetTaken = errors.New("only one quiz is allowed per link")
|
||||
ErrQuizAlreadyAnswer = errors.New("that question is already answered")
|
||||
ErrQuizNotFinished = errors.New("the quiz isn't finished yet")
|
||||
)
|
||||
@@ -148,6 +151,9 @@ func (r *QuizRepo) Create(ctx context.Context, in QuizInput, createdBy string) (
|
||||
VALUES ($1, $2, $3, $4, $5, $6) RETURNING id`,
|
||||
in.Title, in.Description, in.TargetKind, in.TargetPath, in.TargetTitle, createdBy,
|
||||
).Scan(&id); err != nil {
|
||||
if isUniqueViolation(err, "quizzes_one_per_target") {
|
||||
return "", ErrQuizTargetTaken
|
||||
}
|
||||
return "", fmt.Errorf("create quiz: %w", err)
|
||||
}
|
||||
if err := insertQuestions(ctx, tx, id, in.Questions); err != nil {
|
||||
@@ -171,6 +177,9 @@ func (r *QuizRepo) Update(ctx context.Context, id string, in QuizInput, replaceQ
|
||||
WHERE id = $1 AND deleted_at IS NULL`,
|
||||
id, in.Title, in.Description, in.TargetKind, in.TargetPath, in.TargetTitle)
|
||||
if err != nil {
|
||||
if isUniqueViolation(err, "quizzes_one_per_target") {
|
||||
return ErrQuizTargetTaken
|
||||
}
|
||||
return fmt.Errorf("update quiz: %w", err)
|
||||
}
|
||||
if tag.RowsAffected() == 0 {
|
||||
@@ -207,6 +216,23 @@ func insertQuestions(ctx context.Context, tx pgx.Tx, quizID string, qs []Questio
|
||||
return nil
|
||||
}
|
||||
|
||||
// QuizOnTarget returns the live quiz (published or draft) already attached to
|
||||
// a content path, other than exceptID — or "" when the path is free.
|
||||
func (r *QuizRepo) QuizOnTarget(ctx context.Context, path, exceptID string) (id, title string, err error) {
|
||||
err = r.pg.Pool.QueryRow(ctx, `
|
||||
SELECT id, title FROM quizzes
|
||||
WHERE target_path = $1 AND deleted_at IS NULL
|
||||
AND ($2 = '' OR id::text <> $2)
|
||||
LIMIT 1`, path, exceptID).Scan(&id, &title)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return "", "", nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("quiz on target: %w", err)
|
||||
}
|
||||
return id, title, nil
|
||||
}
|
||||
|
||||
func (r *QuizRepo) AttemptCount(ctx context.Context, id string) (int, error) {
|
||||
var n int
|
||||
err := r.pg.Pool.QueryRow(ctx, `SELECT count(*) FROM quiz_attempts WHERE quiz_id = $1`, id).Scan(&n)
|
||||
|
||||
Reference in New Issue
Block a user