in wstl1/mapping_engine/util/jsonutil/jsonmetautil.go [303:377]
func getNodeFieldSegmented(node JSONMetaNode, segments []string) (JSONMetaNode, bool, error) {
if len(segments) == 0 {
return node, false, nil
}
seg := segments[0]
switch n := node.(type) {
case JSONMetaPrimitiveNode:
return nil, false, fmt.Errorf("attempted to key into primitive with %q", seg)
case JSONMetaArrayNode:
if !IsIndex(seg) {
return nil, false, fmt.Errorf("expected an array index with brackets like [123] or [*] but got %q", seg)
}
idxSubstr := seg[1 : len(seg)-1]
if idxSubstr == "*" {
retNode := JSONMetaArrayNode{
JSONMeta: n.JSONMeta,
}
for i := range n.Items {
f, expand, err := getNodeFieldSegmented(n.Items[i], segments[1:])
if err != nil {
return nil, false, fmt.Errorf("error expanding [*] on item index %d: %v", i, err)
}
// If an array expansion occurs down the line, we need to unnest the resulting array here.
if expand {
fArr, ok := f.(JSONMetaArrayNode)
if !ok {
return nil, false, fmt.Errorf("bug: getNodeFieldSegmented returned true for expansion but value was not an array (was %T)", f)
}
retNode.Items = append(retNode.Items, fArr.Items...)
} else {
retNode.Items = append(retNode.Items, f)
}
}
return retNode, true, nil
}
idx, err := strconv.Atoi(idxSubstr)
if err != nil {
return nil, false, fmt.Errorf("could not parse array index %q: %v", seg, err)
}
if idx < 0 {
return nil, false, fmt.Errorf("negative array indices are not supported but got %d", idx)
}
if idx >= len(n.Items) {
// TODO(): Consider returning a different value for fields that don't exist vs
// fields that are actually set to null.
return nil, false, nil
}
return getNodeFieldSegmented(n.Items[idx], segments[1:])
case JSONMetaContainerNode:
if IsIndex(seg) {
return nil, false, fmt.Errorf("expected an object key, but got an array index %q", seg)
}
if val, ok := n.Children[seg]; ok {
return getNodeFieldSegmented(val, segments[1:])
}
// TODO(): Consider returning a different value for fields that don't exist vs
// fields that are actually set to null.
return nil, false, nil
case nil:
return nil, false, nil
default:
return nil, false, fmt.Errorf("found node of un-navigable type %T", node)
}
}