1 package gqlerror
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7 "strconv"
8
9 "github.com/vektah/gqlparser/v2/ast"
10 )
11
12
13 type Error struct {
14 Err error `json:"-"`
15 Message string `json:"message"`
16 Path ast.Path `json:"path,omitempty"`
17 Locations []Location `json:"locations,omitempty"`
18 Extensions map[string]interface{} `json:"extensions,omitempty"`
19 Rule string `json:"-"`
20 }
21
22 func (err *Error) SetFile(file string) {
23 if file == "" {
24 return
25 }
26 if err.Extensions == nil {
27 err.Extensions = map[string]interface{}{}
28 }
29
30 err.Extensions["file"] = file
31 }
32
33 type Location struct {
34 Line int `json:"line,omitempty"`
35 Column int `json:"column,omitempty"`
36 }
37
38 type List []*Error
39
40 func (err *Error) Error() string {
41 var res bytes.Buffer
42 if err == nil {
43 return ""
44 }
45 filename, _ := err.Extensions["file"].(string)
46 if filename == "" {
47 filename = "input"
48 }
49 res.WriteString(filename)
50
51 if len(err.Locations) > 0 {
52 res.WriteByte(':')
53 res.WriteString(strconv.Itoa(err.Locations[0].Line))
54 }
55
56 res.WriteString(": ")
57 if ps := err.pathString(); ps != "" {
58 res.WriteString(ps)
59 res.WriteByte(' ')
60 }
61
62 res.WriteString(err.Message)
63
64 return res.String()
65 }
66
67 func (err *Error) pathString() string {
68 return err.Path.String()
69 }
70
71 func (err *Error) Unwrap() error {
72 return err.Err
73 }
74
75 func (err *Error) AsError() error {
76 if err == nil {
77 return nil
78 }
79 return err
80 }
81
82 func (errs List) Error() string {
83 var buf bytes.Buffer
84 for _, err := range errs {
85 buf.WriteString(err.Error())
86 buf.WriteByte('\n')
87 }
88 return buf.String()
89 }
90
91 func (errs List) Is(target error) bool {
92 for _, err := range errs {
93 if errors.Is(err, target) {
94 return true
95 }
96 }
97 return false
98 }
99
100 func (errs List) As(target interface{}) bool {
101 for _, err := range errs {
102 if errors.As(err, target) {
103 return true
104 }
105 }
106 return false
107 }
108
109 func (errs List) Unwrap() []error {
110 l := make([]error, len(errs))
111 for i, err := range errs {
112 l[i] = err
113 }
114 return l
115 }
116
117 func WrapPath(path ast.Path, err error) *Error {
118 if err == nil {
119 return nil
120 }
121 return &Error{
122 Err: err,
123 Message: err.Error(),
124 Path: path,
125 }
126 }
127
128 func Wrap(err error) *Error {
129 if err == nil {
130 return nil
131 }
132 return &Error{
133 Err: err,
134 Message: err.Error(),
135 }
136 }
137
138 func WrapIfUnwrapped(err error) *Error {
139 if err == nil {
140 return nil
141 }
142 if gqlErr, ok := err.(*Error); ok {
143 return gqlErr
144 }
145 return &Error{
146 Err: err,
147 Message: err.Error(),
148 }
149 }
150
151 func Errorf(message string, args ...interface{}) *Error {
152 return &Error{
153 Message: fmt.Sprintf(message, args...),
154 }
155 }
156
157 func ErrorPathf(path ast.Path, message string, args ...interface{}) *Error {
158 return &Error{
159 Message: fmt.Sprintf(message, args...),
160 Path: path,
161 }
162 }
163
164 func ErrorPosf(pos *ast.Position, message string, args ...interface{}) *Error {
165 return ErrorLocf(
166 pos.Src.Name,
167 pos.Line,
168 pos.Column,
169 message,
170 args...,
171 )
172 }
173
174 func ErrorLocf(file string, line int, col int, message string, args ...interface{}) *Error {
175 var extensions map[string]interface{}
176 if file != "" {
177 extensions = map[string]interface{}{"file": file}
178 }
179 return &Error{
180 Message: fmt.Sprintf(message, args...),
181 Extensions: extensions,
182 Locations: []Location{
183 {Line: line, Column: col},
184 },
185 }
186 }
187
View as plain text