From f03005f86d27e25da8745a3d6526ddaef4b2514b Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Fri, 20 Nov 2020 15:29:53 +1100 Subject: [PATCH] Fixed boolean ops --- pkg/yqlib/doc/Assign Operator.md | 4 +-- pkg/yqlib/operator_booleans.go | 55 +++++++++++++++++++---------- pkg/yqlib/operator_booleans_test.go | 4 +-- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/pkg/yqlib/doc/Assign Operator.md b/pkg/yqlib/doc/Assign Operator.md index 0dadc5bf..f5b893ba 100644 --- a/pkg/yqlib/doc/Assign Operator.md +++ b/pkg/yqlib/doc/Assign Operator.md @@ -6,7 +6,7 @@ Which will assign the LHS node values to the RHS node values. The RHS expression ### relative form: `|=` This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment. ## Examples -### Update parent to be the child value +### Update node to be the child value Given a sample.yml file of: ```yaml a: @@ -23,7 +23,7 @@ a: g: foof ``` -### Update to be the sibling value +### Update node to be the sibling value Given a sample.yml file of: ```yaml a: diff --git a/pkg/yqlib/operator_booleans.go b/pkg/yqlib/operator_booleans.go index 28e2fbac..ee7f6931 100644 --- a/pkg/yqlib/operator_booleans.go +++ b/pkg/yqlib/operator_booleans.go @@ -3,7 +3,7 @@ package yqlib import ( "container/list" - "gopkg.in/yaml.v3" + yaml "gopkg.in/yaml.v3" ) func isTruthy(c *CandidateNode) (bool, error) { @@ -25,9 +25,42 @@ func isTruthy(c *CandidateNode) (bool, error) { type boolOp func(bool, bool) bool +func performBoolOp(results *list.List, lhs *list.List, rhs *list.List, op boolOp) error { + for lhsChild := lhs.Front(); lhsChild != nil; lhsChild = lhsChild.Next() { + lhsCandidate := lhsChild.Value.(*CandidateNode) + lhsTrue, errDecoding := isTruthy(lhsCandidate) + if errDecoding != nil { + return errDecoding + } + + for rhsChild := rhs.Front(); rhsChild != nil; rhsChild = rhsChild.Next() { + rhsCandidate := rhsChild.Value.(*CandidateNode) + rhsTrue, errDecoding := isTruthy(rhsCandidate) + if errDecoding != nil { + return errDecoding + } + boolResult := createBooleanCandidate(lhsCandidate, op(lhsTrue, rhsTrue)) + results.PushBack(boolResult) + } + } + return nil +} + func booleanOp(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode, op boolOp) (*list.List, error) { var results = list.New() + if matchingNodes.Len() == 0 { + lhs, err := d.GetMatchingNodes(list.New(), pathNode.Lhs) + if err != nil { + return nil, err + } + rhs, err := d.GetMatchingNodes(list.New(), pathNode.Rhs) + if err != nil { + return nil, err + } + return results, performBoolOp(results, lhs, rhs, op) + } + for el := matchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) lhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Lhs) @@ -39,23 +72,9 @@ func booleanOp(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTre return nil, err } - for lhsChild := lhs.Front(); lhsChild != nil; lhsChild = lhsChild.Next() { - lhsCandidate := lhsChild.Value.(*CandidateNode) - lhsTrue, errDecoding := isTruthy(lhsCandidate) - if errDecoding != nil { - return nil, errDecoding - } - - for rhsChild := rhs.Front(); rhsChild != nil; rhsChild = rhsChild.Next() { - rhsCandidate := rhsChild.Value.(*CandidateNode) - rhsTrue, errDecoding := isTruthy(rhsCandidate) - if errDecoding != nil { - return nil, errDecoding - } - boolResult := createBooleanCandidate(lhsCandidate, op(lhsTrue, rhsTrue)) - - results.PushBack(boolResult) - } + err = performBoolOp(results, lhs, rhs, op) + if err != nil { + return nil, err } } diff --git a/pkg/yqlib/operator_booleans_test.go b/pkg/yqlib/operator_booleans_test.go index 6c9b1dea..12e65c51 100644 --- a/pkg/yqlib/operator_booleans_test.go +++ b/pkg/yqlib/operator_booleans_test.go @@ -24,8 +24,8 @@ var booleanOperatorScenarios = []expressionScenario{ description: "Matching nodes with select, equals and or", expression: `.[] | select(.a == "cat" or .b == "dog")`, expected: []string{ - "D0, P[], (!!map)::{a: bird, b: dog}\n", - "D0, P[], (!!map)::{a: cat, b: fly}\n", + "D0, P[0], (!!map)::{a: bird, b: dog}\n", + "D0, P[2], (!!map)::{a: cat, b: fly}\n", }, }, {