diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-15 22:13:50 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-15 22:16:22 +0900 |
| commit | 5ed369a6c70707543fd5ec9a13c79851fdfc5d6c (patch) | |
| tree | e5678d6d88fab3ac0ae8c05b85236f3e7d5eddfd /backend/api/handler.go | |
| parent | 87e9f5ed48af3a8dca5f6373ae900336f285eef5 (diff) | |
| download | phperkaigi-2026-albatross-5ed369a6c70707543fd5ec9a13c79851fdfc5d6c.tar.gz phperkaigi-2026-albatross-5ed369a6c70707543fd5ec9a13c79851fdfc5d6c.tar.zst phperkaigi-2026-albatross-5ed369a6c70707543fd5ec9a13c79851fdfc5d6c.zip | |
refactor(backend): introduce DI interfaces for testability
Replace concrete *db.Queries and *pgxpool.Pool dependencies with
db.Querier and db.TxManager interfaces across all handlers, game hub,
and auth. This enables unit testing with mocks.
- Enable sqlc emit_interface to generate Querier interface
- Add TxManager abstraction to encapsulate transactions
- Convert auth package-level functions to Authenticator struct
- Add TaskQueueInterface/TaskWorkerInterface for game.Hub
- Add initial unit tests for game logic and API handlers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'backend/api/handler.go')
| -rw-r--r-- | backend/api/handler.go | 57 |
1 files changed, 25 insertions, 32 deletions
diff --git a/backend/api/handler.go b/backend/api/handler.go index 3fe7e3c..7efacf3 100644 --- a/backend/api/handler.go +++ b/backend/api/handler.go @@ -11,7 +11,6 @@ import ( "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" - "github.com/jackc/pgx/v5/pgxpool" "github.com/labstack/echo/v4" "github.com/oapi-codegen/nullable" @@ -20,10 +19,15 @@ import ( "albatross-2026-backend/db" ) +type AuthenticatorInterface interface { + Login(ctx context.Context, username, password string) (int, error) +} + type Handler struct { - q *db.Queries - pool *pgxpool.Pool + q db.Querier + txm db.TxManager hub GameHubInterface + auth AuthenticatorInterface conf *config.Config } @@ -47,7 +51,7 @@ func (r postLoginCookieResponse) VisitPostLoginResponse(w http.ResponseWriter) e func (h *Handler) PostLogin(ctx context.Context, request PostLoginRequestObject) (PostLoginResponseObject, error) { username := request.Body.Username password := request.Body.Password - userID, err := auth.Login(ctx, h.q, h.pool, username, password) + userID, err := h.auth.Login(ctx, username, password) if err != nil { slog.Error("login failed", "error", err) var msg string @@ -419,40 +423,29 @@ func (h *Handler) PostGamePlaySubmit(ctx context.Context, request PostGamePlaySu }, nil } - tx, err := h.pool.Begin(ctx) - if err != nil { - return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - defer func() { - if err := tx.Rollback(ctx); err != nil && err != pgx.ErrTxClosed { - slog.Error("failed to rollback transaction", "error", err) + var submissionID int32 + err = h.txm.RunInTx(ctx, func(qtx db.Querier) error { + if err := qtx.UpdateCodeAndStatus(ctx, db.UpdateCodeAndStatusParams{ + GameID: int32(gameID), + UserID: user.UserID, + Code: code, + Status: "running", + }); err != nil { + return err } - }() - - qtx := h.q.WithTx(tx) - err = qtx.UpdateCodeAndStatus(ctx, db.UpdateCodeAndStatusParams{ - GameID: int32(gameID), - UserID: user.UserID, - Code: code, - Status: "running", - }) - if err != nil { - return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - submissionID, err := qtx.CreateSubmission(ctx, db.CreateSubmissionParams{ - GameID: int32(gameID), - UserID: user.UserID, - Code: code, - CodeSize: int32(codeSize), + var err error + submissionID, err = qtx.CreateSubmission(ctx, db.CreateSubmissionParams{ + GameID: int32(gameID), + UserID: user.UserID, + Code: code, + CodeSize: int32(codeSize), + }) + return err }) if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } - if err := tx.Commit(ctx); err != nil { - return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - err = h.hub.EnqueueTestTasks(ctx, int(submissionID), gameID, int(user.UserID), language, code) if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) |
