package repository import ( "context" "sno/internal/models" "github.com/jackc/pgx/v5/pgxpool" ) // QuizAttemptRepository defines the interface for quiz attempt data operations. type QuizAttemptRepository interface { Create(ctx context.Context, attempt *models.QuizAttempt) (*models.QuizAttempt, error) GetLatestByUserIDAndQuizID(ctx context.Context, userID int64, quizID int) (*models.QuizAttempt, error) GetByUserID(ctx context.Context, userID int64) ([]models.QuizAttempt, error) } // postgresQuizAttemptRepository implements the QuizAttemptRepository interface. type postgresQuizAttemptRepository struct { db *pgxpool.Pool } // NewQuizAttemptRepository creates a new instance of a quiz attempt repository. func NewQuizAttemptRepository(db *pgxpool.Pool) QuizAttemptRepository { return &postgresQuizAttemptRepository{db: db} } // Create inserts a new quiz attempt record into the database. func (r *postgresQuizAttemptRepository) Create(ctx context.Context, attempt *models.QuizAttempt) (*models.QuizAttempt, error) { query := ` INSERT INTO quiz_attempts (user_id, quiz_id, score, stars_earned, answers) VALUES ($1, $2, $3, $4, $5) RETURNING id, completed_at ` querier := getQuerier(ctx, r.db) err := querier.QueryRow(ctx, query, attempt.UserID, attempt.QuizID, attempt.Score, attempt.StarsEarned, attempt.Answers, ).Scan(&attempt.ID, &attempt.CompletedAt) if err != nil { return nil, err } return attempt, nil } // GetLatestByUserIDAndQuizID retrieves the most recent quiz attempt for a given user and quiz. func (r *postgresQuizAttemptRepository) GetLatestByUserIDAndQuizID(ctx context.Context, userID int64, quizID int) (*models.QuizAttempt, error) { query := ` SELECT id, user_id, quiz_id, score, stars_earned, completed_at, answers FROM quiz_attempts WHERE user_id = $1 AND quiz_id = $2 ORDER BY completed_at DESC LIMIT 1 ` var attempt models.QuizAttempt err := r.db.QueryRow(ctx, query, userID, quizID).Scan( &attempt.ID, &attempt.UserID, &attempt.QuizID, &attempt.Score, &attempt.StarsEarned, &attempt.CompletedAt, &attempt.Answers, ) if err != nil { return nil, err // pgx.ErrNoRows is a common error here, handled by the service } return &attempt, nil } // GetByUserID retrieves all quiz attempts for a given user. func (r *postgresQuizAttemptRepository) GetByUserID(ctx context.Context, userID int64) ([]models.QuizAttempt, error) { query := ` SELECT id, user_id, quiz_id, score, stars_earned, completed_at, answers FROM quiz_attempts WHERE user_id = $1 ORDER BY completed_at DESC ` rows, err := r.db.Query(ctx, query, userID) if err != nil { return nil, err } defer rows.Close() var attempts []models.QuizAttempt for rows.Next() { var a models.QuizAttempt if err := rows.Scan(&a.ID, &a.UserID, &a.QuizID, &a.Score, &a.StarsEarned, &a.CompletedAt, &a.Answers); err != nil { return nil, err } attempts = append(attempts, a) } if err := rows.Err(); err != nil { return nil, err } if attempts == nil { return []models.QuizAttempt{}, nil } return attempts, nil }