Skip to content

Commit 921f087

Browse files
fix(valueparser): Use target type in unmarshalling
1 parent c9c4eac commit 921f087

5 files changed

Lines changed: 74 additions & 56 deletions

File tree

config/config_loader.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@ func LoadConfigStructFromEnv[T any](instance *T, log *logrus.Entry) {
261261
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
262262
value := GetEnv(envKey, "", false, log)
263263

264-
val, err := valueparser.TryUnmarshal[int64](value)
265-
if err != nil {
264+
val, err := valueparser.TryUnmarshal[int64](value, field.Type)
265+
if err == nil {
266266
fieldVal.SetInt(val)
267267

268268
continue
@@ -277,8 +277,8 @@ func LoadConfigStructFromEnv[T any](instance *T, log *logrus.Entry) {
277277
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
278278
value := GetEnv(envKey, "", false, log)
279279

280-
val, err := valueparser.TryUnmarshal[uint64](value)
281-
if err != nil {
280+
val, err := valueparser.TryUnmarshal[uint64](value, field.Type)
281+
if err == nil {
282282
fieldVal.SetUint(val)
283283

284284
continue
@@ -293,8 +293,8 @@ func LoadConfigStructFromEnv[T any](instance *T, log *logrus.Entry) {
293293
case reflect.Float32, reflect.Float64:
294294
value := GetEnv(envKey, "", false, log)
295295

296-
val, err := valueparser.TryUnmarshal[float64](value)
297-
if err != nil {
296+
val, err := valueparser.TryUnmarshal[float64](value, field.Type)
297+
if err == nil {
298298
fieldVal.SetFloat(val)
299299

300300
continue
@@ -309,8 +309,8 @@ func LoadConfigStructFromEnv[T any](instance *T, log *logrus.Entry) {
309309
case reflect.Bool:
310310
value := GetEnv(envKey, "", false, log)
311311

312-
val, err := valueparser.TryUnmarshal[bool](value)
313-
if err != nil {
312+
val, err := valueparser.TryUnmarshal[bool](value, field.Type)
313+
if err == nil {
314314
fieldVal.SetBool(val)
315315

316316
continue
@@ -325,8 +325,8 @@ func LoadConfigStructFromEnv[T any](instance *T, log *logrus.Entry) {
325325
case reflect.String:
326326
value := GetEnv(envKey, "", false, log)
327327

328-
val, err := valueparser.TryUnmarshal[string](value)
329-
if err != nil {
328+
val, err := valueparser.TryUnmarshal[string](value, field.Type)
329+
if err == nil {
330330
fieldVal.SetString(val)
331331

332332
continue

config/utils.go

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package config
22

33
import (
4-
"fmt"
54
"reflect"
65
"strings"
76

7+
"github.com/YaCodeDev/GoYaCodeDevUtils/valueparser"
88
"github.com/sirupsen/logrus"
99
)
1010

@@ -47,33 +47,27 @@ func copyMap(src reflect.Value, dst reflect.Value) {
4747
return
4848
}
4949

50+
var (
51+
convertedKey reflect.Value
52+
convertedVal reflect.Value
53+
err error
54+
)
55+
5056
for _, key := range src.MapKeys() {
5157
val := src.MapIndex(key)
5258

53-
convertedKey := convertValue(key, dst.Type().Key())
54-
convertedVal := convertValue(val, dst.Type().Elem())
55-
56-
dst.SetMapIndex(convertedKey, convertedVal)
57-
}
58-
}
59+
convertedKey, err = valueparser.ConvertValue(key, dst.Type().Key())
60+
if err != nil {
61+
panic("Cannot convert key: " + err.Error())
62+
}
5963

60-
// convertValue converts a reflect.Value to the specified target type.
61-
// It checks if the value is valid and convertible to the target type.
62-
// If the value is valid and convertible, it returns the converted value.
63-
// If the value is invalid, it returns a zero value of the target type.
64-
// If the value is valid but not convertible, it panics with an error message.
65-
// This function is used to ensure that the value being set in a map or slice is of the correct type.
66-
// It is a helper function for copyMap and copyArray functions.
67-
func convertValue(val reflect.Value, targetType reflect.Type) reflect.Value {
68-
if !val.IsValid() {
69-
return reflect.Zero(targetType)
70-
}
64+
convertedVal, err = valueparser.ConvertValue(val, dst.Type().Elem())
65+
if err != nil {
66+
panic("Cannot convert value: " + err.Error())
67+
}
7168

72-
if val.Type().ConvertibleTo(targetType) {
73-
return val.Convert(targetType)
69+
dst.SetMapIndex(convertedKey, convertedVal)
7470
}
75-
76-
panic(fmt.Sprintf("Cannot convert from %s to %s", val.Type(), targetType))
7771
}
7872

7973
// copyArray copies elements from the source slice to the destination slice.
@@ -99,7 +93,12 @@ func copyArray(src, dst reflect.Value) {
9993
val := src.Index(i)
10094

10195
if val.IsValid() {
102-
dst.Index(i).Set(convertValue(val, dst.Type().Elem()))
96+
converted, err := valueparser.ConvertValue(val, dst.Type().Elem())
97+
if err != nil {
98+
panic("Cannot convert value: " + err.Error())
99+
}
100+
101+
dst.Index(i).Set(converted)
103102
}
104103
}
105104
}

valueparser/try_unmarshal.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package valueparser
22

33
import (
44
"encoding"
5+
"fmt"
56
"reflect"
67
)
78

@@ -15,30 +16,32 @@ import (
1516
// if err != nil {
1617
// // Handle error
1718
// }
18-
func TryUnmarshal[T ParsableType](value string) (T, error) {
19+
func TryUnmarshal[T ParsableType](value string, valueType reflect.Type) (T, error) {
1920
var zero T
21+
2022
typ := reflect.TypeOf(zero)
23+
ptr := reflect.New(valueType)
2124

22-
ptr := reflect.New(typ)
2325
if unmarshaler, ok := ptr.Interface().(encoding.TextUnmarshaler); ok {
2426
if err := unmarshaler.UnmarshalText([]byte(value)); err == nil {
25-
if val, ok := ptr.Elem().Interface().(T); ok {
26-
return val, nil
27-
}
28-
29-
return zero, ErrInvalidValue
27+
return zero, fmt.Errorf("cannot convert value %v to type %s: %w", value, typ, err)
28+
}
29+
} else if unmarshaler, ok := ptr.Interface().(Unmarshalable); ok {
30+
if err := unmarshaler.Unmarshal(value); err != nil {
31+
return zero, ErrUnparsableValue
3032
}
33+
} else {
34+
return zero, ErrUnparsableValue
3135
}
3236

33-
if unmarshaler, ok := ptr.Interface().(Unmarshalable); ok {
34-
if err := unmarshaler.Unmarshal(value); err == nil {
35-
if val, ok := ptr.Elem().Interface().(T); ok {
36-
return val, nil
37-
}
37+
val, err := ConvertValue(ptr.Elem(), typ)
38+
if err != nil {
39+
return zero, fmt.Errorf("cannot convert value %v to type %s: %w", value, typ, err)
40+
}
3841

39-
return zero, ErrInvalidValue
40-
}
42+
if val, ok := val.Interface().(T); ok {
43+
return val, nil
4144
}
4245

43-
return zero, ErrUnparsableValue
46+
return zero, ErrInvalidValue
4447
}

valueparser/value_convertor.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package valueparser
2+
3+
import (
4+
"reflect"
5+
)
6+
7+
// ConvertValue converts a reflect.Value to the specified target type.
8+
// It checks if the value is valid and convertible to the target type.
9+
// If the value is valid and convertible, it returns the converted value.
10+
// If the value is invalid, it returns a zero value of the target type.
11+
// If the value is valid but not convertible, it panics with an error message.
12+
func ConvertValue(val reflect.Value, targetType reflect.Type) (reflect.Value, error) {
13+
if !val.IsValid() {
14+
return reflect.Zero(targetType), nil
15+
}
16+
17+
if val.Type().ConvertibleTo(targetType) {
18+
return val.Convert(targetType), nil
19+
}
20+
21+
return reflect.Value{}, ErrUnparsableValue
22+
}

valueparser/value_parser.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,10 @@ func ParseValue[T ParsableType](value string) (T, error) {
7777
return zero, ErrInvalidType
7878
}
7979

80-
val, err := TryUnmarshal[T](value)
80+
val, err := TryUnmarshal[T](value, typ)
8181
if err != nil {
8282
return zero, err
8383
}
8484

85-
var ok bool
86-
87-
if val, ok = reflect.ValueOf(val).Convert(typ).Interface().(T); ok {
88-
return val, nil
89-
}
90-
91-
return zero, ErrInvalidValue
85+
return val, nil
9286
}

0 commit comments

Comments
 (0)