Skip to content
Snippets Groups Projects
Verified Commit 85d91e1d authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

feat: set values in a map #5

parent 4a41f7ac
No related branches found
No related tags found
No related merge requests found
......@@ -106,3 +106,36 @@ func TestSetValueWithArray(t *testing.T) {
assert.NotNil(t, err)
}
type PathValue string
type SubTestSubPaths struct {
Template PathValue
Definitions []PathValue
}
type SubTest2Def struct {
Paths SubTestSubPaths
}
type SubTestStruct1 map[string]SubTest2Def
type MainTestStruct struct {
Sub SubTestStruct1
}
func TestReplacePathForConfig(t *testing.T) {
config := MainTestStruct{
Sub: SubTestStruct1{
"Default": SubTest2Def{
Paths: SubTestSubPaths{
Template: "../../../default.html",
Definitions: []PathValue{"../../../legacy.yaml"},
},
},
},
}
err := SetValue[*MainTestStruct](&config, "Sub.Default.Paths.Template", "test")
assert.Nil(t, err)
}
......@@ -4,12 +4,26 @@
package pathfinder
import (
"bytes"
"encoding/gob"
"fmt"
"reflect"
"strconv"
"strings"
)
func deepCopy(src, dst interface{}) error {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
dec := gob.NewDecoder(&buf)
if err := enc.Encode(src); err != nil {
return err
}
return dec.Decode(dst)
}
// SetValue sets the value of a field in a struct, given a path to the field.
// The object must be a pointer to a struct, otherwise an error is returned.
func SetValue[D any](obj D, keyWithDots string, newValue any) error {
......@@ -17,7 +31,33 @@ func SetValue[D any](obj D, keyWithDots string, newValue any) error {
keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(obj)
for _, key := range keySlice[0 : len(keySlice)-1] {
for keyIndex, key := range keySlice[0 : len(keySlice)-1] {
if v.Kind() == reflect.Map {
if v.IsNil() {
return newInvalidPathError(keyWithDots)
}
currentValue := v.MapIndex(reflect.ValueOf(key)).Interface()
newValueCopy := reflect.New(reflect.TypeOf(currentValue)).Interface()
if err := deepCopy(currentValue, newValueCopy); err != nil {
return err
}
newValueCopyPtr := &newValueCopy
newValueCopyReflect := reflect.ValueOf(newValueCopyPtr).Elem()
if !newValueCopyReflect.CanAddr() {
return newCannotSetError("Wert ist nicht adressierbar")
}
newKey := strings.Join(keySlice[keyIndex+1:], ".")
return SetValue(newValueCopyPtr, newKey, newValue)
}
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Interface {
v = v.Elem().Elem()
}
for v.Kind() != reflect.Ptr {
if v.Kind() == reflect.Invalid {
return newInvalidPathError(keyWithDots)
......@@ -35,13 +75,13 @@ func SetValue[D any](obj D, keyWithDots string, newValue any) error {
return newUnsupportedTypePathError(keyWithDots, v.Type())
}
elem := v.Elem()
if elem.Kind() != reflect.Struct {
switch v.Elem().Kind() {
case reflect.Struct:
v = v.Elem().FieldByName(key)
default:
return newUnsupportedTypePathError(keyWithDots, v.Type())
}
v = elem.FieldByName(key)
}
if v.Kind() == reflect.Invalid {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment