Skip to content

Commit b4c53cb

Browse files
authored
Prefer rhs ordering while merging list. (#203)
* add list merge ordering test. * implement new rhs-preferred ordering. - merge and add each child of rhs - append each remaining child of lhs * update ordering in tests to reflect new ordering algorithm. * simplify merging algorithm. * simplify again. * additional tests for ordered merging.
1 parent 87c6f2e commit b4c53cb

File tree

2 files changed

+43
-36
lines changed

2 files changed

+43
-36
lines changed

typed/merge.go

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -172,55 +172,51 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs value.List) (err
172172
}
173173
out := make([]interface{}, 0, int(math.Max(float64(rLen), float64(lLen))))
174174

175-
// TODO: ordering is totally wrong.
176-
// TODO: might as well make the map order work the same way.
175+
lhsOrder := make([]fieldpath.PathElement, 0, lLen)
177176

178-
// This is a cheap hack to at least make the output order stable.
179-
rhsOrder := make([]fieldpath.PathElement, 0, rLen)
180-
181-
// First, collect all RHS children.
182-
observedRHS := fieldpath.MakePathElementValueMap(rLen)
183-
if rhs != nil {
184-
for i := 0; i < rhs.Length(); i++ {
185-
child := rhs.At(i)
177+
// First, collect all LHS children.
178+
observedLHS := fieldpath.MakePathElementValueMap(lLen)
179+
if lhs != nil {
180+
for i := 0; i < lhs.Length(); i++ {
181+
child := lhs.At(i)
186182
pe, err := listItemToPathElement(w.allocator, w.schema, t, i, child)
187183
if err != nil {
188-
errs = append(errs, errorf("rhs: element %v: %v", i, err.Error())...)
184+
errs = append(errs, errorf("lhs: element %v: %v", i, err.Error())...)
189185
// If we can't construct the path element, we can't
190186
// even report errors deeper in the schema, so bail on
191187
// this element.
192188
continue
193189
}
194-
if _, ok := observedRHS.Get(pe); ok {
195-
errs = append(errs, errorf("rhs: duplicate entries for key %v", pe.String())...)
190+
if _, ok := observedLHS.Get(pe); ok {
191+
errs = append(errs, errorf("lhs: duplicate entries for key %v", pe.String())...)
196192
}
197-
observedRHS.Insert(pe, child)
198-
rhsOrder = append(rhsOrder, pe)
193+
observedLHS.Insert(pe, child)
194+
lhsOrder = append(lhsOrder, pe)
199195
}
200196
}
201197

202-
// Then merge with LHS children.
203-
observedLHS := fieldpath.MakePathElementSet(lLen)
204-
if lhs != nil {
205-
for i := 0; i < lhs.Length(); i++ {
206-
child := lhs.At(i)
198+
// Then merge with RHS children.
199+
observedRHS := fieldpath.MakePathElementSet(rLen)
200+
if rhs != nil {
201+
for i := 0; i < rhs.Length(); i++ {
202+
child := rhs.At(i)
207203
pe, err := listItemToPathElement(w.allocator, w.schema, t, i, child)
208204
if err != nil {
209-
errs = append(errs, errorf("lhs: element %v: %v", i, err.Error())...)
205+
errs = append(errs, errorf("rhs: element %v: %v", i, err.Error())...)
210206
// If we can't construct the path element, we can't
211207
// even report errors deeper in the schema, so bail on
212208
// this element.
213209
continue
214210
}
215-
if observedLHS.Has(pe) {
216-
errs = append(errs, errorf("lhs: duplicate entries for key %v", pe.String())...)
211+
if observedRHS.Has(pe) {
212+
errs = append(errs, errorf("rhs: duplicate entries for key %v", pe.String())...)
217213
continue
218214
}
219-
observedLHS.Insert(pe)
215+
observedRHS.Insert(pe)
220216
w2 := w.prepareDescent(pe, t.ElementType)
221-
w2.lhs = value.Value(child)
222-
if rchild, ok := observedRHS.Get(pe); ok {
223-
w2.rhs = rchild
217+
w2.rhs = child
218+
if lchild, ok := observedLHS.Get(pe); ok {
219+
w2.lhs = lchild
224220
}
225221
errs = append(errs, w2.merge(pe.String)...)
226222
if w2.out != nil {
@@ -230,13 +226,13 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs value.List) (err
230226
}
231227
}
232228

233-
for _, pe := range rhsOrder {
234-
if observedLHS.Has(pe) {
229+
for _, pe := range lhsOrder {
230+
if observedRHS.Has(pe) {
235231
continue
236232
}
237-
value, _ := observedRHS.Get(pe)
233+
value, _ := observedLHS.Get(pe)
238234
w2 := w.prepareDescent(pe, t.ElementType)
239-
w2.rhs = value
235+
w2.lhs = value
240236
errs = append(errs, w2.merge(pe.String)...)
241237
if w2.out != nil {
242238
out = append(out, *w2.out)

typed/merge_test.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,12 +283,11 @@ var mergeCases = []mergeTestCase{{
283283
}, {
284284
`{"setBool":[true]}`,
285285
`{"setBool":[false]}`,
286-
`{"setBool":[true,false]}`,
286+
`{"setBool":[false,true]}`,
287287
}, {
288288
`{"setNumeric":[1,2,3.14159]}`,
289289
`{"setNumeric":[1,2,3]}`,
290-
// KNOWN BUG: this order is wrong
291-
`{"setNumeric":[1,2,3.14159,3]}`,
290+
`{"setNumeric":[1,2,3,3.14159]}`,
292291
}},
293292
}, {
294293
name: "associative list",
@@ -346,11 +345,23 @@ var mergeCases = []mergeTestCase{{
346345
}, {
347346
`{"list":[{"key":"a","id":1,"value":{"a":"a"}}]}`,
348347
`{"list":[{"key":"a","id":2,"value":{"a":"a"}}]}`,
349-
`{"list":[{"key":"a","id":1,"value":{"a":"a"}},{"key":"a","id":2,"value":{"a":"a"}}]}`,
348+
`{"list":[{"key":"a","id":2,"value":{"a":"a"}},{"key":"a","id":1,"value":{"a":"a"}}]}`,
350349
}, {
351350
`{"list":[{"key":"a","id":1},{"key":"b","id":1}]}`,
352351
`{"list":[{"key":"a","id":1},{"key":"a","id":2}]}`,
353-
`{"list":[{"key":"a","id":1},{"key":"b","id":1},{"key":"a","id":2}]}`,
352+
`{"list":[{"key":"a","id":1},{"key":"a","id":2},{"key":"b","id":1}]}`,
353+
}, {
354+
`{"list":[{"key":"b","id":2}]}`,
355+
`{"list":[{"key":"a","id":1},{"key":"b","id":2},{"key":"c","id":3}]}`,
356+
`{"list":[{"key":"a","id":1},{"key":"b","id":2},{"key":"c","id":3}]}`,
357+
}, {
358+
`{"list":[{"key":"a","id":1},{"key":"b","id":2},{"key":"c","id":3}]}`,
359+
`{"list":[{"key":"c","id":3},{"key":"b","id":2}]}`,
360+
`{"list":[{"key":"c","id":3},{"key":"b","id":2},{"key":"a","id":1}]}`,
361+
}, {
362+
`{"list":[{"key":"a","id":1},{"key":"b","id":2},{"key":"c","id":3}]}`,
363+
`{"list":[{"key":"c","id":3},{"key":"a","id":1}]}`,
364+
`{"list":[{"key":"c","id":3},{"key":"a","id":1},{"key":"b","id":2}]}`,
354365
}, {
355366
`{"atomicList":["a","a","a"]}`,
356367
`{"atomicList":null}`,

0 commit comments

Comments
 (0)