master
go 93 lines 2.03 KB
Raw
1 package common
2
3 import (
4 "fmt"
5 "maps"
6 "strings"
7 )
8
9 func MapGetKV(v map[string]any, key string) (any, error) {
10 var ok bool
11 var mcursor map[string]any
12 var cursor any = v
13
14 parts := strings.Split(key, ".")
15 for i, part := range parts {
16 sofar := strings.Join(parts[:i], ".")
17
18 mcursor, ok = cursor.(map[string]any)
19 if !ok {
20 return nil, fmt.Errorf("%s key is not a map", sofar)
21 }
22
23 cursor, ok = mcursor[part]
24 if !ok {
25 // Construct the current path traversed to print a nice error message
26 var path string
27 if len(sofar) > 0 {
28 path += sofar + "."
29 }
30 path += part
31 return nil, fmt.Errorf("%s not found", path)
32 }
33 }
34 return cursor, nil
35 }
36
37 func MapSetKV(v map[string]any, key string, value any) error {
38 var ok bool
39 var mcursor map[string]any
40 var cursor any = v
41
42 parts := strings.Split(key, ".")
43 for i, part := range parts {
44 mcursor, ok = cursor.(map[string]any)
45 if !ok {
46 sofar := strings.Join(parts[:i], ".")
47 return fmt.Errorf("%s key is not a map", sofar)
48 }
49
50 // last part? set here
51 if i == (len(parts) - 1) {
52 mcursor[part] = value
53 break
54 }
55
56 cursor, ok = mcursor[part]
57 if !ok || cursor == nil { // create map if this is empty or is null
58 mcursor[part] = map[string]any{}
59 cursor = mcursor[part]
60 }
61 }
62 return nil
63 }
64
65 // MapMergeDeep merges the right map into the left map, recursively traversing
66 // child maps until a non-map value is found.
67 func MapMergeDeep(left, right map[string]any) map[string]any {
68 // We want to alter a copy of the map, not the original
69 result := maps.Clone(left)
70 if result == nil {
71 result = make(map[string]any)
72 }
73
74 for key, rightVal := range right {
75 // If right value is a map
76 if rightMap, ok := rightVal.(map[string]any); ok {
77 // If key is in left
78 if leftVal, found := result[key]; found {
79 // If left value is also a map
80 if leftMap, ok := leftVal.(map[string]any); ok {
81 // Merge nested map
82 result[key] = MapMergeDeep(leftMap, rightMap)
83 continue
84 }
85 }
86 }
87
88 // Otherwise set new value to result
89 result[key] = rightVal
90 }
91
92 return result
93 }