3
0

Make settings decoding more robust (numbers & strings)

This commit is contained in:
Denis Arh
2022-05-09 17:16:20 +02:00
parent 866b89a8e5
commit 0a2175f384
4 changed files with 36 additions and 19 deletions

View File

@@ -7,9 +7,10 @@ package options
//
import (
"time"
"github.com/cortezaproject/corteza-server/pkg/rand"
"github.com/cortezaproject/corteza-server/pkg/version"
"time"
)
type (

View File

@@ -158,7 +158,6 @@ func (svc *settings) UpdateCurrent(ctx context.Context) error {
}
func (svc *settings) updateCurrent(ctx context.Context, vv types.SettingValueSet) (err error) {
// update current settings with new values
if err = vv.KV().Decode(svc.current); err != nil {
return fmt.Errorf("could not decode settings into KV: %w", err)

View File

@@ -103,7 +103,7 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) {
if decode, ok := decodeMethod.Interface().(func(SettingsKV, string) error); !ok {
panic("invalid DecodeKV() function signature")
} else if err = decode(kv, key); err != nil {
return errors.Wrapf(err, "cannot decode settings for %q", key)
return fmt.Errorf("cannot decode settings for %q: %w", key, err)
} else {
continue
}
@@ -115,7 +115,7 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) {
// It calls DecodeKV recursively
if structField.Kind() == reflect.Struct {
if err = DecodeKV(kv.Filter(key), structValue, key); err != nil {
return
return err
}
continue
@@ -133,7 +133,7 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) {
mapValue := reflect.New(structField.Type().Elem())
err = val.Unmarshal(mapValue.Interface())
if err != nil {
return errors.Wrapf(err, "cannot decode settings for %q", key)
return fmt.Errorf("cannot decode JSON into map for key %q: %w", key, err)
}
structField.SetMapIndex(reflect.ValueOf(k), mapValue.Elem())
@@ -164,19 +164,30 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) {
if err = val.Unmarshal(structField.Addr().Interface()); err != nil {
// Try to get numbers encoded as strings...
var tmp interface{}
if val.Unmarshal(&tmp) != nil {
return fmt.Errorf(
"could not unamarshal JSON value for settings key %q: %w",
key,
err,
)
if err = val.Unmarshal(&tmp); err != nil {
return fmt.Errorf("could not decode JSON for key %q: %w", key, err)
}
switch cnv := tmp.(type) {
case string:
var cnv, is = tmp.(string)
if !is {
// give up
continue
}
switch structFType.Type.Kind() {
case reflect.Int, reflect.Int32, reflect.Int64:
if num, err := strconv.ParseInt(cnv, 10, 64); err == nil {
structField.SetInt(num)
}
case reflect.Uint, reflect.Uint32, reflect.Uint64:
if num, err := strconv.ParseUint(cnv, 10, 64); err == nil {
structField.SetUint(num)
}
case reflect.Float32, reflect.Float64:
if num, err := strconv.ParseFloat(cnv, 64); err == nil {
structField.SetFloat(num)
}
}
}
}

View File

@@ -21,9 +21,11 @@ func TestDecode(t *testing.T) {
withHandler struct{}
dst struct {
S string `kv:"s"`
B bool `kv:"b"`
N int `kv:"n"`
S string `kv:"s"`
B bool `kv:"b"`
N int `kv:"n"`
NAS int `kv:"numAsString"`
Pi float32 `kv:"pi"`
NoKV string
@@ -53,6 +55,8 @@ func TestDecode(t *testing.T) {
"s": types.JSONText(`"string"`),
"b": types.JSONText("true"),
"n": types.JSONText("42"),
"numAsString": types.JSONText(`"84"`),
"pi": types.JSONText(`"3.14"`),
"sub.s": types.JSONText(`"string"`),
"sub.b": types.JSONText("true"),
"sub.bar": nil,
@@ -73,9 +77,11 @@ func TestDecode(t *testing.T) {
}
eq = dst{
S: "string",
B: true,
N: 42,
S: "string",
B: true,
N: 42,
NAS: 84,
Pi: 3.14,
NoKV: "NO-SettingsKV-!",
Ptr: &ptr,