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 | // Merge merges map[string]interface{} to destination struct | ||||||
| func Merge(dst interface{}, mp map[string]interface{}, opts ...Option) error { | func Merge(dst interface{}, mp map[string]interface{}, opts ...Option) error { | ||||||
| 	options := Options{} | 	options := Options{} | ||||||
| @@ -59,6 +90,11 @@ func Merge(dst interface{}, mp map[string]interface{}, opts ...Option) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if mapper, ok := dst.(map[string]interface{}); ok { | ||||||
|  | 		dst = mergeMap(mapper, mp, 0) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	var err error | 	var err error | ||||||
| 	var sval reflect.Value | 	var sval reflect.Value | ||||||
| 	var fname string | 	var fname string | ||||||
|   | |||||||
| @@ -4,6 +4,27 @@ import ( | |||||||
| 	"testing" | 	"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) { | func TestFieldName(t *testing.T) { | ||||||
| 	src := "SomeVar" | 	src := "SomeVar" | ||||||
| 	chk := "some_var" | 	chk := "some_var" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user