Upstream mikefarah/yq state of the touched files before 253c991996
This commit is contained in:
commit
b9be9a6184
3 files changed
+378
No files matched your search
@@ -0,0 +1,133 @@
|
|||||||
|
# Equals / Not Equals
|
||||||
|
|
||||||
|
This is a boolean operator that will return `true` if the LHS is equal to the RHS and `false` otherwise.
|
||||||
|
|
||||||
|
```
|
||||||
|
.a == .b
|
||||||
|
```
|
||||||
|
|
||||||
|
It is most often used with the select operator to find particular nodes:
|
||||||
|
|
||||||
|
```
|
||||||
|
select(.a == .b)
|
||||||
|
```
|
||||||
|
|
||||||
|
The not equals `!=` operator returns `false` if the LHS is equal to the RHS.
|
||||||
|
|
||||||
|
## Related Operators
|
||||||
|
|
||||||
|
- comparison (`>=`, `<` etc) operators [here](https://mikefarah.gitbook.io/yq/operators/compare)
|
||||||
|
- boolean operators (`and`, `or`, `any` etc) [here](https://mikefarah.gitbook.io/yq/operators/boolean-operators)
|
||||||
|
- select operator [here](https://mikefarah.gitbook.io/yq/operators/select)
|
||||||
|
|
||||||
|
|
||||||
|
## Match string
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- cat
|
||||||
|
- goat
|
||||||
|
- dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.[] | (. == "*at")' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Don't match string
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- cat
|
||||||
|
- goat
|
||||||
|
- dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.[] | (. != "*at")' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
false
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Match number
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- 5
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.[] | (. == 4)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
true
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Don't match number
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- 5
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.[] | (. != 4)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Match nulls
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq --null-input 'null == ~'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Non existent key doesn't equal a value
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq 'select(.b != "thing")' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Two non existent keys are equal
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq 'select(.b == .c)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
func equalsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
log.Debugf("equalsOperation")
|
||||||
|
return crossFunction(d, context, expressionNode, isEquals(false), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
|
return func(_ *dataTreeNavigator, _ Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
|
value := false
|
||||||
|
log.Debugf("isEquals cross function")
|
||||||
|
if lhs == nil && rhs == nil {
|
||||||
|
log.Debugf("both are nil")
|
||||||
|
owner := &CandidateNode{}
|
||||||
|
return createBooleanCandidate(owner, !flip), nil
|
||||||
|
} else if lhs == nil {
|
||||||
|
log.Debugf("lhs nil, but rhs is not")
|
||||||
|
value := rhs.Tag == "!!null"
|
||||||
|
if flip {
|
||||||
|
value = !value
|
||||||
|
}
|
||||||
|
return createBooleanCandidate(rhs, value), nil
|
||||||
|
} else if rhs == nil {
|
||||||
|
log.Debugf("lhs not nil, but rhs is")
|
||||||
|
value := lhs.Tag == "!!null"
|
||||||
|
if flip {
|
||||||
|
value = !value
|
||||||
|
}
|
||||||
|
return createBooleanCandidate(lhs, value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhs.Tag == "!!null" {
|
||||||
|
value = (rhs.Tag == "!!null")
|
||||||
|
} else if lhs.Kind == ScalarNode && rhs.Kind == ScalarNode {
|
||||||
|
value = matchKey(lhs.Value, rhs.Value)
|
||||||
|
}
|
||||||
|
log.Debugf("%v == %v ? %v", NodeToString(lhs), NodeToString(rhs), value)
|
||||||
|
if flip {
|
||||||
|
value = !value
|
||||||
|
}
|
||||||
|
return createBooleanCandidate(lhs, value), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func notEqualsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
log.Debugf("notEqualsOperator")
|
||||||
|
return crossFunction(d, context.ReadOnlyClone(), expressionNode, isEquals(true), true)
|
||||||
|
}
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var equalsOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
expression: ".a == .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expression: `(.k | length) == 0`,
|
||||||
|
skipDoc: true,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[k], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: cat`,
|
||||||
|
expression: ".a == .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: cat`,
|
||||||
|
expression: ".b == .a",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[b], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "cat",
|
||||||
|
document2: "dog",
|
||||||
|
expression: "select(fi==0) == select(fi==1)",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{}",
|
||||||
|
expression: "(.a == .b) as $x | .",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{}",
|
||||||
|
expression: ".a == .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{}",
|
||||||
|
expression: "(.a != .b) as $x | .",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{}",
|
||||||
|
expression: ".a != .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{a: {b: 10}}",
|
||||||
|
expression: "select(.c != null)",
|
||||||
|
expected: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{a: {b: 10}}",
|
||||||
|
expression: "select(.d == .c)",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{a: {b: 10}}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{a: {b: 10}}",
|
||||||
|
expression: "select(null == .c)",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{a: {b: 10}}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "{a: { b: {things: \"\"}, f: [1], g: [] }}",
|
||||||
|
expression: ".. | select(. == \"\")",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a b things], (!!str)::\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Match string",
|
||||||
|
document: `[cat,goat,dog]`,
|
||||||
|
expression: `.[] | (. == "*at")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[0], (!!bool)::true\n",
|
||||||
|
"D0, P[1], (!!bool)::true\n",
|
||||||
|
"D0, P[2], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Don't match string",
|
||||||
|
document: `[cat,goat,dog]`,
|
||||||
|
expression: `.[] | (. != "*at")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[0], (!!bool)::false\n",
|
||||||
|
"D0, P[1], (!!bool)::false\n",
|
||||||
|
"D0, P[2], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Match number",
|
||||||
|
document: `[3, 4, 5]`,
|
||||||
|
expression: `.[] | (. == 4)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[0], (!!bool)::false\n",
|
||||||
|
"D0, P[1], (!!bool)::true\n",
|
||||||
|
"D0, P[2], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Don't match number",
|
||||||
|
document: `[3, 4, 5]`,
|
||||||
|
expression: `.[] | (. != 4)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[0], (!!bool)::true\n",
|
||||||
|
"D0, P[1], (!!bool)::false\n",
|
||||||
|
"D0, P[2], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: { cat: {b: apple, c: whatever}, pat: {b: banana} }`,
|
||||||
|
expression: `.a | (.[].b == "apple")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a cat b], (!!bool)::true\n",
|
||||||
|
"D0, P[a pat b], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: ``,
|
||||||
|
expression: `null == null`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Match nulls",
|
||||||
|
document: ``,
|
||||||
|
expression: `null == ~`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Non existent key doesn't equal a value",
|
||||||
|
document: "a: frog",
|
||||||
|
expression: `select(.b != "thing")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::a: frog\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Two non existent keys are equal",
|
||||||
|
document: "a: frog",
|
||||||
|
expression: `select(.b == .c)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::a: frog\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEqualOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range equalsOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentOperatorScenarios(t, "equals", equalsOperatorScenarios)
|
||||||
|
}
|
||||||
Reference in new issue
Block a user