fix(tester): improve error handling

This commit is contained in:
Vyacheslav1557 2025-03-01 20:38:51 +05:00
parent c67405f584
commit e6088953b9
14 changed files with 103 additions and 206 deletions

View file

@ -2,6 +2,7 @@ package rest
import (
"git.sch9.ru/new_gate/ms-tester/internal/tester"
"git.sch9.ru/new_gate/ms-tester/pkg"
testerv1 "git.sch9.ru/new_gate/ms-tester/proto/tester/v1"
"github.com/gofiber/fiber/v2"
)
@ -29,7 +30,7 @@ func (h *TesterHandlers) ListProblems(c *fiber.Ctx) error {
func (h *TesterHandlers) CreateContest(c *fiber.Ctx) error {
id, err := h.contestsUC.CreateContest(c.Context(), "Название контеста")
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(testerv1.CreateContestResponse{
@ -40,7 +41,7 @@ func (h *TesterHandlers) CreateContest(c *fiber.Ctx) error {
func (h *TesterHandlers) DeleteContest(c *fiber.Ctx, id int32) error {
err := h.contestsUC.DeleteContest(c.Context(), id)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
@ -49,7 +50,7 @@ func (h *TesterHandlers) DeleteContest(c *fiber.Ctx, id int32) error {
func (h *TesterHandlers) GetContest(c *fiber.Ctx, id int32) error {
contest, err := h.contestsUC.ReadContestById(c.Context(), id)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(testerv1.GetContestResponse{
@ -65,7 +66,7 @@ func (h *TesterHandlers) GetContest(c *fiber.Ctx, id int32) error {
func (h *TesterHandlers) DeleteParticipant(c *fiber.Ctx, id int32, params testerv1.DeleteParticipantParams) error {
err := h.contestsUC.DeleteParticipant(c.Context(), params.ParticipantId)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
@ -74,7 +75,7 @@ func (h *TesterHandlers) DeleteParticipant(c *fiber.Ctx, id int32, params tester
func (h *TesterHandlers) AddParticipant(c *fiber.Ctx, id int32, params testerv1.AddParticipantParams) error {
id, err := h.contestsUC.AddParticipant(c.Context(), id, params.UserId)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(testerv1.AddParticipantResponse{
@ -85,7 +86,7 @@ func (h *TesterHandlers) AddParticipant(c *fiber.Ctx, id int32, params testerv1.
func (h *TesterHandlers) DeleteTask(c *fiber.Ctx, id int32, params testerv1.DeleteTaskParams) error {
err := h.contestsUC.DeleteTask(c.Context(), params.TaskId)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
@ -94,7 +95,7 @@ func (h *TesterHandlers) DeleteTask(c *fiber.Ctx, id int32, params testerv1.Dele
func (h *TesterHandlers) AddTask(c *fiber.Ctx, id int32, params testerv1.AddTaskParams) error {
id, err := h.contestsUC.AddTask(c.Context(), id, params.ProblemId)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusNotImplemented)
@ -103,7 +104,7 @@ func (h *TesterHandlers) AddTask(c *fiber.Ctx, id int32, params testerv1.AddTask
func (h *TesterHandlers) CreateProblem(c *fiber.Ctx) error {
id, err := h.problemsUC.CreateProblem(c.Context(), "Название задачи")
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(testerv1.CreateProblemResponse{
@ -114,7 +115,7 @@ func (h *TesterHandlers) CreateProblem(c *fiber.Ctx) error {
func (h *TesterHandlers) DeleteProblem(c *fiber.Ctx, id int32) error {
err := h.problemsUC.DeleteProblem(c.Context(), id)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
@ -124,7 +125,7 @@ func (h *TesterHandlers) DeleteProblem(c *fiber.Ctx, id int32) error {
func (h *TesterHandlers) GetProblem(c *fiber.Ctx, id int32) error {
problem, err := h.problemsUC.ReadProblemById(c.Context(), id)
if err != nil {
return err
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(

View file

@ -1,23 +1,27 @@
package repository
import (
"database/sql"
"errors"
"git.sch9.ru/new_gate/ms-tester/pkg/utils"
"git.sch9.ru/new_gate/ms-tester/pkg"
"github.com/jackc/pgerrcode"
"github.com/jackc/pgx/v5/pgconn"
)
func handlePgErr(err error) error {
func handlePgErr(err error, op string) error {
var pgErr *pgconn.PgError
if !errors.As(err, &pgErr) {
return utils.StorageError(err, utils.ErrUnknown, "unexpected error from postgres")
if errors.As(err, &pgErr) {
if pgerrcode.IsIntegrityConstraintViolation(pgErr.Code) {
return pkg.Wrap(pkg.ErrBadInput, err, op, pgErr.Message)
}
if pgerrcode.IsNoData(pgErr.Code) {
return pkg.Wrap(pkg.ErrNotFound, err, op, pgErr.Message)
}
}
if pgerrcode.IsIntegrityConstraintViolation(pgErr.Code) {
// TODO: probably should specify which constraint
return utils.StorageError(err, utils.ErrConflict, pgErr.Message)
if errors.Is(err, sql.ErrNoRows) {
return pkg.Wrap(pkg.ErrNotFound, err, op, "no rows found")
}
if pgerrcode.IsNoData(pgErr.Code) {
return utils.StorageError(err, utils.ErrNotFound, pgErr.Message)
}
return utils.StorageError(err, utils.ErrUnimplemented, "unimplemented error")
return pkg.Wrap(pkg.ErrUnhandled, err, op, "unexpected error")
}

View file

@ -22,11 +22,13 @@ func NewContestRepository(db *sqlx.DB, logger *zap.Logger) *ContestRepository {
const createContestQuery = "INSERT INTO contests (title) VALUES (?) RETURNING id"
func (r *ContestRepository) CreateContest(ctx context.Context, title string) (int32, error) {
const op = "ContestRepository.CreateContest"
query := r.db.Rebind(createContestQuery)
rows, err := r.db.QueryxContext(ctx, query, title)
if err != nil {
return 0, handlePgErr(err)
return 0, handlePgErr(err, op)
}
defer rows.Close()
@ -34,7 +36,7 @@ func (r *ContestRepository) CreateContest(ctx context.Context, title string) (in
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, handlePgErr(err)
return 0, handlePgErr(err, op)
}
return id, nil
@ -43,11 +45,13 @@ func (r *ContestRepository) CreateContest(ctx context.Context, title string) (in
const readContestByIdQuery = "SELECT * from contests WHERE id=? LIMIT 1"
func (r *ContestRepository) ReadContestById(ctx context.Context, id int32) (*models.Contest, error) {
const op = "ContestRepository.ReadContestById"
var contest models.Contest
query := r.db.Rebind(readContestByIdQuery)
err := r.db.GetContext(ctx, &contest, query, id)
if err != nil {
return nil, handlePgErr(err)
return nil, handlePgErr(err, op)
}
return &contest, nil
}
@ -55,10 +59,12 @@ func (r *ContestRepository) ReadContestById(ctx context.Context, id int32) (*mod
const deleteContestQuery = "DELETE FROM contests WHERE id=?"
func (r *ContestRepository) DeleteContest(ctx context.Context, id int32) error {
const op = "ContestRepository.DeleteContest"
query := r.db.Rebind(deleteContestQuery)
_, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return handlePgErr(err)
return handlePgErr(err, op)
}
return nil
@ -67,17 +73,19 @@ func (r *ContestRepository) DeleteContest(ctx context.Context, id int32) error {
const addTaskQuery = "INSERT INTO tasks (problem_id, contest_id, position) VALUES (?, ?,COALESCE(SELECT MAX(position) FROM task WHERE contest_id = ? ,0) + 1) RETURNING id"
func (r *ContestRepository) AddTask(ctx context.Context, contestId int32, problem_id int32) (int32, error) {
const op = "ContestRepository.AddTask"
query := r.db.Rebind(addTaskQuery)
rows, err := r.db.QueryxContext(ctx, query, problem_id, contestId, contestId)
if err != nil {
return 0, handlePgErr(err)
return 0, handlePgErr(err, op)
}
defer rows.Close()
var id int32
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, handlePgErr(err)
return 0, handlePgErr(err, op)
}
return id, nil
}
@ -85,10 +93,12 @@ func (r *ContestRepository) AddTask(ctx context.Context, contestId int32, proble
const deleteTaskQuery = "DELETE FROM tasks WHERE id=?"
func (r *ContestRepository) DeleteTask(ctx context.Context, taskId int32) error {
const op = "ContestRepository.DeleteTask"
query := r.db.Rebind(deleteTaskQuery)
_, err := r.db.ExecContext(ctx, query, taskId)
if err != nil {
return handlePgErr(err)
return handlePgErr(err, op)
}
return nil
}
@ -96,11 +106,13 @@ func (r *ContestRepository) DeleteTask(ctx context.Context, taskId int32) error
const addParticipantQuery = "INSERT INTO participants (user_id ,contest_id, name) VALUES (?, ?, ?) RETURNING id"
func (r *ContestRepository) AddParticipant(ctx context.Context, contestId int32, userId int32) (int32, error) {
const op = "ContestRepository.AddParticipant"
query := r.db.Rebind(addParticipantQuery)
name := ""
rows, err := r.db.QueryxContext(ctx, query, contestId, userId, name)
if err != nil {
return 0, handlePgErr(err)
return 0, handlePgErr(err, op)
}
defer rows.Close()
var id int32
@ -115,10 +127,12 @@ func (r *ContestRepository) AddParticipant(ctx context.Context, contestId int32,
const deleteParticipantQuery = "DELETE FROM participants WHERE id=?"
func (r *ContestRepository) DeleteParticipant(ctx context.Context, participantId int32) error {
const op = "ContestRepository.DeleteParticipant"
query := r.db.Rebind(deleteParticipantQuery)
_, err := r.db.ExecContext(ctx, query, participantId)
if err != nil {
return handlePgErr(err)
return handlePgErr(err, op)
}
return nil
}

View file

@ -22,10 +22,12 @@ func NewProblemRepository(db *sqlx.DB, logger *zap.Logger) *ProblemRepository {
const createProblemQuery = "INSERT INTO problems (title) VALUES (?) RETURNING id"
func (r *ProblemRepository) CreateProblem(ctx context.Context, title string) (int32, error) {
const op = "ProblemRepository.CreateProblem"
query := r.db.Rebind(createProblemQuery)
rows, err := r.db.QueryxContext(ctx, query, title)
if err != nil {
return 0, handlePgErr(err)
return 0, handlePgErr(err, op)
}
defer rows.Close()
@ -33,7 +35,7 @@ func (r *ProblemRepository) CreateProblem(ctx context.Context, title string) (in
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, handlePgErr(err)
return 0, handlePgErr(err, op)
}
return id, nil
@ -42,11 +44,13 @@ func (r *ProblemRepository) CreateProblem(ctx context.Context, title string) (in
const readProblemQuery = "SELECT * from problems WHERE id=? LIMIT 1"
func (r *ProblemRepository) ReadProblemById(ctx context.Context, id int32) (*models.Problem, error) {
const op = "ProblemRepository.ReadProblemById"
var problem models.Problem
query := r.db.Rebind(readProblemQuery)
err := r.db.GetContext(ctx, &problem, query, id)
if err != nil {
return nil, handlePgErr(err)
return nil, handlePgErr(err, op)
}
return &problem, nil
}
@ -54,10 +58,12 @@ func (r *ProblemRepository) ReadProblemById(ctx context.Context, id int32) (*mod
const deleteProblemQuery = "DELETE FROM problems WHERE id=?"
func (r *ProblemRepository) DeleteProblem(ctx context.Context, id int32) error {
const op = "ProblemRepository.DeleteProblem"
query := r.db.Rebind(deleteProblemQuery)
_, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return handlePgErr(err)
return handlePgErr(err, op)
}
return nil