mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-23 22:25:42 +00:00
Added comparison ops (>,>=...)
This commit is contained in:
parent
897604142f
commit
fb148c305a
133
pkg/yqlib/compare_operators.go
Normal file
133
pkg/yqlib/compare_operators.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type compareTypePref struct {
|
||||||
|
OrEqual bool
|
||||||
|
Greater bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
log.Debugf("-- compareOperator")
|
||||||
|
prefs := expressionNode.Operation.Preferences.(compareTypePref)
|
||||||
|
return crossFunction(d, context.ReadOnlyClone(), expressionNode, compare(prefs), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compare(prefs compareTypePref) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
|
return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
|
log.Debugf("-- compare cross function")
|
||||||
|
if lhs == nil && rhs == nil {
|
||||||
|
owner := &CandidateNode{}
|
||||||
|
return createBooleanCandidate(owner, prefs.OrEqual), nil
|
||||||
|
} else if lhs == nil {
|
||||||
|
log.Debugf("lhs nil, but rhs is not")
|
||||||
|
return createBooleanCandidate(rhs, false), nil
|
||||||
|
} else if rhs == nil {
|
||||||
|
log.Debugf("rhs nil, but rhs is not")
|
||||||
|
return createBooleanCandidate(lhs, false), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs.Node = unwrapDoc(lhs.Node)
|
||||||
|
rhs.Node = unwrapDoc(rhs.Node)
|
||||||
|
|
||||||
|
switch lhs.Node.Kind {
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return nil, fmt.Errorf("maps not yet supported for comparison")
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
return nil, fmt.Errorf("arrays not yet supported for comparison")
|
||||||
|
default:
|
||||||
|
if rhs.Node.Kind != yaml.ScalarNode {
|
||||||
|
return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Node.Tag, rhs.Path, lhs.Node.Tag)
|
||||||
|
}
|
||||||
|
target := lhs.CreateReplacement(&yaml.Node{})
|
||||||
|
boolV, err := compareScalars(context, prefs, lhs.Node, rhs.Node)
|
||||||
|
|
||||||
|
return createBooleanCandidate(target, boolV), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareDateTime(layout string, prefs compareTypePref, lhs *yaml.Node, rhs *yaml.Node) (bool, error) {
|
||||||
|
lhsTime, err := time.Parse(layout, lhs.Value)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rhsTime, err := time.Parse(layout, rhs.Value)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefs.OrEqual && lhsTime.Equal(rhsTime) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if prefs.Greater {
|
||||||
|
return lhsTime.After(rhsTime), nil
|
||||||
|
}
|
||||||
|
return lhsTime.Before(rhsTime), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareScalars(context Context, prefs compareTypePref, lhs *yaml.Node, rhs *yaml.Node) (bool, error) {
|
||||||
|
lhsTag := guessTagFromCustomType(lhs)
|
||||||
|
rhsTag := guessTagFromCustomType(rhs)
|
||||||
|
|
||||||
|
isDateTime := lhs.Tag == "!!timestamp"
|
||||||
|
// if the lhs is a string, it might be a timestamp in a custom format.
|
||||||
|
if lhsTag == "!!str" && context.GetDateTimeLayout() != time.RFC3339 {
|
||||||
|
_, err := time.Parse(context.GetDateTimeLayout(), lhs.Value)
|
||||||
|
isDateTime = err == nil
|
||||||
|
}
|
||||||
|
if isDateTime {
|
||||||
|
return compareDateTime(context.GetDateTimeLayout(), prefs, lhs, rhs)
|
||||||
|
} else if lhsTag == "!!int" && rhsTag == "!!int" {
|
||||||
|
_, lhsNum, err := parseInt(lhs.Value)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, rhsNum, err := parseInt(rhs.Value)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefs.OrEqual && lhsNum == rhsNum {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if prefs.Greater {
|
||||||
|
return lhsNum > rhsNum, nil
|
||||||
|
}
|
||||||
|
return lhsNum < rhsNum, nil
|
||||||
|
} else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") {
|
||||||
|
lhsNum, err := strconv.ParseFloat(lhs.Value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
rhsNum, err := strconv.ParseFloat(rhs.Value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if prefs.OrEqual && lhsNum == rhsNum {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if prefs.Greater {
|
||||||
|
return lhsNum > rhsNum, nil
|
||||||
|
}
|
||||||
|
return lhsNum < rhsNum, nil
|
||||||
|
} else if lhsTag == "!!str" && rhsTag == "!!str" {
|
||||||
|
if prefs.OrEqual && lhs.Value == rhs.Value {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if prefs.Greater {
|
||||||
|
return lhs.Value > rhs.Value, nil
|
||||||
|
}
|
||||||
|
return lhs.Value < rhs.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, fmt.Errorf("%v not yet supported for comparison", lhs.Tag)
|
||||||
|
}
|
371
pkg/yqlib/compare_operators_test.go
Normal file
371
pkg/yqlib/compare_operators_test.go
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var compareOperatorScenarios = []expressionScenario{
|
||||||
|
// ints, not equal
|
||||||
|
{
|
||||||
|
description: "Compare numbers (>)",
|
||||||
|
document: "a: 5\nb: 4",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5\nb: 4",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Compare integers (>=)",
|
||||||
|
document: "a: 5\nb: 4",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5\nb: 4",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// ints, equal
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Compare equal numbers (>)",
|
||||||
|
document: "a: 5\nb: 5",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5\nb: 5",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Compare equal numbers (>=)",
|
||||||
|
document: "a: 5\nb: 5",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5\nb: 5",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// floats, not equal
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.2\nb: 4.1",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.2\nb: 4.1",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.2\nb: 4.1",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.5\nb: 4.1",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// floats, equal
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.5\nb: 5.5",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.5\nb: 5.5",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.1\nb: 5.1",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 5.1\nb: 5.1",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// strings, not equal
|
||||||
|
{
|
||||||
|
description: "Compare strings",
|
||||||
|
subdescription: "Compares strings by their bytecode.",
|
||||||
|
document: "a: zoo\nb: apple",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: zoo\nb: apple",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: zoo\nb: apple",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: zoo\nb: apple",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// strings, equal
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: cat\nb: cat",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: cat\nb: cat",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: cat\nb: cat",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: cat\nb: cat",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// datetime, not equal
|
||||||
|
{
|
||||||
|
description: "Compare date times",
|
||||||
|
subdescription: "You can compare date times. Assumes RFC3339 date time format, see [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.",
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// datetime, equal
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// both null
|
||||||
|
{
|
||||||
|
description: "Both sides are null: > is false",
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Both sides are null: >= is true",
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// one null
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "One side is null: > is false",
|
||||||
|
document: `a: 5`,
|
||||||
|
expression: ".a > .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: 5`,
|
||||||
|
expression: ".a < .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "One side is null: >= is false",
|
||||||
|
document: `a: 5`,
|
||||||
|
expression: ".a >= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: 5`,
|
||||||
|
expression: ".a <= .b",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: 5`,
|
||||||
|
expression: ".b <= .a",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: 5`,
|
||||||
|
expression: ".b < .a",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range compareOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentOperatorScenarios(t, "compare", compareOperatorScenarios)
|
||||||
|
}
|
@ -10,6 +10,12 @@ The `or` and `and` operators take two parameters and return a boolean result.
|
|||||||
|
|
||||||
These are most commonly used with the `select` operator to filter particular nodes.
|
These are most commonly used with the `select` operator to filter particular nodes.
|
||||||
|
|
||||||
|
## Related Operators
|
||||||
|
|
||||||
|
- equals / not equals (`==`, `!=`) operators (here)[https://mikefarah.gitbook.io/yq/operators/equals]
|
||||||
|
- comparison (`>=`, `<` etc) operators (here)[https://mikefarah.gitbook.io/yq/operators/compare]
|
||||||
|
- select operator (here)[https://mikefarah.gitbook.io/yq/operators/select]
|
||||||
|
|
||||||
{% hint style="warning" %}
|
{% hint style="warning" %}
|
||||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||||
|
|
||||||
|
106
pkg/yqlib/doc/operators/compare.md
Normal file
106
pkg/yqlib/doc/operators/compare.md
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
# Compare Operators
|
||||||
|
|
||||||
|
Comparison operators (`>`, `>=`, `<`, `<=`) can be used for comparing scalar values of the same time.
|
||||||
|
|
||||||
|
The following types are currently supported:
|
||||||
|
|
||||||
|
- numbers
|
||||||
|
- strings
|
||||||
|
- datetimes
|
||||||
|
|
||||||
|
## Related Operators
|
||||||
|
|
||||||
|
- equals / not equals (`==`, `!=`) operators (here)[https://mikefarah.gitbook.io/yq/operators/equals]
|
||||||
|
- 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]
|
||||||
|
|
||||||
|
{% hint style="warning" %}
|
||||||
|
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||||
|
|
||||||
|
`yq e <exp> <file>`
|
||||||
|
{% endhint %}
|
||||||
|
|
||||||
|
## Compare numbers (>)
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: 5
|
||||||
|
b: 4
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.a > .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compare equal numbers (>=)
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: 5
|
||||||
|
b: 5
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.a >= .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compare strings
|
||||||
|
Compares strings by their bytecode.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: zoo
|
||||||
|
b: apple
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.a > .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compare date times
|
||||||
|
You can compare date times. Assumes RFC3339 date time format, see [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: 2021-01-01T03:10:00Z
|
||||||
|
b: 2020-01-01T03:10:00Z
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq '.a > .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Both sides are null: > is false
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq --null-input '.a > .b'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Both sides are null: >= is true
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq --null-input '.a >= .b'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
@ -14,6 +14,13 @@ select(.a == .b)
|
|||||||
|
|
||||||
The not equals `!=` operator returns `false` if the LHS is equal to the RHS.
|
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]
|
||||||
|
|
||||||
|
|
||||||
{% hint style="warning" %}
|
{% hint style="warning" %}
|
||||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||||
|
|
||||||
|
@ -9,3 +9,9 @@ The `or` and `and` operators take two parameters and return a boolean result.
|
|||||||
`any_c(condition)` and `all_c(condition)` are like `any` and `all` but they take a condition expression that is used against each element to determine if it's `true`. Note: in `jq` you can simply pass a condition to `any` or `all` and it simply works - `yq` isn't that clever..yet
|
`any_c(condition)` and `all_c(condition)` are like `any` and `all` but they take a condition expression that is used against each element to determine if it's `true`. Note: in `jq` you can simply pass a condition to `any` or `all` and it simply works - `yq` isn't that clever..yet
|
||||||
|
|
||||||
These are most commonly used with the `select` operator to filter particular nodes.
|
These are most commonly used with the `select` operator to filter particular nodes.
|
||||||
|
|
||||||
|
## Related Operators
|
||||||
|
|
||||||
|
- equals / not equals (`==`, `!=`) operators (here)[https://mikefarah.gitbook.io/yq/operators/equals]
|
||||||
|
- comparison (`>=`, `<` etc) operators (here)[https://mikefarah.gitbook.io/yq/operators/compare]
|
||||||
|
- select operator (here)[https://mikefarah.gitbook.io/yq/operators/select]
|
||||||
|
15
pkg/yqlib/doc/operators/headers/compare.md
Normal file
15
pkg/yqlib/doc/operators/headers/compare.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Compare Operators
|
||||||
|
|
||||||
|
Comparison operators (`>`, `>=`, `<`, `<=`) can be used for comparing scalar values of the same time.
|
||||||
|
|
||||||
|
The following types are currently supported:
|
||||||
|
|
||||||
|
- numbers
|
||||||
|
- strings
|
||||||
|
- datetimes
|
||||||
|
|
||||||
|
## Related Operators
|
||||||
|
|
||||||
|
- equals / not equals (`==`, `!=`) operators (here)[https://mikefarah.gitbook.io/yq/operators/equals]
|
||||||
|
- 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]
|
@ -13,3 +13,10 @@ select(.a == .b)
|
|||||||
```
|
```
|
||||||
|
|
||||||
The not equals `!=` operator returns `false` if the LHS is equal to the RHS.
|
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]
|
||||||
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
# Select
|
# Select
|
||||||
|
|
||||||
Select is used to filter arrays and maps by a boolean expression.
|
Select is used to filter arrays and maps by a boolean expression.
|
||||||
|
|
||||||
|
## Related Operators
|
||||||
|
|
||||||
|
- equals / not equals (`==`, `!=`) operators (here)[https://mikefarah.gitbook.io/yq/operators/equals]
|
||||||
|
- 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]
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
Select is used to filter arrays and maps by a boolean expression.
|
Select is used to filter arrays and maps by a boolean expression.
|
||||||
|
|
||||||
|
## Related Operators
|
||||||
|
|
||||||
|
- equals / not equals (`==`, `!=`) operators (here)[https://mikefarah.gitbook.io/yq/operators/equals]
|
||||||
|
- 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]
|
||||||
|
|
||||||
{% hint style="warning" %}
|
{% hint style="warning" %}
|
||||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||||
|
|
||||||
|
@ -509,6 +509,13 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
|
|
||||||
lexer.Add([]byte(`\s*==\s*`), opToken(equalsOpType))
|
lexer.Add([]byte(`\s*==\s*`), opToken(equalsOpType))
|
||||||
lexer.Add([]byte(`\s*!=\s*`), opToken(notEqualsOpType))
|
lexer.Add([]byte(`\s*!=\s*`), opToken(notEqualsOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\s*>=\s*`), opTokenWithPrefs(compareOpType, nil, compareTypePref{OrEqual: true, Greater: true}))
|
||||||
|
lexer.Add([]byte(`\s*>\s*`), opTokenWithPrefs(compareOpType, nil, compareTypePref{OrEqual: false, Greater: true}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\s*<=\s*`), opTokenWithPrefs(compareOpType, nil, compareTypePref{OrEqual: true, Greater: false}))
|
||||||
|
lexer.Add([]byte(`\s*<\s*`), opTokenWithPrefs(compareOpType, nil, compareTypePref{OrEqual: false, Greater: false}))
|
||||||
|
|
||||||
lexer.Add([]byte(`\s*=\s*`), assignOpToken(false))
|
lexer.Add([]byte(`\s*=\s*`), assignOpToken(false))
|
||||||
|
|
||||||
lexer.Add([]byte(`del`), opToken(deleteChildOpType))
|
lexer.Add([]byte(`del`), opToken(deleteChildOpType))
|
||||||
|
@ -72,7 +72,9 @@ var subtractOpType = &operationType{Type: "SUBTRACT", NumArgs: 2, Precedence: 42
|
|||||||
var alternativeOpType = &operationType{Type: "ALTERNATIVE", NumArgs: 2, Precedence: 42, Handler: alternativeOperator}
|
var alternativeOpType = &operationType{Type: "ALTERNATIVE", NumArgs: 2, Precedence: 42, Handler: alternativeOperator}
|
||||||
|
|
||||||
var equalsOpType = &operationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: equalsOperator}
|
var equalsOpType = &operationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: equalsOperator}
|
||||||
var notEqualsOpType = &operationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: notEqualsOperator}
|
var notEqualsOpType = &operationType{Type: "NOT_EQUALS", NumArgs: 2, Precedence: 40, Handler: notEqualsOperator}
|
||||||
|
|
||||||
|
var compareOpType = &operationType{Type: "COMPARE", NumArgs: 2, Precedence: 40, Handler: compareOperator}
|
||||||
|
|
||||||
//createmap needs to be above union, as we use union to build the components of the objects
|
//createmap needs to be above union, as we use union to build the components of the objects
|
||||||
var createMapOpType = &operationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 15, Handler: createMapOperator}
|
var createMapOpType = &operationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 15, Handler: createMapOperator}
|
||||||
|
Loading…
Reference in New Issue
Block a user