Skip to content

Commit a5bdfc2

Browse files
authored
Merge pull request #76 from gone-io/feature/update
enhance error handling and add `WarpThirdComponent ` for third component injecting
2 parents 170c808 + 084c524 commit a5bdfc2

File tree

4 files changed

+125
-12
lines changed

4 files changed

+125
-12
lines changed

error.go

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,50 @@ func ToError(input any) Error {
131131
if input == nil {
132132
return nil
133133
}
134-
switch input := input.(type) {
134+
switch err := input.(type) {
135135
case Error:
136-
return input
136+
return err
137137
case error:
138-
return NewInnerErrorSkip(input.Error(), http.StatusInternalServerError, 2)
138+
return newIError(err, http.StatusInternalServerError, 2)
139139
case string:
140-
return NewInnerErrorSkip(input, http.StatusInternalServerError, 2)
140+
return NewInnerErrorSkip(err, http.StatusInternalServerError, 2)
141141
default:
142142
return NewInnerErrorSkip(fmt.Sprintf("%v", input), http.StatusInternalServerError, 2)
143143
}
144144
}
145145

146+
var _ Error = (*withMessage)(nil)
147+
148+
type withMessage struct {
149+
cause Error
150+
msg string
151+
}
152+
153+
func (e *withMessage) Code() int {
154+
return e.cause.Code()
155+
}
156+
157+
func (e *withMessage) GetStatusCode() int {
158+
return e.cause.GetStatusCode()
159+
}
160+
161+
func (e *withMessage) Error() string {
162+
return e.msg + ";" + e.cause.Error()
163+
}
164+
func (e *withMessage) Msg() string {
165+
if e.msg == "" {
166+
return e.cause.Msg()
167+
}
168+
return e.msg
169+
}
170+
func (e *withMessage) SetMsg(msg string) {
171+
e.msg = msg
172+
}
173+
174+
func (e *withMessage) Unwrap() error {
175+
return e.cause
176+
}
177+
146178
// ToErrorWithMsg converts any input to an Error type with an additional message prefix.
147179
// If input is nil, returns nil.
148180
// If msg is not empty, prepends it to the error message in format "msg: original_error_msg".
@@ -151,16 +183,20 @@ func ToErrorWithMsg(input any, msg string) Error {
151183
if input == nil {
152184
return nil
153185
}
154-
err := ToError(input)
155-
if msg != "" {
156-
err.SetMsg(fmt.Sprintf("%s: %s", msg, err.Msg()))
186+
return &withMessage{
187+
cause: ToError(input),
188+
msg: msg,
157189
}
158-
return err
190+
}
191+
192+
func ToErrorf(input any, format string, params ...any) error {
193+
return ToErrorWithMsg(input, fmt.Sprintf(format, params...))
159194
}
160195

161196
type iError struct {
162197
*defaultErr
163198
trace []byte
199+
cause error
164200
}
165201

166202
func (e *iError) Error() string {
@@ -172,6 +208,10 @@ func (e *iError) Stack() []byte {
172208
return e.trace
173209
}
174210

211+
func (e *iError) Unwrap() error {
212+
return e.cause
213+
}
214+
175215
// NewInnerError creates a new InnerError with message and code, skipping one stack frame.
176216
// Parameters:
177217
// - msg: error message
@@ -241,6 +281,14 @@ func NewInnerErrorSkip(msg string, code int, skip int) Error {
241281
}
242282
}
243283

284+
func newIError(err error, code int, skip int) Error {
285+
return &iError{
286+
defaultErr: &defaultErr{code: code, msg: err.Error(), statusCode: http.StatusInternalServerError},
287+
trace: PanicTrace(2, skip),
288+
cause: err,
289+
}
290+
}
291+
244292
// Error Code:1001~1999 used for gone framework.
245293
const (
246294
GonerNameNotFound = 1001

error_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package gone
22

33
import (
4+
"errors"
45
"fmt"
56
"net/http"
67
"strings"
@@ -200,7 +201,7 @@ func TestToErrorWithMsg(t *testing.T) {
200201
name: "with prefix",
201202
input: "test error",
202203
msg: "prefix",
203-
wantMsg: "prefix: test error",
204+
wantMsg: "prefix",
204205
},
205206
{
206207
name: "without prefix",
@@ -343,3 +344,40 @@ func TestBError_SetMsg(t *testing.T) {
343344
})
344345
}
345346
}
347+
348+
func TestToErrorf(t *testing.T) {
349+
t.Run("input nil", func(t *testing.T) {
350+
err := ToErrorf(nil, "test error")
351+
if err != nil {
352+
t.Error("must be nil")
353+
}
354+
})
355+
356+
t.Run("input error", func(t *testing.T) {
357+
var err = errors.New("test error")
358+
newErr := ToErrorf(err, "my-test")
359+
360+
if !errors.Is(newErr, err) {
361+
t.Error("must be input error")
362+
}
363+
364+
var gErr Error
365+
if !errors.As(newErr, &gErr) {
366+
t.Error("must be GoneError")
367+
}
368+
369+
if gErr.GetStatusCode() != http.StatusInternalServerError {
370+
t.Error("must be 500")
371+
}
372+
373+
if gErr.Msg() != "my-test" {
374+
t.Error("must be my-test")
375+
}
376+
377+
gErr.SetMsg("my-test2")
378+
if gErr.Msg() != "my-test2" {
379+
t.Error("must be my-test2")
380+
}
381+
382+
})
383+
}

experimental.go renamed to func_provider.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package gone
22

33
import "reflect"
44

5-
// FunctionProvider is an experimental type that may change or be removed in future releases.
5+
// FunctionProvider is a function, which first parameter is tagConf, and second parameter is a struct that can be injected.
6+
// And the function must return a T type value and error.
67
type FunctionProvider[P, T any] func(tagConf string, param P) (T, error)
78

8-
// XProvider is an experimental type that may change or be removed in future releases.
9+
// XProvider is a Goner Provider was created by WrapFunctionProvider.
910
type XProvider[T any] struct {
1011
Flag
1112
injector FuncInjector `gone:"*"`
@@ -20,7 +21,7 @@ func (p *XProvider[T]) Provide(tagConf string) (T, error) {
2021
return obj, nil
2122
}
2223

23-
// WrapFunctionProvider is an experimental function that may change or be removed in future releases.
24+
// WrapFunctionProvider can wrap a FunctionProvider to a Provider.
2425
func WrapFunctionProvider[P, T any](fn FunctionProvider[P, T]) *XProvider[T] {
2526
p := XProvider[T]{}
2627

@@ -52,3 +53,11 @@ func WrapFunctionProvider[P, T any](fn FunctionProvider[P, T]) *XProvider[T] {
5253
}
5354
return &p
5455
}
56+
57+
// WarpThirdComponent can wrap a third component to a Goner Provider which can make third component to inject Goners.
58+
func WarpThirdComponent[T any](t T) Goner {
59+
provider := WrapFunctionProvider(func(tagConf string, param struct{}) (T, error) {
60+
return t, nil
61+
})
62+
return provider
63+
}

experimental_test.go renamed to func_provider_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,21 @@ func TestWrapFunctionProvider(t *testing.T) {
6666
}
6767
})
6868
}
69+
70+
func TestWarpThirdComponent(t *testing.T) {
71+
type ThirdComponent struct {
72+
ID string
73+
}
74+
75+
var thirdComponent = ThirdComponent{
76+
ID: "third",
77+
}
78+
79+
NewApp().
80+
Load(WarpThirdComponent(thirdComponent)).
81+
Run(func(thirdComponent ThirdComponent) {
82+
if thirdComponent.ID != "third" {
83+
t.Errorf("Expected %v, got %v", "third", thirdComponent.ID)
84+
}
85+
})
86+
}

0 commit comments

Comments
 (0)