func getNodeFieldSegmented()

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)
	}
}