222 lines
5.3 KiB
Go
222 lines
5.3 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
|
"git.sch9.ru/new_gate/ms-tester/pkg"
|
|
sq "github.com/Masterminds/squirrel"
|
|
)
|
|
|
|
const (
|
|
GetSolutionQuery = "SELECT * FROM solutions WHERE id = $1"
|
|
)
|
|
|
|
func (r *Repository) GetSolution(ctx context.Context, id int32) (*models.Solution, error) {
|
|
const op = "Repository.GetSolution"
|
|
|
|
var solution models.Solution
|
|
err := r.db.GetContext(ctx, &solution, GetSolutionQuery, id)
|
|
if err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
|
|
return &solution, nil
|
|
}
|
|
|
|
const (
|
|
CreateSolutionQuery = `INSERT INTO solutions (task_id, participant_id, language, penalty, solution)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING id`
|
|
)
|
|
|
|
func (r *Repository) CreateSolution(ctx context.Context, creation *models.SolutionCreation) (int32, error) {
|
|
const op = "Repository.CreateSolution"
|
|
|
|
rows, err := r.db.QueryxContext(ctx,
|
|
CreateSolutionQuery,
|
|
creation.TaskId,
|
|
creation.ParticipantId,
|
|
creation.Language,
|
|
creation.Penalty,
|
|
creation.Solution,
|
|
)
|
|
if err != nil {
|
|
return 0, pkg.HandlePgErr(err, op)
|
|
}
|
|
|
|
defer rows.Close()
|
|
var id int32
|
|
rows.Next()
|
|
err = rows.Scan(&id)
|
|
if err != nil {
|
|
return 0, pkg.HandlePgErr(err, op)
|
|
}
|
|
|
|
return id, nil
|
|
}
|
|
|
|
func buildListSolutionsQueries(filter models.SolutionsFilter) (sq.SelectBuilder, sq.SelectBuilder) {
|
|
columns := []string{
|
|
"s.id",
|
|
"s.participant_id",
|
|
"p2.name AS participant_name",
|
|
"s.state",
|
|
"s.score",
|
|
"s.penalty",
|
|
"s.time_stat",
|
|
"s.memory_stat",
|
|
"s.language",
|
|
"s.task_id",
|
|
"t.position AS task_position",
|
|
"p.title AS task_title",
|
|
"t.contest_id",
|
|
"c.title",
|
|
"s.updated_at",
|
|
"s.created_at",
|
|
}
|
|
|
|
qb := sq.StatementBuilder.PlaceholderFormat(sq.Dollar).Select(columns...).
|
|
From("solutions s").
|
|
LeftJoin("tasks t ON s.task_id = t.id").
|
|
LeftJoin("problems p ON t.problem_id = p.id").
|
|
LeftJoin("contests c ON t.contest_id = c.id").
|
|
LeftJoin("participants p2 ON s.participant_id = p2.id")
|
|
|
|
if filter.ContestId != nil {
|
|
qb = qb.Where(sq.Eq{"s.contest_id": *filter.ContestId})
|
|
}
|
|
if filter.ParticipantId != nil {
|
|
qb = qb.Where(sq.Eq{"s.participant_id": *filter.ParticipantId})
|
|
}
|
|
if filter.TaskId != nil {
|
|
qb = qb.Where(sq.Eq{"s.task_id": *filter.TaskId})
|
|
}
|
|
if filter.Language != nil {
|
|
qb = qb.Where(sq.Eq{"s.language": *filter.Language})
|
|
}
|
|
if filter.State != nil {
|
|
qb = qb.Where(sq.Eq{"s.state": *filter.State})
|
|
}
|
|
|
|
countQb := sq.Select("COUNT(*)").FromSelect(qb, "sub")
|
|
|
|
if filter.Order != nil && *filter.Order < 0 {
|
|
qb = qb.OrderBy("s.id DESC")
|
|
} else {
|
|
qb = qb.OrderBy("s.id ASC")
|
|
}
|
|
|
|
qb = qb.Limit(uint64(filter.PageSize)).Offset(uint64(filter.Offset()))
|
|
|
|
return qb, countQb
|
|
}
|
|
|
|
func (r *Repository) ListSolutions(ctx context.Context, filter models.SolutionsFilter) (*models.SolutionsList, error) {
|
|
const op = "ContestRepository.ListSolutions"
|
|
|
|
baseQb, countQb := buildListSolutionsQueries(filter)
|
|
|
|
query, args, err := countQb.ToSql()
|
|
if err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
|
|
var totalCount int32
|
|
err = r.db.GetContext(ctx, &totalCount, query, args...)
|
|
if err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
|
|
query, args, err = baseQb.ToSql()
|
|
if err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
rows, err := r.db.QueryxContext(ctx, query, args...)
|
|
if err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
defer rows.Close()
|
|
|
|
solutions := make([]*models.SolutionsListItem, 0)
|
|
for rows.Next() {
|
|
var solution models.SolutionsListItem
|
|
err = rows.StructScan(&solution)
|
|
if err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
solutions = append(solutions, &solution)
|
|
}
|
|
|
|
if err = rows.Err(); err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
|
|
return &models.SolutionsList{
|
|
Solutions: solutions,
|
|
Pagination: models.Pagination{
|
|
Total: models.Total(totalCount, filter.PageSize),
|
|
Page: filter.Page,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
const (
|
|
// state=5 - AC
|
|
GetBestSolutions = `
|
|
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.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 *Repository) GetBestSolutions(ctx context.Context, contestId int32, participantId int32) ([]*models.SolutionsListItem, error) {
|
|
const op = "Repository.GetBestSolutions"
|
|
var solutions []*models.SolutionsListItem
|
|
query := r.db.Rebind(GetBestSolutions)
|
|
err := r.db.SelectContext(ctx, &solutions, query, contestId, participantId)
|
|
|
|
if err != nil {
|
|
return nil, pkg.HandlePgErr(err, op)
|
|
}
|
|
|
|
return solutions, nil
|
|
}
|