Rework YAML setting unmarshling for more flexibility

Allow settings to use JSON values, use recursive
value decoding for nested structures.
This commit is contained in:
Tomaž Jerman
2022-06-07 15:17:03 +02:00
parent c1500df2da
commit 05b97eefd0
5 changed files with 88 additions and 58 deletions
+58 -54
View File
@@ -23,67 +23,28 @@ func (wset *settingSet) UnmarshalYAML(n *yaml.Node) error {
wrap.res = &types.SettingValue{}
switch v.Kind {
case yaml.MappingNode:
if y7s.IsKind(n, yaml.SequenceNode) {
if !y7s.IsKind(v, yaml.MappingNode) {
return y7s.NodeErr(n, "malformed setting definition: sequence of settings must be defined as maps")
}
if err = v.Decode(&wrap); err != nil {
return
}
default:
} else {
if err = y7s.DecodeScalar(k, "setting name", &wrap.res.Name); err != nil {
return err
}
if y7s.IsKind(v, yaml.SequenceNode) {
aux := make([]interface{}, 0, 10)
y7s.EachSeq(v, func(n *yaml.Node) error {
var vx interface{}
err := y7s.DecodeScalar(n, "setting value", &vx)
if err != nil {
return err
}
aux = append(aux, vx)
return nil
})
m, err := json.Marshal(aux)
if err != nil {
return err
}
wrap.res.Value = sqlt.JSONText(m)
} else if y7s.IsKind(v, yaml.MappingNode) {
aux := make(map[string]interface{})
y7s.EachMap(v, func(k, v *yaml.Node) error {
var vx interface{}
err := y7s.DecodeScalar(v, "setting value", &vx)
if err != nil {
return err
}
aux[k.Value] = vx
return nil
})
m, err := json.Marshal(aux)
if err != nil {
return err
}
wrap.res.Value = sqlt.JSONText(m)
} else {
var aux interface{}
err = y7s.DecodeScalar(v, "setting value", &aux)
if err != nil {
return err
}
m, err := json.Marshal(aux)
if err != nil {
return err
}
wrap.res.Value = sqlt.JSONText(m)
value, err := wrap.unmarshalSettingValue(v)
if err != nil {
return err
}
m, err := json.Marshal(value)
if err != nil {
return err
}
wrap.res.Value = sqlt.JSONText(m)
}
*wset = append(*wset, wrap)
@@ -107,10 +68,11 @@ func (wrap *setting) UnmarshalYAML(n *yaml.Node) (err error) {
case "value":
var aux interface{}
err = y7s.DecodeScalar(v, "setting value", &aux)
aux, err = wrap.unmarshalSettingValue(v)
if err != nil {
return err
}
m, err := json.Marshal(aux)
if err != nil {
return err
@@ -140,6 +102,48 @@ func (wrap *setting) UnmarshalYAML(n *yaml.Node) (err error) {
return nil
}
func (wrap *setting) unmarshalSettingValue(n *yaml.Node) (v interface{}, err error) {
switch n.Kind {
case yaml.SequenceNode:
out := make([]interface{}, 0, 10)
err = y7s.EachSeq(n, func(n *yaml.Node) error {
aux, err := wrap.unmarshalSettingValue(n)
if err != nil {
return err
}
out = append(out, aux)
return nil
})
return out, err
case yaml.MappingNode:
out := make(map[string]interface{})
err = y7s.EachMap(n, func(k, v *yaml.Node) error {
aux, err := wrap.unmarshalSettingValue(v)
if err != nil {
return err
}
out[k.Value] = aux
return nil
})
return out, err
case yaml.ScalarNode:
var out interface{}
if err := y7s.DecodeScalar(n, "setting value", &out); err != nil {
return v, err
}
return out, nil
default:
return nil, y7s.NodeErr(n, "unknown node kind")
}
}
func (wset settingSet) MarshalEnvoy() ([]resource.Interface, error) {
nn := make([]resource.Interface, 0, len(wset))
+13 -1
View File
@@ -2,6 +2,7 @@ package envoy
import (
"context"
"encoding/json"
"strconv"
"testing"
"time"
@@ -570,7 +571,7 @@ func TestStoreYaml_base(t *testing.T) {
ss, _, err := store.SearchSettings(ctx, s, stypes.SettingsFilter{})
req.NoError(err)
req.Len(ss, 2)
req.Len(ss, 3)
sv := ss[0]
req.Equal("base_setting_1", sv.Name)
@@ -583,6 +584,17 @@ func TestStoreYaml_base(t *testing.T) {
req.Equal("20", sv.Value.String())
req.Equal(updatedAt.Format(time.RFC3339), sv.UpdatedAt.Format(time.RFC3339))
req.Equal(usr.ID, sv.UpdatedBy)
sv = ss[2]
req.Equal("base_setting_3.dot", sv.Name)
sValue := make(map[string]interface{})
req.NoError(json.Unmarshal(sv.Value, &sValue))
req.Contains(sValue, "someKey")
req.Equal("someValue", sValue["someKey"])
req.Contains(sValue, "otherKey")
req.Equal(float64(10), sValue["otherKey"])
req.Equal(updatedAt.Format(time.RFC3339), sv.UpdatedAt.Format(time.RFC3339))
req.Equal(usr.ID, sv.UpdatedBy)
},
},
+6
View File
@@ -117,6 +117,12 @@ func sTestSettings(ctx context.Context, t *testing.T, s store.Storer, usrID uint
UpdatedAt: updatedAt,
UpdatedBy: usrID,
},
{
Name: pfx + "_setting_3.dot",
Value: []byte(`{"someKey": "someValue","otherKey":10}`),
UpdatedAt: updatedAt,
UpdatedBy: usrID,
},
}
err := store.CreateSetting(ctx, s, ss...)
+5
View File
@@ -1,3 +1,8 @@
settings:
s1.opt.1: s1 opt1
s1.opt.2: s1 opt2
compose.ui.record-toolbar: { "hideBack": true }
compose.ui.record-otherbar:
hideBack: true
hideCreate: true
+6 -3
View File
@@ -544,10 +544,13 @@ func TestYamlStore_base(t *testing.T) {
ss, _, err := store.SearchSettings(ctx, s, systypes.SettingsFilter{})
req.NoError(err)
req.NotNil(ss)
req.Len(ss, 4)
req.Len(ss, 6)
rs := []string{ss[0].Name, ss[1].Name, ss[2].Name, ss[3].Name}
req.Subset(rs, []string{"s1.opt.1", "s1.opt.2", "s2.opt.1", "s2.opt.2"})
rs := []string{ss[0].Name, ss[1].Name, ss[2].Name, ss[3].Name, ss[4].Name, ss[5].Name}
req.Subset(rs, []string{"s1.opt.1", "s1.opt.2", "compose.ui.record-toolbar", "compose.ui.record-otherbar", "s2.opt.1", "s2.opt.2"})
req.Equal("{\"hideBack\":true}", ss[2].Value.String())
req.Equal("{\"hideBack\":true,\"hideCreate\":true}", ss[3].Value.String())
},
},
}