tableau
tableau copied to clipboard
ecode: add `xerrors.Is` API to check ecode in error
- Implement custom xerrors package with advanced features, based on source code from https://pkg.go.dev/errors and https://github.com/rotisserie/eris
- Add APIs to xerrors/error.go :
// Is reports whether any error in err's tree matches code.
func Is(err error, code tableaupb.Code) bool {
return Code(err) == code
}
// Code returns the top-level code wrapped in error in err's tree.
func Code(err error) tableaupb.Code {
if err == nil {
return tableaupb.Code_SUCCESS
}
for err != nil {
cause, ok := err.(xcauser)
if !ok {
break
}
if w, ok := err.(*withCode); ok {
return w.Code()
}
err = cause.Cause()
}
return tableaupb.Code_ERR_UNKNOWN
}
Customizing error tests with Is and As methods
The errors.Is function examines each error in a chain for a match with a target value. By default, an error matches the target if the two are equal. In addition, an error in the chain may declare that it matches a target by implementing an Is method.
As an example, consider this error inspired by the Upspin error package which compares an error against a template, considering only fields which are non-zero in the template:
type Error struct {
Path string
User string
}
func (e *Error) Is(target error) bool {
t, ok := target.(*Error)
if !ok {
return false
}
return (e.Path == t.Path || t.Path == "") &&
(e.User == t.User || t.User == "")
}
if errors.Is(err, &Error{User: "someuser"}) {
// err's User field is "someuser".
}
The errors.As function similarly consults an As method when present.
Solution
Use protobuf enum to define error code in proto/tableau/protobuf/internal/code.proto:
enum Code {
ERR_UNKNOWN = -1;
OK = 0;
ERR_SHEET_NOT_FOUND = 1;
// ...
}
References
- Effective Error Handling in Golang
- The Go Blog: Working with Errors in Go 1.13
- Error Inspection — Draft Design
- The Go Blog: Errors are values
- Format errors in Go - %s %v or %w
- https://pkg.go.dev/errors#Is
- https://pkg.go.dev/errors#As