package gqlerror import ( "bytes" "errors" "fmt" "strconv" "github.com/vektah/gqlparser/v2/ast" ) // Error is the standard graphql error type described in https://spec.graphql.org/draft/#sec-Errors type Error struct { Err error `json:"-"` Message string `json:"message"` Path ast.Path `json:"path,omitempty"` Locations []Location `json:"locations,omitempty"` Extensions map[string]interface{} `json:"extensions,omitempty"` Rule string `json:"-"` } func (err *Error) SetFile(file string) { if file == "" { return } if err.Extensions == nil { err.Extensions = map[string]interface{}{} } err.Extensions["file"] = file } type Location struct { Line int `json:"line,omitempty"` Column int `json:"column,omitempty"` } type List []*Error func (err *Error) Error() string { var res bytes.Buffer if err == nil { return "" } filename, _ := err.Extensions["file"].(string) if filename == "" { filename = "input" } res.WriteString(filename) if len(err.Locations) > 0 { res.WriteByte(':') res.WriteString(strconv.Itoa(err.Locations[0].Line)) } res.WriteString(": ") if ps := err.pathString(); ps != "" { res.WriteString(ps) res.WriteByte(' ') } res.WriteString(err.Message) return res.String() } func (err *Error) pathString() string { return err.Path.String() } func (err *Error) Unwrap() error { return err.Err } func (err *Error) AsError() error { if err == nil { return nil } return err } func (errs List) Error() string { var buf bytes.Buffer for _, err := range errs { buf.WriteString(err.Error()) buf.WriteByte('\n') } return buf.String() } func (errs List) Is(target error) bool { for _, err := range errs { if errors.Is(err, target) { return true } } return false } func (errs List) As(target interface{}) bool { for _, err := range errs { if errors.As(err, target) { return true } } return false } func (errs List) Unwrap() []error { l := make([]error, len(errs)) for i, err := range errs { l[i] = err } return l } func WrapPath(path ast.Path, err error) *Error { if err == nil { return nil } return &Error{ Err: err, Message: err.Error(), Path: path, } } func Wrap(err error) *Error { if err == nil { return nil } return &Error{ Err: err, Message: err.Error(), } } func WrapIfUnwrapped(err error) *Error { if err == nil { return nil } if gqlErr, ok := err.(*Error); ok { return gqlErr } return &Error{ Err: err, Message: err.Error(), } } func Errorf(message string, args ...interface{}) *Error { return &Error{ Message: fmt.Sprintf(message, args...), } } func ErrorPathf(path ast.Path, message string, args ...interface{}) *Error { return &Error{ Message: fmt.Sprintf(message, args...), Path: path, } } func ErrorPosf(pos *ast.Position, message string, args ...interface{}) *Error { return ErrorLocf( pos.Src.Name, pos.Line, pos.Column, message, args..., ) } func ErrorLocf(file string, line int, col int, message string, args ...interface{}) *Error { var extensions map[string]interface{} if file != "" { extensions = map[string]interface{}{"file": file} } return &Error{ Message: fmt.Sprintf(message, args...), Extensions: extensions, Locations: []Location{ {Line: line, Column: col}, }, } }