From eb9181670e2884e76f8357a0493aa5564af87a45 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Tue, 28 Feb 2023 16:14:42 +1100 Subject: [PATCH] Fixed variable operator to work like jq --- pkg/yqlib/doc/operators/multiply-merge.md | 11 ++++++++++- pkg/yqlib/operator_alternative_test.go | 2 +- pkg/yqlib/operator_booleans_test.go | 18 +++++++++++++----- pkg/yqlib/operator_equals_test.go | 4 ++-- pkg/yqlib/operator_has_test.go | 2 +- pkg/yqlib/operator_subtract_test.go | 2 +- pkg/yqlib/operator_traverse_path_test.go | 2 +- pkg/yqlib/operator_union_test.go | 2 +- pkg/yqlib/operator_variables.go | 17 ++++++++++++++--- 9 files changed, 44 insertions(+), 16 deletions(-) diff --git a/pkg/yqlib/doc/operators/multiply-merge.md b/pkg/yqlib/doc/operators/multiply-merge.md index ac12e721..60967413 100644 --- a/pkg/yqlib/doc/operators/multiply-merge.md +++ b/pkg/yqlib/doc/operators/multiply-merge.md @@ -329,7 +329,16 @@ idPath=".a" originalPath=".myArray" otherPath=".newArray" yq eval-all ' ``` will output ```yaml -myArray: [] +myArray: + - a: apple + b: appleB2 + - a: kiwi + b: kiwiB + - a: banana + b: bananaB + c: bananaC + - a: dingo + c: dingoC something: else ``` diff --git a/pkg/yqlib/operator_alternative_test.go b/pkg/yqlib/operator_alternative_test.go index 74106639..e70b8b25 100644 --- a/pkg/yqlib/operator_alternative_test.go +++ b/pkg/yqlib/operator_alternative_test.go @@ -16,7 +16,7 @@ var alternativeOperatorScenarios = []expressionScenario{ }, { skipDoc: true, - expression: `(.b // "hello") as $x`, + expression: `(.b // "hello") as $x | .`, document: `a: bridge`, expected: []string{ "D0, P[], (doc)::a: bridge\n", diff --git a/pkg/yqlib/operator_booleans_test.go b/pkg/yqlib/operator_booleans_test.go index f5735bb2..dc219ad1 100644 --- a/pkg/yqlib/operator_booleans_test.go +++ b/pkg/yqlib/operator_booleans_test.go @@ -102,7 +102,7 @@ var booleanOperatorScenarios = []expressionScenario{ { skipDoc: true, document: `[{pet: cat}]`, - expression: `any_c(.name == "harry") as $c`, + expression: `any_c(.name == "harry") as $c | .`, expected: []string{ "D0, P[], (doc)::[{pet: cat}]\n", }, @@ -110,9 +110,17 @@ var booleanOperatorScenarios = []expressionScenario{ { skipDoc: true, document: `[{pet: cat}]`, - expression: `all_c(.name == "harry") as $c`, + expression: `any_c(.name == "harry") as $c | $c`, expected: []string{ - "D0, P[], (doc)::[{pet: cat}]\n", + "D0, P[], (!!bool)::false\n", + }, + }, + { + skipDoc: true, + document: `[{pet: cat}]`, + expression: `all_c(.name == "harry") as $c | $c`, + expected: []string{ + "D0, P[], (!!bool)::false\n", }, }, { @@ -185,7 +193,7 @@ var booleanOperatorScenarios = []expressionScenario{ { skipDoc: true, document: `{}`, - expression: `(.a.b or .c) as $x`, + expression: `(.a.b or .c) as $x | .`, expected: []string{ "D0, P[], (doc)::{}\n", }, @@ -193,7 +201,7 @@ var booleanOperatorScenarios = []expressionScenario{ { skipDoc: true, document: `{}`, - expression: `(.a.b and .c) as $x`, + expression: `(.a.b and .c) as $x | .`, expected: []string{ "D0, P[], (doc)::{}\n", }, diff --git a/pkg/yqlib/operator_equals_test.go b/pkg/yqlib/operator_equals_test.go index 37fe5005..7a821647 100644 --- a/pkg/yqlib/operator_equals_test.go +++ b/pkg/yqlib/operator_equals_test.go @@ -47,7 +47,7 @@ var equalsOperatorScenarios = []expressionScenario{ { skipDoc: true, document: "{}", - expression: "(.a == .b) as $x", + expression: "(.a == .b) as $x | .", expected: []string{ "D0, P[], (doc)::{}\n", }, @@ -63,7 +63,7 @@ var equalsOperatorScenarios = []expressionScenario{ { skipDoc: true, document: "{}", - expression: "(.a != .b) as $x", + expression: "(.a != .b) as $x | .", expected: []string{ "D0, P[], (doc)::{}\n", }, diff --git a/pkg/yqlib/operator_has_test.go b/pkg/yqlib/operator_has_test.go index 3a631330..47504048 100644 --- a/pkg/yqlib/operator_has_test.go +++ b/pkg/yqlib/operator_has_test.go @@ -16,7 +16,7 @@ var hasOperatorScenarios = []expressionScenario{ { skipDoc: true, document: `a: hello`, - expression: `has(.b) as $c`, + expression: `has(.b) as $c | .`, expected: []string{ "D0, P[], (doc)::a: hello\n", }, diff --git a/pkg/yqlib/operator_subtract_test.go b/pkg/yqlib/operator_subtract_test.go index aaaa91f6..e5134b06 100644 --- a/pkg/yqlib/operator_subtract_test.go +++ b/pkg/yqlib/operator_subtract_test.go @@ -8,7 +8,7 @@ var subtractOperatorScenarios = []expressionScenario{ { skipDoc: true, document: `{}`, - expression: "(.a - .b) as $x", + expression: "(.a - .b) as $x | .", expected: []string{ "D0, P[], (doc)::{}\n", }, diff --git a/pkg/yqlib/operator_traverse_path_test.go b/pkg/yqlib/operator_traverse_path_test.go index 405a523e..8d3e94ad 100644 --- a/pkg/yqlib/operator_traverse_path_test.go +++ b/pkg/yqlib/operator_traverse_path_test.go @@ -151,7 +151,7 @@ var traversePathOperatorScenarios = []expressionScenario{ { skipDoc: true, document: `c: dog`, - expression: `.[.a.b] as $x`, + expression: `.[.a.b] as $x | .`, expected: []string{ "D0, P[], (doc)::c: dog\n", }, diff --git a/pkg/yqlib/operator_union_test.go b/pkg/yqlib/operator_union_test.go index ce12f19a..4b98ac06 100644 --- a/pkg/yqlib/operator_union_test.go +++ b/pkg/yqlib/operator_union_test.go @@ -8,7 +8,7 @@ var unionOperatorScenarios = []expressionScenario{ { skipDoc: true, document: "{}", - expression: `(.a, .b.c) as $x`, + expression: `(.a, .b.c) as $x | .`, expected: []string{ "D0, P[], (doc)::{}\n", }, diff --git a/pkg/yqlib/operator_variables.go b/pkg/yqlib/operator_variables.go index aec60e28..d9baded9 100644 --- a/pkg/yqlib/operator_variables.go +++ b/pkg/yqlib/operator_variables.go @@ -28,6 +28,17 @@ func useWithPipe(d *dataTreeNavigator, context Context, originalExp *ExpressionN func variableLoop(d *dataTreeNavigator, context Context, originalExp *ExpressionNode) (Context, error) { log.Debug("variable loop!") results := list.New() + var evaluateAllTogether = true + for matchEl := context.MatchingNodes.Front(); matchEl != nil; matchEl = matchEl.Next() { + evaluateAllTogether = evaluateAllTogether && matchEl.Value.(*CandidateNode).EvaluateTogether + if !evaluateAllTogether { + break + } + } + if evaluateAllTogether { + return variableLoopSingleChild(d, context, originalExp) + } + for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { result, err := variableLoopSingleChild(d, context.SingleChildContext(el.Value.(*CandidateNode)), originalExp) if err != nil { @@ -56,17 +67,17 @@ func variableLoopSingleChild(d *dataTreeNavigator, context Context, originalExp // now we loop over lhs, set variable to each result and calculate originalExp.Rhs for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() { + log.Debug("PROCESSING VARIABLE: ", NodeToString(el.Value.(*CandidateNode))) var variableValue = list.New() if prefs.IsReference { variableValue.PushBack(el.Value) } else { - copy, err := el.Value.(*CandidateNode).Copy() + candidateCopy, err := el.Value.(*CandidateNode).Copy() if err != nil { return Context{}, err } - variableValue.PushBack(copy) + variableValue.PushBack(candidateCopy) } - log.Debug("PROCESSING VARIABLE: ", NodeToString(el.Value.(*CandidateNode))) newContext := context.ChildContext(context.MatchingNodes) newContext.SetVariable(variableName, variableValue)