aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/api/handler.go
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-15 22:13:50 +0900
committernsfisis <nsfisis@gmail.com>2026-02-15 22:16:22 +0900
commit5ed369a6c70707543fd5ec9a13c79851fdfc5d6c (patch)
treee5678d6d88fab3ac0ae8c05b85236f3e7d5eddfd /backend/api/handler.go
parent87e9f5ed48af3a8dca5f6373ae900336f285eef5 (diff)
downloadphperkaigi-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.go57
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())