Apply nested collection operations when copying mappings
This commit is contained in:
@@ -22,21 +22,28 @@ func mergeRecursiveMappings(target, incoming *document.Node, current Path, index
|
||||
if hooks.merge != nil {
|
||||
if merged, handled := hooks.merge(path, nil, entry.Value); handled {
|
||||
cloned := entry
|
||||
cloned.Value = document.Clone(merged)
|
||||
cloned.Value = cloneMergeSubtree(merged, path, hooks.merge)
|
||||
index.append(target, cloned)
|
||||
continue
|
||||
}
|
||||
}
|
||||
cloned := entry
|
||||
cloned.Value = document.Clone(entry.Value)
|
||||
index.append(target, cloned)
|
||||
if hooks.added != nil {
|
||||
hooks.added(path, entry.Value)
|
||||
}
|
||||
cloned := entry
|
||||
cloned.Value = cloneMergeSubtree(entry.Value, path, hooks.merge)
|
||||
index.append(target, cloned)
|
||||
continue
|
||||
}
|
||||
|
||||
existing := target.Mapping[position].Value
|
||||
if hooks.merge != nil {
|
||||
if merged, handled := hooks.merge(path, existing, entry.Value); handled {
|
||||
target.Mapping[position] = entry
|
||||
target.Mapping[position].Value = cloneMergeSubtree(merged, path, hooks.merge)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if existing.Kind == document.Mapping && entry.Value.Kind == document.Mapping {
|
||||
if hooks.combined != nil {
|
||||
hooks.combined(path, entry.Value)
|
||||
@@ -44,18 +51,33 @@ func mergeRecursiveMappings(target, incoming *document.Node, current Path, index
|
||||
mergeRecursiveMappings(existing, entry.Value, path, index, hooks)
|
||||
continue
|
||||
}
|
||||
if hooks.merge != nil {
|
||||
if merged, handled := hooks.merge(path, existing, entry.Value); handled {
|
||||
target.Mapping[position] = entry
|
||||
target.Mapping[position].Value = document.Clone(merged)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if hooks.replaced != nil {
|
||||
hooks.replaced(path, existing, entry.Value)
|
||||
}
|
||||
target.Mapping[position] = entry
|
||||
target.Mapping[position].Value = document.Clone(entry.Value)
|
||||
target.Mapping[position].Value = cloneMergeSubtree(entry.Value, path, hooks.merge)
|
||||
}
|
||||
}
|
||||
|
||||
// A copied mapping can contain collection operations even though its ancestor
|
||||
// has no retained mapping. Visit those operations with absent lower values.
|
||||
// Ordinary origin/replacement hooks already accounted for the whole subtree;
|
||||
// do not replay them for every descendant. Records inside sequences remain whole.
|
||||
func cloneMergeSubtree(incoming *document.Node, path Path, merge func(Path, *document.Node, *document.Node) (*document.Node, bool)) *document.Node {
|
||||
if incoming == nil || incoming.Kind != document.Mapping || merge == nil {
|
||||
return document.Clone(incoming)
|
||||
}
|
||||
cloned := *incoming
|
||||
cloned.Mapping = make([]document.Entry, len(incoming.Mapping))
|
||||
for index, entry := range incoming.Mapping {
|
||||
childPath := path.Key(entry.Key)
|
||||
value := entry.Value
|
||||
if merged, handled := merge(childPath, nil, value); handled {
|
||||
value = merged
|
||||
}
|
||||
entry.Value = cloneMergeSubtree(value, childPath, merge)
|
||||
cloned.Mapping[index] = entry
|
||||
}
|
||||
return &cloned
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user