Skip to content

Commit 917be5d

Browse files
committed
Move map operations from tools
These two operations are used on multiple places in our tools, so it make sence to have it in the library.
1 parent 7d3567e commit 917be5d

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

misc/structs.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package misc
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"strings"
7+
)
8+
9+
// AssimilateMap recursively saves content of the given map to destination map of strings
10+
func AssimilateMap(theMap map[string]interface{}, destination *map[string]string) {
11+
defer func() { // recover from any panic
12+
if r := recover(); r != nil {
13+
log.Printf("Panic:recovered in assimilateMap %v\n", r)
14+
}
15+
}()
16+
for key, val := range theMap {
17+
switch value := val.(type) {
18+
case map[string]interface{}:
19+
// go one level deeper in the map
20+
AssimilateMap(value, destination)
21+
case []interface{}:
22+
// transform slice value to comma separated list and assimilate it
23+
aList := make([]string, 0, len(value))
24+
for _, item := range value {
25+
if itm, ok := item.(string); ok {
26+
aList = append(aList, itm)
27+
}
28+
}
29+
(*destination)[key] = strings.Join(aList, ",")
30+
case float64, float32:
31+
(*destination)[key] = fmt.Sprintf("%f", value)
32+
case int, int8, int16, int32, int64:
33+
(*destination)[key] = fmt.Sprintf("%d", value)
34+
case bool:
35+
(*destination)[key] = fmt.Sprintf("%t", value)
36+
default:
37+
// assimilate KV pair
38+
if stringer, ok := value.(fmt.Stringer); ok {
39+
(*destination)[key] = stringer.String()
40+
} else {
41+
(*destination)[key] = value.(string)
42+
}
43+
}
44+
}
45+
}
46+
47+
// MergeMaps merges given maps into a new one
48+
func MergeMaps(ms ...map[string]interface{}) map[string]interface{} {
49+
res := make(map[string]interface{})
50+
for _, m := range ms {
51+
for k, v := range m {
52+
switch value := v.(type) {
53+
case map[string]interface{}:
54+
// go one level deeper in the map
55+
res[k] = MergeMaps(value)
56+
case []interface{}:
57+
vCopy := make([]interface{}, len(value))
58+
copy(vCopy, value)
59+
res[k] = vCopy
60+
default:
61+
// assimilate KV pair
62+
res[k] = value
63+
}
64+
}
65+
}
66+
return res
67+
}

tests/misc_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package tests
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/infrawatch/apputils/misc"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
type TestStringer struct {
12+
numvalue int
13+
strvalue string
14+
}
15+
16+
func (ts TestStringer) String() string {
17+
return fmt.Sprintf("%s %d!", ts.strvalue, ts.numvalue)
18+
}
19+
20+
func TestStructsOperations(t *testing.T) {
21+
map1 := map[string]interface{}{
22+
"map": map[string]interface{}{
23+
"a": "A",
24+
"b": "B",
25+
"c": map[string]interface{}{
26+
"1": 1,
27+
"2": 2,
28+
},
29+
"d": []interface{}{"d1", "d2"},
30+
},
31+
"slice": []interface{}{
32+
"A",
33+
"B",
34+
},
35+
"float32": float32(.32),
36+
"float64": float64(.64),
37+
"int": int(1),
38+
"int8": int8(2),
39+
"int16": int16(3),
40+
"int32": int32(4),
41+
"int64": int64(5),
42+
"bool": true,
43+
"string": "dub dub",
44+
"stringer": TestStringer{numvalue: 666, strvalue: "wubba lubba"},
45+
}
46+
map2 := map[string]string{"key": "value"}
47+
map3 := map[string]interface{}{
48+
"map": map[string]interface{}{"foo": "bar"},
49+
"slice": []interface{}{"wubba", "lubba", "dub dub"},
50+
}
51+
52+
t.Run("Test AssimilateMap", func(t *testing.T) {
53+
testAssimilate := map[string]string{
54+
"key": "value",
55+
"a": "A",
56+
"b": "B",
57+
"1": "1",
58+
"2": "2",
59+
"d": "d1,d2",
60+
"slice": "A,B",
61+
"float32": "0.320000",
62+
"float64": "0.640000",
63+
"int": "1",
64+
"int8": "2",
65+
"int16": "3",
66+
"int32": "4",
67+
"int64": "5",
68+
"bool": "true",
69+
"string": "dub dub",
70+
"stringer": "wubba lubba 666!",
71+
}
72+
misc.AssimilateMap(map1, &map2)
73+
assert.Equal(t, testAssimilate, map2)
74+
})
75+
76+
t.Run("Test MergeMaps", func(t *testing.T) {
77+
testMerge := map[string]interface{}{
78+
"float32": float32(.32),
79+
"float64": float64(.64),
80+
"int": int(1),
81+
"int8": int8(2),
82+
"int16": int16(3),
83+
"int32": int32(4),
84+
"int64": int64(5),
85+
"bool": true,
86+
"string": "dub dub",
87+
"stringer": TestStringer{numvalue: 666, strvalue: "wubba lubba"},
88+
"map": map[string]interface{}{"foo": "bar"},
89+
"slice": []interface{}{"wubba", "lubba", "dub dub"},
90+
}
91+
map4 := misc.MergeMaps(map1, map3)
92+
assert.Equal(t, testMerge, map4)
93+
})
94+
95+
}

0 commit comments

Comments
 (0)