From 85d91e1d80f8469997b15a08393b3475caa5808d Mon Sep 17 00:00:00 2001 From: Volker Schukai <volker.schukai@schukai.com> Date: Wed, 13 Sep 2023 15:36:55 +0200 Subject: [PATCH] feat: set values in a map #5 --- issue_2_test.go | 33 ++++++++++++++++++++++++++++++++ set.go | 50 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/issue_2_test.go b/issue_2_test.go index 1e3ef82..a86b84b 100644 --- a/issue_2_test.go +++ b/issue_2_test.go @@ -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) + +} diff --git a/set.go b/set.go index fa7443a..f4face6 100644 --- a/set.go +++ b/set.go @@ -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 { -- GitLab