@@ -21,6 +21,16 @@ import (
2121 "strings"
2222)
2323
24+ // ErrCode represents a specific error type in a error class.
25+ // Same error code can be used in different error classes.
26+ type ErrCode int
27+
28+ // ErrCodeText is a textual error code that represents a specific error type in a error class.
29+ type ErrCodeText string
30+
31+ type ErrorID string
32+ type RFCErrorCode string
33+
2434// Error is the 'prototype' of a type of errors.
2535// Use DefineError to make a *Error:
2636// var ErrUnavailable = ClassRegion.DefineError().
@@ -46,29 +56,25 @@ import (
4656// // handle this error.
4757// }
4858type Error struct {
49- class * ErrClass
50- code ErrCode
59+ code ErrCode
5160 // codeText is the textual describe of the error code
5261 codeText ErrCodeText
5362 // message is a template of the description of this error.
5463 // printf-style formatting is enabled.
5564 message string
5665 // The workaround field: how to work around this error.
5766 // It's used to teach the users how to solve the error if occurring in the real environment.
58- Workaround string
67+ workaround string
5968 // Description is the expanded detail of why this error occurred.
6069 // This could be written by developer at a static env,
6170 // and the more detail this field explaining the better,
6271 // even some guess of the cause could be included.
63- Description string
64- args []interface {}
65- file string
66- line int
67- }
68-
69- // Class returns ErrClass
70- func (e * Error ) Class () * ErrClass {
71- return e .class
72+ description string
73+ // Cause is used to warp some third party error.
74+ cause error
75+ args []interface {}
76+ file string
77+ line int
7278}
7379
7480// Code returns the numeric code of this error.
@@ -84,23 +90,7 @@ func (e *Error) Code() ErrCode {
8490// The error code is a 3-tuple of abbreviated component name, error class and error code,
8591// joined by a colon like {Component}:{ErrorClass}:{InnerErrorCode}.
8692func (e * Error ) RFCCode () RFCErrorCode {
87- ec := e .Class ()
88- if ec == nil {
89- return RFCErrorCode (e .ID ())
90- }
91- reg := ec .registry
92- // Maybe top-level errors.
93- if reg .Name == "" {
94- return RFCErrorCode (fmt .Sprintf ("%s:%s" ,
95- ec .Description ,
96- e .ID (),
97- ))
98- }
99- return RFCErrorCode (fmt .Sprintf ("%s:%s:%s" ,
100- reg .Name ,
101- ec .Description ,
102- e .ID (),
103- ))
93+ return RFCErrorCode (e .ID ())
10494}
10595
10696// ID returns the ID of this error.
@@ -124,14 +114,17 @@ func (e *Error) MessageTemplate() string {
124114
125115// Error implements error interface.
126116func (e * Error ) Error () string {
117+ if e == nil {
118+ return "<nil>"
119+ }
127120 describe := e .codeText
128121 if len (describe ) == 0 {
129122 describe = ErrCodeText (strconv .Itoa (int (e .code )))
130123 }
131- return fmt .Sprintf ("[%s] %s" , e .RFCCode (), e .getMsg ())
124+ return fmt .Sprintf ("[%s]%s" , e .RFCCode (), e .GetMsg ())
132125}
133126
134- func (e * Error ) getMsg () string {
127+ func (e * Error ) GetMsg () string {
135128 if len (e .args ) > 0 {
136129 return fmt .Sprintf (e .message , e .args ... )
137130 }
@@ -197,9 +190,8 @@ func (e *Error) Equal(err error) bool {
197190 if ! ok {
198191 return false
199192 }
200- classEquals := e .class .Equal (inErr .class )
201193 idEquals := e .ID () == inErr .ID ()
202- return classEquals && idEquals
194+ return idEquals
203195}
204196
205197// NotEqual checks if err is not equal to e.
@@ -239,7 +231,6 @@ type jsonError struct {
239231 Error string `json:"message"`
240232 Description string `json:"description,omitempty"`
241233 Workaround string `json:"workaround,omitempty"`
242- Class ErrClassID `json:"classID"`
243234 File string `json:"file"`
244235 Line int `json:"line"`
245236}
@@ -251,11 +242,10 @@ type jsonError struct {
251242// This function is reserved for compatibility.
252243func (e * Error ) MarshalJSON () ([]byte , error ) {
253244 return json .Marshal (& jsonError {
254- Error : e .getMsg (),
255- Description : e .Description ,
256- Workaround : e .Workaround ,
245+ Error : e .GetMsg (),
246+ Description : e .description ,
247+ Workaround : e .workaround ,
257248 RFCCode : e .RFCCode (),
258- Class : e .class .ID ,
259249 Line : e .line ,
260250 File : e .file ,
261251 })
@@ -273,21 +263,90 @@ func (e *Error) UnmarshalJSON(data []byte) error {
273263 return Trace (err )
274264 }
275265 codes := strings .Split (string (err .RFCCode ), ":" )
276- regName := codes [0 ]
277- className := codes [1 ]
278- innerCode := codes [2 ]
266+ innerCode := codes [len (codes )- 1 ]
279267 if i , errAtoi := strconv .Atoi (innerCode ); errAtoi == nil {
280268 e .code = ErrCode (i )
281- } else {
282- e .codeText = ErrCodeText (innerCode )
283269 }
270+ e .codeText = ErrCodeText (err .RFCCode )
284271 e .line = err .Line
285272 e .file = err .File
286273 e .message = err .Error
287- e .class = & ErrClass {
288- Description : className ,
289- ID : err .Class ,
290- registry : & Registry {Name : regName },
291- }
292274 return nil
293275}
276+
277+ func (e * Error ) Wrap (err error ) * Error {
278+ if err != nil {
279+ newErr := * e
280+ newErr .cause = err
281+ return & newErr
282+ }
283+ return e
284+ }
285+
286+ func (e * Error ) Cause () error {
287+ root := Unwrap (e .cause )
288+ if root == nil {
289+ return e .cause
290+ }
291+ return root
292+ }
293+
294+ func (e * Error ) FastGenWithCause (args ... interface {}) error {
295+ err := * e
296+ if e .cause != nil {
297+ err .message = e .cause .Error ()
298+ }
299+ err .args = args
300+ return SuspendStack (& err )
301+ }
302+
303+ func (e * Error ) GenWithStackByCause (args ... interface {}) error {
304+ err := * e
305+ if e .cause != nil {
306+ err .message = e .cause .Error ()
307+ }
308+ err .args = args
309+ err .fillLineAndFile (1 )
310+ return AddStack (& err )
311+ }
312+
313+ type NormalizeOption func (* Error )
314+
315+ // Description returns a NormalizeOption to set description.
316+ func Description (desc string ) NormalizeOption {
317+ return func (e * Error ) {
318+ e .description = desc
319+ }
320+ }
321+
322+ // Workaround returns a NormalizeOption to set workaround.
323+ func Workaround (wr string ) NormalizeOption {
324+ return func (e * Error ) {
325+ e .workaround = wr
326+ }
327+ }
328+
329+ // RFCCodeText returns a NormalizeOption to set RFC error code.
330+ func RFCCodeText (codeText string ) NormalizeOption {
331+ return func (e * Error ) {
332+ e .codeText = ErrCodeText (codeText )
333+ }
334+ }
335+
336+ // MySQLErrorCode returns a NormalizeOption to set error code.
337+ func MySQLErrorCode (code int ) NormalizeOption {
338+ return func (e * Error ) {
339+ e .code = ErrCode (code )
340+ }
341+ }
342+
343+ // Normalize creates a new Error object.
344+ func Normalize (message string , opts ... NormalizeOption ) * Error {
345+ e := & Error {
346+ message : message ,
347+ }
348+ for _ , opt := range opts {
349+ opt (e )
350+ }
351+ return e
352+ }
0 commit comments