deep merge
This commit is contained in:
@@ -10,7 +10,6 @@ import (
|
|||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
"cloud.o-forge.io/core/oc-lib/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Booking is a struct that represents a booking
|
* Booking is a struct that represents a booking
|
||||||
*/
|
*/
|
||||||
|
|||||||
+83
-4
@@ -128,10 +128,8 @@ func ModelGenericUpdateOne(change map[string]interface{}, id string, a Accessor)
|
|||||||
r.Sign()
|
r.Sign()
|
||||||
}
|
}
|
||||||
|
|
||||||
loaded := r.Serialize(r) // get the loaded object
|
loaded := r.Serialize(r) // get the loaded object
|
||||||
for k, v := range change { // apply the changes, with a flatten method
|
deepMerge(loaded, change)
|
||||||
loaded[k] = v
|
|
||||||
}
|
|
||||||
newObj := a.NewObj()
|
newObj := a.NewObj()
|
||||||
b, err = json.Marshal(loaded)
|
b, err = json.Marshal(loaded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -255,6 +253,87 @@ func IsMySelf(peerID string, wfa Accessor) (bool, string) {
|
|||||||
return peerID == pp.GetID(), pp.GetID()
|
return peerID == pp.GetID(), pp.GetID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deepMerge overlays patch values onto base, preserving base values for keys
|
||||||
|
// absent from patch, nil patch values, and empty strings when base is non-empty.
|
||||||
|
// This prevents partial frontend payloads from silently erasing server-managed
|
||||||
|
// fields (source, env, country, owners, creator_id, creation_date, …).
|
||||||
|
func deepMerge(base, patch map[string]interface{}) {
|
||||||
|
for k, pv := range patch {
|
||||||
|
bv := base[k]
|
||||||
|
switch pvTyped := pv.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
if bvMap, ok := bv.(map[string]interface{}); ok {
|
||||||
|
deepMerge(bvMap, pvTyped)
|
||||||
|
} else {
|
||||||
|
base[k] = pv
|
||||||
|
}
|
||||||
|
case []interface{}:
|
||||||
|
if bvSlice, ok := bv.([]interface{}); ok {
|
||||||
|
base[k] = mergeSlices(bvSlice, pvTyped)
|
||||||
|
} else {
|
||||||
|
base[k] = pv
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
// Don't overwrite a non-empty base value with an empty string.
|
||||||
|
if pvTyped != "" {
|
||||||
|
base[k] = pv
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if pv != nil {
|
||||||
|
base[k] = pv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeSlices merges two slices element-wise.
|
||||||
|
// For slices of maps it matches elements by their "id" field when available;
|
||||||
|
// falls back to positional matching. An empty patch slice leaves base intact.
|
||||||
|
func mergeSlices(base, patch []interface{}) []interface{} {
|
||||||
|
if len(patch) == 0 {
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
for _, e := range patch {
|
||||||
|
if _, ok := e.(map[string]interface{}); !ok {
|
||||||
|
return patch // non-map elements: replace wholesale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
baseByID := map[string]map[string]interface{}{}
|
||||||
|
for _, e := range base {
|
||||||
|
if em, ok := e.(map[string]interface{}); ok {
|
||||||
|
if id, ok := em["id"].(string); ok && id != "" {
|
||||||
|
baseByID[id] = em
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := make([]interface{}, 0, len(patch))
|
||||||
|
for i, pe := range patch {
|
||||||
|
pm, _ := pe.(map[string]interface{})
|
||||||
|
if pm == nil {
|
||||||
|
result = append(result, pe)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var baseElem map[string]interface{}
|
||||||
|
if id, ok := pm["id"].(string); ok && id != "" {
|
||||||
|
baseElem = baseByID[id]
|
||||||
|
}
|
||||||
|
if baseElem == nil && i < len(base) {
|
||||||
|
baseElem, _ = base[i].(map[string]interface{})
|
||||||
|
}
|
||||||
|
if baseElem != nil {
|
||||||
|
merged := make(map[string]interface{}, len(baseElem))
|
||||||
|
for k, v := range baseElem {
|
||||||
|
merged[k] = v
|
||||||
|
}
|
||||||
|
deepMerge(merged, pm)
|
||||||
|
result = append(result, merged)
|
||||||
|
} else {
|
||||||
|
result = append(result, pe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateNodeID() (string, error) {
|
func GenerateNodeID() (string, error) {
|
||||||
folderStatic := "/var/lib/opencloud-node"
|
folderStatic := "/var/lib/opencloud-node"
|
||||||
if _, err := os.Stat(folderStatic); err == nil {
|
if _, err := os.Stat(folderStatic); err == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user