package postgres import ( "errors" "github.com/jackc/pgerrcode" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "code.nochebuena.dev/einherjar/core/xerrors" ) // HandleError maps pgx and PostgreSQL errors to typed [xerrors] values. // Returns nil when err is nil. Also available as [Provider.HandleError]. // // Mapped codes: // - UniqueViolation → ErrAlreadyExists // - ForeignKeyViolation → ErrInvalidInput // - CheckViolation → ErrInvalidInput // - pgx.ErrNoRows → ErrNotFound // - all others → ErrInternal func HandleError(err error) error { if err == nil { return nil } var pgErr *pgconn.PgError if errors.As(err, &pgErr) { switch pgErr.Code { case pgerrcode.UniqueViolation: return xerrors.New(xerrors.ErrAlreadyExists, "record already exists"). WithContext("constraint", pgErr.ConstraintName).WithError(err) case pgerrcode.ForeignKeyViolation: return xerrors.New(xerrors.ErrInvalidInput, "data integrity violation"). WithContext("table", pgErr.TableName).WithError(err) case pgerrcode.CheckViolation: return xerrors.New(xerrors.ErrInvalidInput, "data constraint violation"). WithContext("table", pgErr.TableName). WithContext("column", pgErr.ColumnName).WithError(err) } } if errors.Is(err, pgx.ErrNoRows) { return xerrors.New(xerrors.ErrNotFound, "record not found").WithError(err) } return xerrors.New(xerrors.ErrInternal, "unexpected database error").WithError(err) }