mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Fixed boolean op with empty context issue
This commit is contained in:
parent
25d0787011
commit
37f3e21970
@ -93,3 +93,31 @@ will output
|
|||||||
true
|
true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Non exisitant key doesn't equal a value
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'select(.b != "thing")' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Two non existant keys are equal
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'select(.b == .c)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
|
||||||
|
@ -27,20 +27,37 @@ type boolOp func(bool, bool) bool
|
|||||||
|
|
||||||
func performBoolOp(op boolOp) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
func performBoolOp(op boolOp) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
|
owner := lhs
|
||||||
|
|
||||||
|
if lhs == nil && rhs == nil {
|
||||||
|
owner = &CandidateNode{}
|
||||||
|
} else if lhs == nil {
|
||||||
|
owner = rhs
|
||||||
|
}
|
||||||
|
|
||||||
|
var errDecoding error
|
||||||
|
lhsTrue := false
|
||||||
|
if lhs != nil {
|
||||||
lhs.Node = unwrapDoc(lhs.Node)
|
lhs.Node = unwrapDoc(lhs.Node)
|
||||||
|
lhsTrue, errDecoding = isTruthy(lhs)
|
||||||
|
|
||||||
|
if errDecoding != nil {
|
||||||
|
return nil, errDecoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debugf("-- lhsTrue", lhsTrue)
|
||||||
|
|
||||||
|
rhsTrue := false
|
||||||
|
if rhs != nil {
|
||||||
rhs.Node = unwrapDoc(rhs.Node)
|
rhs.Node = unwrapDoc(rhs.Node)
|
||||||
|
rhsTrue, errDecoding = isTruthy(rhs)
|
||||||
lhsTrue, errDecoding := isTruthy(lhs)
|
|
||||||
if errDecoding != nil {
|
if errDecoding != nil {
|
||||||
return nil, errDecoding
|
return nil, errDecoding
|
||||||
}
|
}
|
||||||
|
|
||||||
rhsTrue, errDecoding := isTruthy(rhs)
|
|
||||||
if errDecoding != nil {
|
|
||||||
return nil, errDecoding
|
|
||||||
}
|
}
|
||||||
|
log.Debugf("-- rhsTrue", rhsTrue)
|
||||||
|
|
||||||
return createBooleanCandidate(lhs, op(lhsTrue, rhsTrue)), nil
|
return createBooleanCandidate(owner, op(lhsTrue, rhsTrue)), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,8 +65,9 @@ func orOperator(d *dataTreeNavigator, context Context, expressionNode *Expressio
|
|||||||
log.Debugf("-- orOp")
|
log.Debugf("-- orOp")
|
||||||
return crossFunction(d, context, expressionNode, performBoolOp(
|
return crossFunction(d, context, expressionNode, performBoolOp(
|
||||||
func(b1 bool, b2 bool) bool {
|
func(b1 bool, b2 bool) bool {
|
||||||
|
log.Debugf("-- peformingOrOp with %v and %v", b1, b2)
|
||||||
return b1 || b2
|
return b1 || b2
|
||||||
}), false)
|
}), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func andOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
func andOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
@ -57,7 +75,7 @@ func andOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
|
|||||||
return crossFunction(d, context, expressionNode, performBoolOp(
|
return crossFunction(d, context, expressionNode, performBoolOp(
|
||||||
func(b1 bool, b2 bool) bool {
|
func(b1 bool, b2 bool) bool {
|
||||||
return b1 && b2
|
return b1 && b2
|
||||||
}), false)
|
}), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func notOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
func notOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
@ -12,6 +12,22 @@ var booleanOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!bool)::true\n",
|
"D0, P[], (!!bool)::true\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "b: hi",
|
||||||
|
expression: `select(.a or .b)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::b: hi\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "b: hi",
|
||||||
|
expression: `select((.a and .b) | not)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::b: hi\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "AND example",
|
description: "AND example",
|
||||||
expression: `true and false`,
|
expression: `true and false`,
|
||||||
|
@ -4,13 +4,22 @@ import "gopkg.in/yaml.v3"
|
|||||||
|
|
||||||
func equalsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
func equalsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
log.Debugf("-- equalsOperation")
|
log.Debugf("-- equalsOperation")
|
||||||
return crossFunction(d, context, expressionNode, isEquals(false), false)
|
return crossFunction(d, context, expressionNode, isEquals(false), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
value := false
|
value := false
|
||||||
|
|
||||||
|
if lhs == nil && rhs == nil {
|
||||||
|
owner := &CandidateNode{}
|
||||||
|
return createBooleanCandidate(owner, !flip), nil
|
||||||
|
} else if lhs == nil {
|
||||||
|
return createBooleanCandidate(rhs, flip), nil
|
||||||
|
} else if rhs == nil {
|
||||||
|
return createBooleanCandidate(lhs, flip), nil
|
||||||
|
}
|
||||||
|
|
||||||
lhsNode := unwrapDoc(lhs.Node)
|
lhsNode := unwrapDoc(lhs.Node)
|
||||||
rhsNode := unwrapDoc(rhs.Node)
|
rhsNode := unwrapDoc(rhs.Node)
|
||||||
|
|
||||||
@ -29,5 +38,5 @@ func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *Candid
|
|||||||
|
|
||||||
func notEqualsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
func notEqualsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
log.Debugf("-- equalsOperation")
|
log.Debugf("-- equalsOperation")
|
||||||
return crossFunction(d, context, expressionNode, isEquals(true), false)
|
return crossFunction(d, context, expressionNode, isEquals(true), true)
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,22 @@ var equalsOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!bool)::true\n",
|
"D0, P[], (!!bool)::true\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Non exisitant key doesn't equal a value",
|
||||||
|
document: "a: frog",
|
||||||
|
expression: `select(.b != "thing")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: frog\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Two non existant keys are equal",
|
||||||
|
document: "a: frog",
|
||||||
|
expression: `select(.b == .c)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: frog\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEqualOperatorScenarios(t *testing.T) {
|
func TestEqualOperatorScenarios(t *testing.T) {
|
||||||
|
@ -14,6 +14,16 @@ var selectOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[1], (!!str)::goat\n",
|
"D0, P[1], (!!str)::goat\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: hello",
|
||||||
|
document2: "b: world",
|
||||||
|
expression: `select(.a == "hello" or .b == "world")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: hello\n",
|
||||||
|
"D0, P[], (doc)::b: world\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[{animal: cat, legs: {cool: true}}, {animal: fish}]`,
|
document: `[{animal: cat, legs: {cool: true}}, {animal: fish}]`,
|
||||||
|
Loading…
Reference in New Issue
Block a user