Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit 3a684c7

Browse files
authored
Merge pull request #240 from julnicolas/feature/add_or_compose_decode_hook_func
add OrComposeDecodeHookFunc function
2 parents ac10e22 + 0bb6a2e commit 3a684c7

2 files changed

Lines changed: 110 additions & 0 deletions

File tree

decode_hooks.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,28 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
7777
}
7878
}
7979

80+
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
81+
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
82+
func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
83+
return func(a, b reflect.Value) (interface{}, error) {
84+
var allErrs string
85+
var out interface{}
86+
var err error
87+
88+
for _, f := range ff {
89+
out, err = DecodeHookExec(f, a, b)
90+
if err != nil {
91+
allErrs += err.Error() + "\n"
92+
continue
93+
}
94+
95+
return out, nil
96+
}
97+
98+
return nil, errors.New(allErrs)
99+
}
100+
}
101+
80102
// StringToSliceHookFunc returns a DecodeHookFunc that converts
81103
// string to []string by splitting on the given sep.
82104
func StringToSliceHookFunc(sep string) DecodeHookFunc {

decode_hooks_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,94 @@ func TestComposeDecodeHookFunc_kinds(t *testing.T) {
8484
}
8585
}
8686

87+
func TestOrComposeDecodeHookFunc(t *testing.T) {
88+
f1 := func(
89+
f reflect.Kind,
90+
t reflect.Kind,
91+
data interface{}) (interface{}, error) {
92+
return data.(string) + "foo", nil
93+
}
94+
95+
f2 := func(
96+
f reflect.Kind,
97+
t reflect.Kind,
98+
data interface{}) (interface{}, error) {
99+
return data.(string) + "bar", nil
100+
}
101+
102+
f := OrComposeDecodeHookFunc(f1, f2)
103+
104+
result, err := DecodeHookExec(
105+
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
106+
if err != nil {
107+
t.Fatalf("bad: %s", err)
108+
}
109+
if result.(string) != "foo" {
110+
t.Fatalf("bad: %#v", result)
111+
}
112+
}
113+
114+
func TestOrComposeDecodeHookFunc_correctValueIsLast(t *testing.T) {
115+
f1 := func(
116+
f reflect.Kind,
117+
t reflect.Kind,
118+
data interface{}) (interface{}, error) {
119+
return nil, errors.New("f1 error")
120+
}
121+
122+
f2 := func(
123+
f reflect.Kind,
124+
t reflect.Kind,
125+
data interface{}) (interface{}, error) {
126+
return nil, errors.New("f2 error")
127+
}
128+
129+
f3 := func(
130+
f reflect.Kind,
131+
t reflect.Kind,
132+
data interface{}) (interface{}, error) {
133+
return data.(string) + "bar", nil
134+
}
135+
136+
f := OrComposeDecodeHookFunc(f1, f2, f3)
137+
138+
result, err := DecodeHookExec(
139+
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
140+
if err != nil {
141+
t.Fatalf("bad: %s", err)
142+
}
143+
if result.(string) != "bar" {
144+
t.Fatalf("bad: %#v", result)
145+
}
146+
}
147+
148+
func TestOrComposeDecodeHookFunc_err(t *testing.T) {
149+
f1 := func(
150+
f reflect.Kind,
151+
t reflect.Kind,
152+
data interface{}) (interface{}, error) {
153+
return nil, errors.New("f1 error")
154+
}
155+
156+
f2 := func(
157+
f reflect.Kind,
158+
t reflect.Kind,
159+
data interface{}) (interface{}, error) {
160+
return nil, errors.New("f2 error")
161+
}
162+
163+
f := OrComposeDecodeHookFunc(f1, f2)
164+
165+
_, err := DecodeHookExec(
166+
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
167+
if err == nil {
168+
t.Fatalf("bad: should return an error")
169+
}
170+
if err.Error() != "f1 error\nf2 error\n" {
171+
t.Fatalf("bad: %s", err)
172+
}
173+
}
174+
87175
func TestComposeDecodeHookFunc_safe_nofuncs(t *testing.T) {
88176
f := ComposeDecodeHookFunc()
89177
type myStruct2 struct {

0 commit comments

Comments
 (0)