-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from infrawatch/asimilatemap
Move map operations from tools
- Loading branch information
Showing
2 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package misc | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
) | ||
|
||
// AssimilateMap recursively saves content of the given map to destination map of strings | ||
func AssimilateMap(theMap map[string]interface{}, destination *map[string]string) { | ||
defer func() { // recover from any panic | ||
if r := recover(); r != nil { | ||
log.Printf("Panic:recovered in assimilateMap %v\n", r) | ||
} | ||
}() | ||
for key, val := range theMap { | ||
switch value := val.(type) { | ||
case map[string]interface{}: | ||
// go one level deeper in the map | ||
AssimilateMap(value, destination) | ||
case []interface{}: | ||
// transform slice value to comma separated list and assimilate it | ||
aList := make([]string, 0, len(value)) | ||
for _, item := range value { | ||
if itm, ok := item.(string); ok { | ||
aList = append(aList, itm) | ||
} | ||
} | ||
(*destination)[key] = strings.Join(aList, ",") | ||
case float64, float32: | ||
(*destination)[key] = fmt.Sprintf("%f", value) | ||
case int, int8, int16, int32, int64: | ||
(*destination)[key] = fmt.Sprintf("%d", value) | ||
case bool: | ||
(*destination)[key] = fmt.Sprintf("%t", value) | ||
default: | ||
// assimilate KV pair | ||
if stringer, ok := value.(fmt.Stringer); ok { | ||
(*destination)[key] = stringer.String() | ||
} else { | ||
(*destination)[key] = value.(string) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// MergeMaps merges given maps into a new one | ||
func MergeMaps(ms ...map[string]interface{}) map[string]interface{} { | ||
res := make(map[string]interface{}) | ||
for _, m := range ms { | ||
for k, v := range m { | ||
switch value := v.(type) { | ||
case map[string]interface{}: | ||
// go one level deeper in the map | ||
res[k] = MergeMaps(value) | ||
case []interface{}: | ||
vCopy := make([]interface{}, len(value)) | ||
copy(vCopy, value) | ||
res[k] = vCopy | ||
default: | ||
// assimilate KV pair | ||
res[k] = value | ||
} | ||
} | ||
} | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package tests | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/infrawatch/apputils/misc" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
type TestStringer struct { | ||
numvalue int | ||
strvalue string | ||
} | ||
|
||
func (ts TestStringer) String() string { | ||
return fmt.Sprintf("%s %d!", ts.strvalue, ts.numvalue) | ||
} | ||
|
||
func TestStructsOperations(t *testing.T) { | ||
map1 := map[string]interface{}{ | ||
"map": map[string]interface{}{ | ||
"a": "A", | ||
"b": "B", | ||
"c": map[string]interface{}{ | ||
"1": 1, | ||
"2": 2, | ||
}, | ||
"d": []interface{}{"d1", "d2"}, | ||
}, | ||
"slice": []interface{}{ | ||
"A", | ||
"B", | ||
}, | ||
"float32": float32(.32), | ||
"float64": float64(.64), | ||
"int": int(1), | ||
"int8": int8(2), | ||
"int16": int16(3), | ||
"int32": int32(4), | ||
"int64": int64(5), | ||
"bool": true, | ||
"string": "dub dub", | ||
"stringer": TestStringer{numvalue: 666, strvalue: "wubba lubba"}, | ||
} | ||
map2 := map[string]string{"key": "value"} | ||
map3 := map[string]interface{}{ | ||
"map": map[string]interface{}{"foo": "bar"}, | ||
"slice": []interface{}{"wubba", "lubba", "dub dub"}, | ||
} | ||
|
||
t.Run("Test AssimilateMap", func(t *testing.T) { | ||
testAssimilate := map[string]string{ | ||
"key": "value", | ||
"a": "A", | ||
"b": "B", | ||
"1": "1", | ||
"2": "2", | ||
"d": "d1,d2", | ||
"slice": "A,B", | ||
"float32": "0.320000", | ||
"float64": "0.640000", | ||
"int": "1", | ||
"int8": "2", | ||
"int16": "3", | ||
"int32": "4", | ||
"int64": "5", | ||
"bool": "true", | ||
"string": "dub dub", | ||
"stringer": "wubba lubba 666!", | ||
} | ||
misc.AssimilateMap(map1, &map2) | ||
assert.Equal(t, testAssimilate, map2) | ||
}) | ||
|
||
t.Run("Test MergeMaps", func(t *testing.T) { | ||
testMerge := map[string]interface{}{ | ||
"float32": float32(.32), | ||
"float64": float64(.64), | ||
"int": int(1), | ||
"int8": int8(2), | ||
"int16": int16(3), | ||
"int32": int32(4), | ||
"int64": int64(5), | ||
"bool": true, | ||
"string": "dub dub", | ||
"stringer": TestStringer{numvalue: 666, strvalue: "wubba lubba"}, | ||
"map": map[string]interface{}{"foo": "bar"}, | ||
"slice": []interface{}{"wubba", "lubba", "dub dub"}, | ||
} | ||
map4 := misc.MergeMaps(map1, map3) | ||
assert.Equal(t, testMerge, map4) | ||
}) | ||
|
||
} |