Skip to content

fix: apply per-candidate index when traversing arrays/maps by a streamed index#2750

Open
StressTestor wants to merge 1 commit into
mikefarah:masterfrom
StressTestor:fix/traverse-array-context-index
Open

fix: apply per-candidate index when traversing arrays/maps by a streamed index#2750
StressTestor wants to merge 1 commit into
mikefarah:masterfrom
StressTestor:fix/traverse-array-context-index

Conversation

@StressTestor

Copy link
Copy Markdown

Note: this PR was prepared by an AI agent (Claude Code) acting on behalf of @StressTestor, not by the user personally.

what

$o[.] over a streamed context only returned the first match. this fixes it.

echo '["a","b"]' | yq '. as $o | keys[] | $o[.]'
# before: a
# after:  a
#         b

it hits maps the same way: echo '{"x":1,"y":2}' | yq '. as $o | keys[] | $o[.]' returned only 1.

why

the index in $o[.] is a collect expression that yields one index set per incoming candidate (for keys[] streaming 0 then 1, it yields [0] then [1]). traverseArrayOperator evaluated it over the whole context but then used only rhs.MatchingNodes.Front(), the first index set, so every candidate but the first was dropped. the . as $k | $o[.] workaround worked because as splits the stream, so each call sees a single candidate and Front() is enough.

fix

pair each index set with its candidate (pkg/yqlib/operator_traverse_path.go):

  • when the LHS has one node per candidate (.[] | .[idx]), traverse each LHS node with its own index set
  • when the LHS collapses to a single node (a variable like $o), traverse it against every index set

LHS and RHS are still each evaluated once over the whole context, so positional operators like split_doc keep their document index.

tests

regression scenarios for the array and map forms in operator_traverse_path_test.go. full go test ./... passes, and the existing traverse and split-doc scenarios are unchanged.

Fixes #2593.

…med index

`$o[.]` over a streamed context (e.g. `keys[] | $o[.]`) only returned the
first match. The index expression yields one index set per incoming
candidate, but traverseArrayOperator used only the first set
(rhs.MatchingNodes.Front()), dropping the rest.

Pair each index set with its candidate: when the LHS has one node per
candidate (e.g. `.[] | .[idx]`) each node is traversed with its own index
set; when the LHS collapses to a single node (a variable) it is traversed
against every index set. Covers both arrays and maps.

Fixes mikefarah#2593.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extracting object values by iterating via keys causes missing items

1 participant