feat(tester): add solution endpoints

add CreateSolution&GetSolution&ListSolutions endpoints
This commit is contained in:
Vyacheslav1557 2025-03-27 00:04:52 +05:00
parent af6e0b89f6
commit ef696d2836
9 changed files with 316 additions and 8 deletions

View file

@ -2,8 +2,10 @@ package repository
import (
"context"
"fmt"
"git.sch9.ru/new_gate/ms-tester/internal/models"
"github.com/jmoiron/sqlx"
"strings"
)
type ContestRepository struct {
@ -247,3 +249,145 @@ func (r *ContestRepository) UpdateParticipant(ctx context.Context, id int32, par
return nil
}
const (
readSolutionQuery = "SELECT * FROM solutions WHERE id = ?"
)
func (r *ContestRepository) ReadSolution(ctx context.Context, id int32) (*models.Solution, error) {
const op = "ContestRepository.ReadSolution"
query := r.db.Rebind(readSolutionQuery)
var solution models.Solution
err := r.db.GetContext(ctx, &solution, query, id)
if err != nil {
return nil, handlePgErr(err, op)
}
return &solution, nil
}
const (
createSolutionQuery = `INSERT INTO solutions (task_id, participant_id, language, penalty, solution)
VALUES (?, ?, ?, ?, ?)
RETURNING id`
)
func (r *ContestRepository) CreateSolution(ctx context.Context, creation *models.SolutionCreation) (int32, error) {
const op = "ContestRepository.CreateSolution"
query := r.db.Rebind(createSolutionQuery)
rows, err := r.db.QueryxContext(ctx,
query,
creation.TaskId,
creation.ParticipantId,
creation.Language,
creation.Penalty,
creation.Solution,
)
if err != nil {
return 0, handlePgErr(err, op)
}
defer rows.Close()
var id int32
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, handlePgErr(err, op)
}
return id, nil
}
func (r *ContestRepository) ListSolutions(ctx context.Context, filters models.SolutionsFilter) ([]*models.SolutionsListItem, int32, error) {
const op = "ContestRepository.ListSolutions"
baseQuery := `
SELECT
s.id,
s.task_id,
t.contest_id,
s.participant_id,
s.state,
s.score,
s.penalty,
s.total_score,
s.language,
s.updated_at,
s.created_at
FROM solutions s
LEFT JOIN tasks t ON s.task_id = t.id
WHERE 1=1
`
var conditions []string
var args []interface{}
if filters.ContestId != nil {
conditions = append(conditions, "contest_id = ?")
args = append(args, *filters.ContestId)
}
if filters.ParticipantId != nil {
conditions = append(conditions, "participant_id = ?")
args = append(args, *filters.ParticipantId)
}
if filters.TaskId != nil {
conditions = append(conditions, "task_id = ?")
args = append(args, *filters.TaskId)
}
if filters.Language != nil {
conditions = append(conditions, "language = ?")
args = append(args, *filters.Language)
}
if filters.State != nil {
conditions = append(conditions, "state = ?")
args = append(args, *filters.State)
}
if len(conditions) > 0 {
baseQuery += " AND " + strings.Join(conditions, " AND ")
}
if filters.Order != nil {
orderDirection := "ASC"
if *filters.Order < 0 {
orderDirection = "DESC"
}
baseQuery += fmt.Sprintf(" ORDER BY s.id %s", orderDirection)
}
countQuery := "SELECT COUNT(*) FROM (" + baseQuery + ") as count_table"
var totalCount int32
err := r.db.QueryRowxContext(ctx, r.db.Rebind(countQuery), args...).Scan(&totalCount)
if err != nil {
return nil, 0, handlePgErr(err, op)
}
offset := (filters.Page - 1) * filters.PageSize
baseQuery += " LIMIT ? OFFSET ?"
args = append(args, filters.PageSize, offset)
rows, err := r.db.QueryxContext(ctx, r.db.Rebind(baseQuery), args...)
if err != nil {
return nil, 0, handlePgErr(err, op)
}
defer rows.Close()
var solutions []*models.SolutionsListItem
for rows.Next() {
var solution models.SolutionsListItem
err = rows.StructScan(&solution)
if err != nil {
return nil, 0, handlePgErr(err, op)
}
solutions = append(solutions, &solution)
}
if err = rows.Err(); err != nil {
return nil, 0, handlePgErr(err, op)
}
return solutions, totalCount, nil
}