map.go

 1// Copyright 2020 Jebbs. All rights reserved.
 2// Use of this source code is governed by MIT
 3// license that can be found in the LICENSE file.
 4
 5package merge
 6
 7import (
 8	"fmt"
 9	"reflect"
10)
11
12// Maps merges source maps into target
13func Maps(target map[string]interface{}, sources ...map[string]interface{}) (err error) {
14	for _, source := range sources {
15		err = mergeMaps(target, source)
16		if err != nil {
17			return err
18		}
19	}
20	return nil
21}
22
23// mergeMaps merges source map into target
24// it supports only map[string]interface{} type for any children of the map tree
25func mergeMaps(target map[string]interface{}, source map[string]interface{}) (err error) {
26	for key, value := range source {
27		target[key], err = mergeField(target[key], value)
28		if err != nil {
29			return fmt.Errorf("field '%s': %s", key, err)
30		}
31	}
32	return nil
33}
34
35func mergeField(target interface{}, source interface{}) (interface{}, error) {
36	if source == nil {
37		return target, nil
38	}
39	if target == nil {
40		return source, nil
41	}
42	if reflect.TypeOf(source) != reflect.TypeOf(target) {
43		return nil, fmt.Errorf("type mismatch, expect %T, incoming %T", target, source)
44	}
45	if slice, ok := source.([]interface{}); ok {
46		tslice, _ := target.([]interface{})
47		tslice = append(tslice, slice...)
48		return tslice, nil
49	} else if smap, ok := source.(map[string]interface{}); ok {
50		tmap, _ := target.(map[string]interface{})
51		err := mergeMaps(tmap, smap)
52		return tmap, err
53	}
54	return source, nil
55}