Merge pull request 'read the best solution for each task in contest' (#8) from get-contest-extension into develop

Reviewed-on: #8
Reviewed-by: Vyacheslav Birin <vyacheslav1557@noreply.localhost>
This commit is contained in:
Vyacheslav Birin 2025-04-14 11:38:34 +00:00
commit a2e0894728
5 changed files with 82 additions and 1 deletions

View file

@ -99,6 +99,15 @@ func (h *TesterHandlers) GetContest(c *fiber.Ctx, id int32) error {
return c.SendStatus(pkg.ToREST(err))
}
var participantId int32 = 2
solutions, err := h.contestsUC.ReadBestSolutions(c.Context(), id, participantId)
m := make(map[int32]*models.Solution)
for i := 0; i < len(solutions); i++ {
m[solutions[i].TaskPosition] = solutions[i]
}
resp := testerv1.GetContestResponse{
Contest: C2C(*contest),
Tasks: make([]struct {
@ -108,11 +117,15 @@ func (h *TesterHandlers) GetContest(c *fiber.Ctx, id int32) error {
}
for i, task := range tasks {
solution := testerv1.Solution{}
if sol, ok := m[task.Position]; ok {
solution = S2S(*sol)
}
resp.Tasks[i] = struct {
Solution testerv1.Solution `json:"solution"`
Task testerv1.TasksListItem `json:"task"`
}{
Solution: testerv1.Solution{},
Solution: solution,
Task: TLI2TLI(*task),
}
}

View file

@ -49,4 +49,5 @@ type ContestRepository interface {
ListSolutions(ctx context.Context, filter models.SolutionsFilter) (*models.SolutionsList, error)
ReadTask(ctx context.Context, id int32) (*models.Task, error)
ReadMonitor(ctx context.Context, id int32) (*models.Monitor, error)
ReadBestSolutions(ctx context.Context, contestId int32, participantId int32) ([]*models.Solution, error)
}

View file

@ -626,3 +626,65 @@ func (r *ContestRepository) ReadMonitor(ctx context.Context, contestId int32) (*
return &monitor, nil
}
const (
// state=5 - AC
readBestSolutions = `
WITH contest_tasks AS (
SELECT t.id AS task_id,
t.position AS task_position,
t.contest_id,
t.problem_id,
t.created_at,
t.updated_at,
p.title AS task_title,
c.title AS contest_title
FROM tasks t
LEFT JOIN problems p ON p.id = t.problem_id
LEFT JOIN contests c ON c.id = t.contest_id
WHERE t.contest_id = ?
),
best_solutions AS (
SELECT DISTINCT ON (s.task_id)
*
FROM solutions s
WHERE s.participant_id = ?
ORDER BY s.task_id, s.score DESC, s.created_at DESC
)
SELECT
s.id,
s.participant_id,
p.name AS participant_name,
s.solution,
s.state,
s.score,
s.penalty,
s.time_stat,
s.memory_stat,
s.language,
ct.task_id,
ct.task_position,
ct.task_title,
ct.contest_id,
ct.contest_title,
s.updated_at,
s.created_at
FROM contest_tasks ct
LEFT JOIN best_solutions s ON s.task_id = ct.task_id
LEFT JOIN participants p ON p.id = s.participant_id WHERE s.id IS NOT NULL
ORDER BY ct.task_position
`
)
func (r *ContestRepository) ReadBestSolutions(ctx context.Context, contestId int32, participantId int32) ([]*models.Solution, error) {
const op = "ContestRepository.ReadBestSolutions"
var solutions []*models.Solution
query := r.db.Rebind(readBestSolutions)
err := r.db.SelectContext(ctx, &solutions, query, contestId, participantId)
if err != nil {
return nil, handlePgErr(err, op)
}
return solutions, nil
}

View file

@ -31,4 +31,5 @@ type ContestUseCase interface {
ListSolutions(ctx context.Context, filter models.SolutionsFilter) (*models.SolutionsList, error)
ReadTask(ctx context.Context, id int32) (*models.Task, error)
ReadMonitor(ctx context.Context, id int32) (*models.Monitor, error)
ReadBestSolutions(ctx context.Context, contestId int32, participantId int32) ([]*models.Solution, error)
}

View file

@ -85,3 +85,7 @@ func (uc *ContestUseCase) ReadTask(ctx context.Context, id int32) (*models.Task,
func (uc *ContestUseCase) ReadMonitor(ctx context.Context, contestId int32) (*models.Monitor, error) {
return uc.contestRepo.ReadMonitor(ctx, contestId)
}
func (uc *ContestUseCase) ReadBestSolutions(ctx context.Context, contestId int32, participantId int32) ([]*models.Solution, error) {
return uc.contestRepo.ReadBestSolutions(ctx, contestId, participantId)
}