Upstream mikefarah/yq state of the touched files before 253c991996

This commit is contained in:
upstream committed 2026-09-03 13:29:22 +02:00
commit b9be9a6184
3 files changed
+378

No files matched your search

+133
View File
@@ -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
```
+48
View File
@@ -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)
}
+197
View File
@@ -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)
}