package api import ( "errors" "log" "github.com/danielgtaylor/huma/v2" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" ) // Postgres error codes this package maps to specific HTTP statuses. // See https://www.postgresql.org/docs/current/errcodes-appendix.html const ( pgCodeUniqueViolation = "23505" pgCodeForeignKeyViolation = "23503" ) // dbError turns a database error into the huma error a handler should // return, so Postgres's own error text never reaches a client and callers // get the right HTTP status instead of a generic 500. func dbError(err error) error { if errors.Is(err, pgx.ErrNoRows) { return huma.Error404NotFound("not found") } var pgErr *pgconn.PgError if errors.As(err, &pgErr) { switch pgErr.Code { case pgCodeUniqueViolation: return huma.Error409Conflict("already exists") case pgCodeForeignKeyViolation: // A foreign key failure here is either a reference to a platform // that doesn't exist (create/update) or a delete blocked by // games that still reference this platform. return huma.Error409Conflict("referenced by another record, or refers to one that doesn't exist") } } log.Printf("unmapped database error: %v", err) return huma.Error500InternalServerError("internal error") } // notFoundIfZero turns the "0 rows affected" result of a soft-delete // UPDATE into a 404, since the row either never existed or was already // deleted. func notFoundIfZero(rows int64) error { if rows == 0 { return huma.Error404NotFound("not found") } return nil }