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/admin | |
| 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/admin')
| -rw-r--r-- | backend/admin/handler.go | 68 |
1 files changed, 27 insertions, 41 deletions
diff --git a/backend/admin/handler.go b/backend/admin/handler.go index e8a7921..6ca0a3f 100644 --- a/backend/admin/handler.go +++ b/backend/admin/handler.go @@ -10,7 +10,6 @@ import ( "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" - "github.com/jackc/pgx/v5/pgxpool" "github.com/labstack/echo/v4" "albatross-2026-backend/account" @@ -22,13 +21,13 @@ import ( var jst = time.FixedZone("Asia/Tokyo", 9*60*60) type Handler struct { - q *db.Queries - pool *pgxpool.Pool + q db.Querier + txm db.TxManager conf *config.Config } -func NewHandler(q *db.Queries, pool *pgxpool.Pool, conf *config.Config) *Handler { - return &Handler{q: q, pool: pool, conf: conf} +func NewHandler(q db.Querier, txm db.TxManager, conf *config.Config) *Handler { + return &Handler{q: q, txm: txm, conf: conf} } func (h *Handler) newAdminMiddleware() echo.MiddlewareFunc { @@ -506,48 +505,35 @@ func (h *Handler) postGameEdit(c echo.Context) error { } ctx := c.Request().Context() - tx, err := h.pool.Begin(ctx) - if err != nil { - return 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) + err = h.txm.RunInTx(ctx, func(qtx db.Querier) error { + if err := qtx.UpdateGame(ctx, db.UpdateGameParams{ + GameID: int32(gameID), + GameType: gameType, + IsPublic: isPublic, + DisplayName: displayName, + DurationSeconds: int32(durationSeconds), + StartedAt: changedStartedAt, + ProblemID: int32(problemID), + }); err != nil { + return err } - }() - - qtx := h.q.WithTx(tx) - err = qtx.UpdateGame(ctx, db.UpdateGameParams{ - GameID: int32(gameID), - GameType: gameType, - IsPublic: isPublic, - DisplayName: displayName, - DurationSeconds: int32(durationSeconds), - StartedAt: changedStartedAt, - ProblemID: int32(problemID), + if err := qtx.RemoveAllMainPlayers(ctx, int32(gameID)); err != nil { + return err + } + for _, userID := range mainPlayers { + if err := qtx.AddMainPlayer(ctx, db.AddMainPlayerParams{ + GameID: int32(gameID), + UserID: int32(userID), + }); err != nil { + return err + } + } + return nil }) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } - err = qtx.RemoveAllMainPlayers(ctx, int32(gameID)) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - for _, userID := range mainPlayers { - err = qtx.AddMainPlayer(ctx, db.AddMainPlayerParams{ - GameID: int32(gameID), - UserID: int32(userID), - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - } - - if err := tx.Commit(ctx); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - return c.Redirect(http.StatusSeeOther, h.conf.BasePath+"admin/games") } |
