package repository import ( "context" "sno/internal/models" "github.com/jackc/pgx/v5/pgxpool" ) // QuizRepository defines the interface for quiz data operations. type QuizRepository interface { GetAllActive(ctx context.Context) ([]models.Quiz, error) Create(ctx context.Context, quiz *models.Quiz) (*models.Quiz, error) GetByID(ctx context.Context, id int) (*models.Quiz, error) Update(ctx context.Context, id int, quiz *models.Quiz) (*models.Quiz, error) Delete(ctx context.Context, id int) error } // postgresQuizRepository implements the QuizRepository interface for PostgreSQL. type postgresQuizRepository struct { db *pgxpool.Pool } // NewQuizRepository creates a new instance of a quiz repository. func NewQuizRepository(db *pgxpool.Pool) QuizRepository { return &postgresQuizRepository{db: db} } // GetAllActive retrieves all quizzes where is_active is true. func (r *postgresQuizRepository) GetAllActive(ctx context.Context) ([]models.Quiz, error) { query := ` SELECT id, title, description, image_url, reward_stars, has_timer, timer_per_question, can_repeat, repeat_cooldown_hours, is_active, created_by, created_at FROM quizzes WHERE is_active = true ORDER BY created_at DESC ` rows, err := r.db.Query(ctx, query) if err != nil { return nil, err } defer rows.Close() var quizzes []models.Quiz for rows.Next() { var q models.Quiz if err := rows.Scan( &q.ID, &q.Title, &q.Description, &q.ImageURL, &q.RewardStars, &q.HasTimer, &q.TimerPerQuestion, &q.CanRepeat, &q.RepeatCooldownHours, &q.IsActive, &q.CreatedBy, &q.CreatedAt, ); err != nil { return nil, err } quizzes = append(quizzes, q) } if err := rows.Err(); err != nil { return nil, err } if quizzes == nil { return []models.Quiz{}, nil } return quizzes, nil } // Create inserts a new quiz into the database. func (r *postgresQuizRepository) Create(ctx context.Context, quiz *models.Quiz) (*models.Quiz, error) { query := ` INSERT INTO quizzes (title, description, image_url, reward_stars, has_timer, timer_per_question, can_repeat, repeat_cooldown_hours, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, is_active, created_at ` err := r.db.QueryRow(ctx, query, quiz.Title, quiz.Description, quiz.ImageURL, quiz.RewardStars, quiz.HasTimer, quiz.TimerPerQuestion, quiz.CanRepeat, quiz.RepeatCooldownHours, quiz.CreatedBy, ).Scan(&quiz.ID, &quiz.IsActive, &quiz.CreatedAt) if err != nil { return nil, err } return quiz, nil } // GetByID retrieves a single quiz by its ID. func (r *postgresQuizRepository) GetByID(ctx context.Context, id int) (*models.Quiz, error) { query := ` SELECT id, title, description, image_url, reward_stars, has_timer, timer_per_question, can_repeat, repeat_cooldown_hours, is_active, created_by, created_at FROM quizzes WHERE id = $1 ` var q models.Quiz err := r.db.QueryRow(ctx, query, id).Scan( &q.ID, &q.Title, &q.Description, &q.ImageURL, &q.RewardStars, &q.HasTimer, &q.TimerPerQuestion, &q.CanRepeat, &q.RepeatCooldownHours, &q.IsActive, &q.CreatedBy, &q.CreatedAt, ) if err != nil { return nil, err } return &q, nil } // Update updates an existing quiz func (r *postgresQuizRepository) Update(ctx context.Context, id int, quiz *models.Quiz) (*models.Quiz, error) { query := ` UPDATE quizzes SET title = $2, description = $3, image_url = $4, reward_stars = $5, has_timer = $6, timer_per_question = $7, can_repeat = $8, repeat_cooldown_hours = $9, is_active = $10 WHERE id = $1 RETURNING id, title, description, image_url, reward_stars, has_timer, timer_per_question, can_repeat, repeat_cooldown_hours, is_active, created_by, created_at ` var q models.Quiz err := r.db.QueryRow(ctx, query, id, quiz.Title, quiz.Description, quiz.ImageURL, quiz.RewardStars, quiz.HasTimer, quiz.TimerPerQuestion, quiz.CanRepeat, quiz.RepeatCooldownHours, quiz.IsActive, ).Scan( &q.ID, &q.Title, &q.Description, &q.ImageURL, &q.RewardStars, &q.HasTimer, &q.TimerPerQuestion, &q.CanRepeat, &q.RepeatCooldownHours, &q.IsActive, &q.CreatedBy, &q.CreatedAt, ) if err != nil { return nil, err } return &q, nil } // Delete deletes a quiz and its associated questions func (r *postgresQuizRepository) Delete(ctx context.Context, id int) error { // Start transaction tx, err := r.db.Begin(ctx) if err != nil { return err } defer tx.Rollback(ctx) // Delete associated questions first _, err = tx.Exec(ctx, "DELETE FROM questions WHERE quiz_id = $1", id) if err != nil { return err } // Delete the quiz _, err = tx.Exec(ctx, "DELETE FROM quizzes WHERE id = $1", id) if err != nil { return err } // Commit transaction return tx.Commit(ctx) }