github.com/lyraproj/hiera@v1.0.0-rc4/merge/deepmerge.go (about)

     1  package merge
     2  
     3  import (
     4  	"github.com/lyraproj/dgo/dgo"
     5  	"github.com/lyraproj/dgo/vf"
     6  	"github.com/lyraproj/hiera/api"
     7  )
     8  
     9  // Deep will merge the values 'a' and 'b' if both values are hashes or both values are
    10  // arrays. When this is not the case, no merge takes place and the 'a' argument is returned.
    11  // The second bool return value true if a merge took place and false when the first argument
    12  // is returned.
    13  //
    14  // When both values are hashes, Deep is called recursively entries with identical keys.
    15  // When both values are arrays, the merge creates a union of the unique elements from the two arrays.
    16  // No recursive merge takes place for the array elements.
    17  func Deep(a, b dgo.Value, opi interface{}) (dgo.Value, bool) {
    18  	var options dgo.Map
    19  	if opi != nil {
    20  		options = api.ToMap(`deep merge options`, options)
    21  	}
    22  	return deep(a, b, options)
    23  }
    24  
    25  func deep(a, b dgo.Value, options dgo.Map) (dgo.Value, bool) {
    26  	switch a := a.(type) {
    27  	case dgo.Map:
    28  		if hb, ok := b.(dgo.Map); ok {
    29  			es := vf.MapWithCapacity(a.Len() + hb.Len())
    30  			a.EachEntry(func(e dgo.MapEntry) {
    31  				if bv := hb.Get(e.Key()); bv != nil {
    32  					if m, mh := deep(e.Value(), bv, options); mh {
    33  						es.Put(e.Key(), m)
    34  						return
    35  					}
    36  				}
    37  				es.Put(e.Key(), e.Value())
    38  			})
    39  			hb.EachEntry(func(e dgo.MapEntry) {
    40  				if !a.ContainsKey(e.Key()) {
    41  					es.Put(e.Key(), e.Value())
    42  				}
    43  			})
    44  			if !a.Equals(es) {
    45  				return es, true
    46  			}
    47  		}
    48  
    49  	case dgo.Array:
    50  		if ab, ok := b.(dgo.Array); ok && ab.Len() > 0 {
    51  			if a.Len() == 0 {
    52  				return ab, true
    53  			}
    54  			an := a.WithAll(ab).Unique()
    55  			if !an.Equals(a) {
    56  				return an, true
    57  			}
    58  		}
    59  	}
    60  	return a, false
    61  }