github.com/yanndegat/hiera@v0.6.8/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/yanndegat/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 }