-
Notifications
You must be signed in to change notification settings - Fork 66
typed: Allow duplicates when we merge #253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -180,14 +180,18 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs value.List) (err | |
} | ||
out := make([]interface{}, 0, outLen) | ||
|
||
rhsOrder, observedRHS, rhsErrs := w.indexListPathElements(t, rhs) | ||
rhsPEs, observedRHS, rhsErrs := w.indexListPathElements(t, rhs, false) | ||
errs = append(errs, rhsErrs...) | ||
lhsOrder, observedLHS, lhsErrs := w.indexListPathElements(t, lhs) | ||
lhsPEs, observedLHS, lhsErrs := w.indexListPathElements(t, lhs, true) | ||
errs = append(errs, lhsErrs...) | ||
|
||
if len(errs) != 0 { | ||
return errs | ||
} | ||
|
||
sharedOrder := make([]*fieldpath.PathElement, 0, rLen) | ||
for i := range rhsOrder { | ||
pe := &rhsOrder[i] | ||
for i := range rhsPEs { | ||
pe := &rhsPEs[i] | ||
if _, ok := observedLHS.Get(*pe); ok { | ||
sharedOrder = append(sharedOrder, pe) | ||
} | ||
|
@@ -199,13 +203,15 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs value.List) (err | |
sharedOrder = sharedOrder[1:] | ||
} | ||
|
||
lLen, rLen = len(lhsOrder), len(rhsOrder) | ||
mergedRHS := fieldpath.MakePathElementMap(len(rhsPEs)) | ||
lLen, rLen = len(lhsPEs), len(rhsPEs) | ||
for lI, rI := 0, 0; lI < lLen || rI < rLen; { | ||
if lI < lLen && rI < rLen { | ||
pe := lhsOrder[lI] | ||
if pe.Equals(rhsOrder[rI]) { | ||
pe := lhsPEs[lI] | ||
if pe.Equals(rhsPEs[rI]) { | ||
// merge LHS & RHS items | ||
lChild, _ := observedLHS.Get(pe) | ||
mergedRHS.Insert(pe, struct{}{}) | ||
lChild, _ := observedLHS.Get(pe) // may be nil if the PE is duplicaated. | ||
rChild, _ := observedRHS.Get(pe) | ||
mergeOut, errs := w.mergeListItem(t, pe, lChild, rChild) | ||
errs = append(errs, errs...) | ||
|
@@ -222,30 +228,34 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs value.List) (err | |
} | ||
continue | ||
} | ||
if _, ok := observedRHS.Get(pe); ok && nextShared != nil && !nextShared.Equals(lhsOrder[lI]) { | ||
if _, ok := observedRHS.Get(pe); ok && nextShared != nil && !nextShared.Equals(lhsPEs[lI]) { | ||
// shared item, but not the one we want in this round | ||
lI++ | ||
continue | ||
} | ||
} | ||
if lI < lLen { | ||
pe := lhsOrder[lI] | ||
pe := lhsPEs[lI] | ||
if _, ok := observedRHS.Get(pe); !ok { | ||
// take LHS item | ||
lChild, _ := observedLHS.Get(pe) | ||
// take LHS item using At to make sure we get the right item (observed may not contain the right item). | ||
lChild := lhs.AtUsing(w.allocator, lI) | ||
apelisse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
mergeOut, errs := w.mergeListItem(t, pe, lChild, nil) | ||
errs = append(errs, errs...) | ||
if mergeOut != nil { | ||
out = append(out, *mergeOut) | ||
} | ||
lI++ | ||
continue | ||
} else if _, ok := mergedRHS.Get(pe); ok { | ||
// we've already merged it with RHS, we don't want to duplicate it, skip it. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure why this case is necessary. It's hard to track the invariants of |
||
lI++ | ||
} | ||
} | ||
if rI < rLen { | ||
// Take the RHS item, merge with matching LHS item if possible | ||
pe := rhsOrder[rI] | ||
lChild, _ := observedLHS.Get(pe) // may be nil | ||
pe := rhsPEs[rI] | ||
mergedRHS.Insert(pe, struct{}{}) | ||
lChild, _ := observedLHS.Get(pe) // may be nil if absent or duplicaated. | ||
rChild, _ := observedRHS.Get(pe) | ||
mergeOut, errs := w.mergeListItem(t, pe, lChild, rChild) | ||
errs = append(errs, errs...) | ||
|
@@ -272,7 +282,7 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs value.List) (err | |
return errs | ||
} | ||
|
||
func (w *mergingWalker) indexListPathElements(t *schema.List, list value.List) ([]fieldpath.PathElement, fieldpath.PathElementValueMap, ValidationErrors) { | ||
func (w *mergingWalker) indexListPathElements(t *schema.List, list value.List, allowDuplicates bool) ([]fieldpath.PathElement, fieldpath.PathElementValueMap, ValidationErrors) { | ||
var errs ValidationErrors | ||
length := 0 | ||
if list != nil { | ||
|
@@ -290,11 +300,15 @@ func (w *mergingWalker) indexListPathElements(t *schema.List, list value.List) ( | |
// this element. | ||
continue | ||
} | ||
if _, found := observed.Get(pe); found { | ||
if _, found := observed.Get(pe); found && !allowDuplicates { | ||
errs = append(errs, errorf("duplicate entries for key %v", pe.String())...) | ||
continue | ||
} else if !found { | ||
observed.Insert(pe, child) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this existence check necessary? Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. observed is a map from pathelement to the actual value. the value that ends-up being in the PE is the one we're going to use to merge I think, so if we were to override here, I think we would end-up merging with the last item in the list rather than the first. But since we've decided we might not want to do that, I will probably deal with that differently. |
||
} else { | ||
// Duplicated items are not merged with the new value, make them nil. | ||
observed.Insert(pe, value.NewValueInterface(nil)) | ||
} | ||
observed.Insert(pe, child) | ||
pes = append(pes, pe) | ||
} | ||
return pes, observed, errs | ||
|
Uh oh!
There was an error while loading. Please reload this page.