github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/toolkit/maputils/maputils.go (about) 1 package maputils 2 3 import ( 4 "github.com/unionj-cloud/go-doudou/toolkit/sliceutils" 5 "reflect" 6 ) 7 8 type ChangeType int 9 10 const ( 11 ADDED ChangeType = iota 12 MODIFIED 13 DELETED 14 ) 15 16 type Change struct { 17 OldValue interface{} 18 NewValue interface{} 19 ChangeType ChangeType 20 } 21 22 func Diff(new, old map[string]interface{}) map[string]Change { 23 mp := map[string]bool{} 24 for k, _ := range old { 25 mp[k] = true 26 } 27 changes := make(map[string]Change) 28 29 if new != nil { 30 for key, value := range new { 31 //key state insert or update 32 //insert 33 if !mp[key] { 34 changes[key] = createAddChange(value) 35 } else { 36 //update 37 oldValue := old[key] 38 if !reflect.DeepEqual(oldValue, value) { 39 changes[key] = createModifyChange(oldValue, value) 40 } 41 } 42 delete(mp, key) 43 } 44 } 45 46 // remove del keys 47 for key := range mp { 48 //get old value and del 49 oldValue := old[key] 50 changes[key] = createDeletedChange(oldValue) 51 } 52 53 return changes 54 } 55 56 func createModifyChange(oldValue interface{}, newValue interface{}) Change { 57 return Change{ 58 OldValue: oldValue, 59 NewValue: newValue, 60 ChangeType: MODIFIED, 61 } 62 } 63 64 func createAddChange(newValue interface{}) Change { 65 return Change{ 66 NewValue: newValue, 67 ChangeType: ADDED, 68 } 69 } 70 71 func createDeletedChange(oldValue interface{}) Change { 72 return Change{ 73 OldValue: oldValue, 74 ChangeType: DELETED, 75 } 76 } 77 78 var ( 79 MaxDepth = 32 80 ) 81 82 // Merge recursively merges the src and dst maps. Key conflicts are resolved by 83 // preferring src, or recursively descending, if both src and dst are maps. 84 // borrow code from https://github.com/peterbourgon/mergemap 85 func Merge(dst, src map[string]interface{}) map[string]interface{} { 86 return merge(dst, src, 0, false) 87 } 88 89 func MergeOverwriteSlice(dst, src map[string]interface{}) map[string]interface{} { 90 return merge(dst, src, 0, true) 91 } 92 93 // overwrite means overwrite slice value 94 func merge(dst, src map[string]interface{}, depth int, overwrite bool) map[string]interface{} { 95 if depth > MaxDepth { 96 panic("too deep!") 97 } 98 for key, srcVal := range src { 99 if dstVal, ok := dst[key]; ok { 100 srcMap, srcMapOk := mapify(srcVal) 101 dstMap, dstMapOk := mapify(dstVal) 102 if srcMapOk && dstMapOk { 103 srcVal = merge(dstMap, srcMap, depth+1, overwrite) 104 goto REWRITE 105 } 106 if overwrite { 107 goto REWRITE 108 } 109 srcSlice, srcSliceOk := sliceutils.TakeSliceArg(srcVal) 110 dstSlice, dstSliceOk := sliceutils.TakeSliceArg(dstVal) 111 if srcSliceOk && dstSliceOk { 112 merged := make([]interface{}, 0) 113 kv := make(map[interface{}]struct{}) 114 for _, item := range dstSlice { 115 if !reflect.ValueOf(item).Type().Comparable() { 116 merged = append(merged, item) 117 continue 118 } 119 if _, exists := kv[item]; !exists { 120 merged = append(merged, item) 121 kv[item] = struct{}{} 122 } 123 } 124 for _, item := range srcSlice { 125 if !reflect.ValueOf(item).Type().Comparable() { 126 merged = append(merged, item) 127 continue 128 } 129 if _, exists := kv[item]; !exists { 130 merged = append(merged, item) 131 kv[item] = struct{}{} 132 } 133 } 134 srcVal = merged 135 } 136 } 137 REWRITE: 138 dst[key] = srcVal 139 } 140 return dst 141 } 142 143 func mapify(i interface{}) (map[string]interface{}, bool) { 144 value := reflect.ValueOf(i) 145 if value.Kind() == reflect.Map { 146 m := map[string]interface{}{} 147 for _, k := range value.MapKeys() { 148 m[k.String()] = value.MapIndex(k).Interface() 149 } 150 return m, true 151 } 152 return map[string]interface{}{}, false 153 }