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) { ...@@ -106,3 +106,36 @@ func TestSetValueWithArray(t *testing.T) {
assert.NotNil(t, err) 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 @@ ...@@ -4,12 +4,26 @@
package pathfinder package pathfinder
import ( import (
"bytes"
"encoding/gob"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
"strings" "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. // 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. // 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 { 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 { ...@@ -17,7 +31,33 @@ func SetValue[D any](obj D, keyWithDots string, newValue any) error {
keySlice := strings.Split(keyWithDots, ".") keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(obj) 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 { for v.Kind() != reflect.Ptr {
if v.Kind() == reflect.Invalid { if v.Kind() == reflect.Invalid {
return newInvalidPathError(keyWithDots) return newInvalidPathError(keyWithDots)
...@@ -35,13 +75,13 @@ func SetValue[D any](obj D, keyWithDots string, newValue any) error { ...@@ -35,13 +75,13 @@ func SetValue[D any](obj D, keyWithDots string, newValue any) error {
return newUnsupportedTypePathError(keyWithDots, v.Type()) return newUnsupportedTypePathError(keyWithDots, v.Type())
} }
elem := v.Elem() switch v.Elem().Kind() {
if elem.Kind() != reflect.Struct { case reflect.Struct:
v = v.Elem().FieldByName(key)
default:
return newUnsupportedTypePathError(keyWithDots, v.Type()) return newUnsupportedTypePathError(keyWithDots, v.Type())
} }
v = elem.FieldByName(key)
} }
if v.Kind() == reflect.Invalid { 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