-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherr_wrapper.go
154 lines (137 loc) · 3.74 KB
/
err_wrapper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package berror
import (
"errors"
"fmt"
"github.com/bearaujus/berror/pkg"
)
type (
// ErrDefinition represents an interface for creating new error instances
// with custom formatting and behavior.
ErrDefinition interface {
// New creates a new WrappedErr instance using the error definition's format
// and the provided arguments.
New(a ...any) WrappedErr
// Is checks if a given error matches the current ErrDefinition.
// This comparison is based on the error's format and behavior.
Is(err error) bool
// Format returns the format string associated with the ErrDefinition.
Format() string
}
errDefinition struct {
code string
format string
formatter ErrWrapperFormatter
disableStackTrace bool
stackTraceCapturer ErrWrapperStackTraceCapturer
}
)
// NewErrDefinition creates a new ErrDefinition with a specified format string.
// ErrDefinitionOption can be provided to customize the error definition.
func NewErrDefinition(format string, opts ...ErrDefinitionOption) ErrDefinition {
ed := errDefinition{
format: format,
formatter: ErrWrapperFormatterDefault,
stackTraceCapturer: pkg.CaptureStackTrace,
}
for _, opt := range opts {
opt(&ed)
}
return &ed
}
func (ed *errDefinition) New(a ...any) WrappedErr {
we := &wrappedErr{
ew: ed,
Args: a,
err: fmt.Sprintf(ed.format, a...),
}
if !ed.disableStackTrace {
we.stack = ed.stackTraceCapturer()
}
return we
}
func (ed *errDefinition) Is(err error) bool {
return errors.Is(err, ed.New())
}
func (ed *errDefinition) Format() string {
return ed.format
}
type (
// WrappedErr represents an interface for wrapped errors with additional metadata.
WrappedErr interface {
// Code returns the error code of the wrapped error.
Code() string
// StackTrace returns the captured stack trace.
StackTrace() string
// Error returns the formatted error message.
Error() string
// RawError returns the raw error message without formatting.
RawError() string
// Is checks if the given error matches this wrapped error by comparing
// the error codes or formatted messages. If neither matches, it unwraps
// the error arguments recursively and compares them.
Is(err error) bool
// Unwrap extracts and returns unwrapped errors from the arguments.
Unwrap() []error
// String returns the formatted error message as a string.
String() string
// ErrorDefinition returns ErrDefinition from current WrappedErr.
ErrorDefinition() ErrDefinition
}
wrappedErr struct {
ew *errDefinition
Args []any
err string
stack string
}
)
func (we *wrappedErr) Code() string {
return we.ew.code
}
func (we *wrappedErr) StackTrace() string {
return we.stack
}
func (we *wrappedErr) Error() string {
return we.ew.formatter(we.err, we.ew.code, we.stack)
}
func (we *wrappedErr) RawError() string {
return we.err
}
func (we *wrappedErr) Is(err error) bool {
parsedWE, ok := CastToWrappedErrFromErr(err)
if ok && parsedWE.Code() == we.ew.code && parsedWE.ErrorDefinition().Format() == we.ew.format {
return true
}
for _, uErr := range we.Unwrap() {
if errors.Is(uErr, err) {
return true
}
}
return false
}
func (we *wrappedErr) Unwrap() []error {
var errs []error
for _, arg := range we.Args {
switch errType := arg.(type) {
case error:
errs = append(errs, errType)
}
}
return errs
}
func (we *wrappedErr) String() string {
return we.Error()
}
func (we *wrappedErr) ErrorDefinition() ErrDefinition {
return we.ew
}
// CastToWrappedErrFromErr attempts to cast a standard error to a WrappedErr.
func CastToWrappedErrFromErr(err error) (WrappedErr, bool) {
if err == nil {
return nil, false
}
var parsedWe *wrappedErr
if !errors.As(err, &parsedWe) {
return nil, false
}
return parsedWe, true
}