util/reflect: add ability to merge maps
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
		| @@ -44,6 +44,37 @@ func SliceAppend(b bool) Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var maxDepth = 32 | ||||
|  | ||||
| func mergeMap(dst, src map[string]interface{}, depth int) map[string]interface{} { | ||||
| 	if depth > maxDepth { | ||||
| 		return dst | ||||
| 	} | ||||
| 	for key, srcVal := range src { | ||||
| 		if dstVal, ok := dst[key]; ok { | ||||
| 			srcMap, srcMapOk := mapify(srcVal) | ||||
| 			dstMap, dstMapOk := mapify(dstVal) | ||||
| 			if srcMapOk && dstMapOk { | ||||
| 				srcVal = mergeMap(dstMap, srcMap, depth+1) | ||||
| 			} | ||||
| 		} | ||||
| 		dst[key] = srcVal | ||||
| 	} | ||||
| 	return dst | ||||
| } | ||||
|  | ||||
| func mapify(i interface{}) (map[string]interface{}, bool) { | ||||
| 	value := reflect.ValueOf(i) | ||||
| 	if value.Kind() == reflect.Map { | ||||
| 		m := map[string]interface{}{} | ||||
| 		for _, k := range value.MapKeys() { | ||||
| 			m[k.String()] = value.MapIndex(k).Interface() | ||||
| 		} | ||||
| 		return m, true | ||||
| 	} | ||||
| 	return map[string]interface{}{}, false | ||||
| } | ||||
|  | ||||
| // Merge merges map[string]interface{} to destination struct | ||||
| func Merge(dst interface{}, mp map[string]interface{}, opts ...Option) error { | ||||
| 	options := Options{} | ||||
| @@ -59,6 +90,11 @@ func Merge(dst interface{}, mp map[string]interface{}, opts ...Option) error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if mapper, ok := dst.(map[string]interface{}); ok { | ||||
| 		dst = mergeMap(mapper, mp, 0) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var sval reflect.Value | ||||
| 	var fname string | ||||
|   | ||||
| @@ -4,6 +4,27 @@ import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestMergeMap(t *testing.T) { | ||||
| 	src := map[string]interface{}{ | ||||
| 		"skey1": "sval1", | ||||
| 		"skey2": map[string]interface{}{ | ||||
| 			"skey3": "sval3", | ||||
| 		}, | ||||
| 	} | ||||
| 	dst := map[string]interface{}{ | ||||
| 		"skey1": "dval1", | ||||
| 		"skey2": map[string]interface{}{ | ||||
| 			"skey3": "dval3", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	if err := Merge(src, dst); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	t.Logf("%#+v", src) | ||||
| } | ||||
|  | ||||
| func TestFieldName(t *testing.T) { | ||||
| 	src := "SomeVar" | ||||
| 	chk := "some_var" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user