mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-14 07:08:06 +00:00
Added reverse op
This commit is contained in:
parent
2752544bc8
commit
8142e94349
3
pkg/yqlib/doc/operators/headers/reverse.md
Normal file
3
pkg/yqlib/doc/operators/headers/reverse.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Reverse
|
||||||
|
|
||||||
|
Reverses the order of the items in an array
|
@ -2,4 +2,7 @@
|
|||||||
|
|
||||||
Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield).
|
Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield).
|
||||||
|
|
||||||
|
To sort by descending order, pipe the results through the `reverse` operator after sorting.
|
||||||
|
|
||||||
Note that at this stage, `yq` only sorts scalar fields.
|
Note that at this stage, `yq` only sorts scalar fields.
|
||||||
|
|
||||||
|
48
pkg/yqlib/doc/operators/reverse.md
Normal file
48
pkg/yqlib/doc/operators/reverse.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Reverse
|
||||||
|
|
||||||
|
Reverses the order of the items in an array
|
||||||
|
|
||||||
|
{% hint style="warning" %}
|
||||||
|
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||||
|
|
||||||
|
`yq e <exp> <file>`
|
||||||
|
{% endhint %}
|
||||||
|
|
||||||
|
## Reverse
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq 'reverse' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- 3
|
||||||
|
- 2
|
||||||
|
- 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sort descending by string field
|
||||||
|
Use sort with reverse to sort in descending order.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- a: banana
|
||||||
|
- a: cat
|
||||||
|
- a: apple
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq 'sort_by(.a) | reverse' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- a: cat
|
||||||
|
- a: banana
|
||||||
|
- a: apple
|
||||||
|
```
|
||||||
|
|
@ -2,8 +2,11 @@
|
|||||||
|
|
||||||
Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield).
|
Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield).
|
||||||
|
|
||||||
|
To sort by descending order, pipe the results through the `reverse` operator after sorting.
|
||||||
|
|
||||||
Note that at this stage, `yq` only sorts scalar fields.
|
Note that at this stage, `yq` only sorts scalar fields.
|
||||||
|
|
||||||
|
|
||||||
{% 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. 
|
||||||
|
|
||||||
@ -28,6 +31,26 @@ will output
|
|||||||
- a: cat
|
- a: cat
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Sort descending by string field
|
||||||
|
Use sort with reverse to sort in descending order.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- a: banana
|
||||||
|
- a: cat
|
||||||
|
- a: apple
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq 'sort_by(.a) | reverse' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- a: cat
|
||||||
|
- a: banana
|
||||||
|
- a: apple
|
||||||
|
```
|
||||||
|
|
||||||
## Sort array in place
|
## Sort array in place
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -416,6 +416,7 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
|
|
||||||
lexer.Add([]byte(`sort`), opToken(sortOpType))
|
lexer.Add([]byte(`sort`), opToken(sortOpType))
|
||||||
lexer.Add([]byte(`sort_by`), opToken(sortByOpType))
|
lexer.Add([]byte(`sort_by`), opToken(sortByOpType))
|
||||||
|
lexer.Add([]byte(`reverse`), opToken(reverseOpType))
|
||||||
|
|
||||||
lexer.Add([]byte(`any`), opToken(anyOpType))
|
lexer.Add([]byte(`any`), opToken(anyOpType))
|
||||||
lexer.Add([]byte(`any_c`), opToken(anyConditionOpType))
|
lexer.Add([]byte(`any_c`), opToken(anyConditionOpType))
|
||||||
|
@ -123,6 +123,7 @@ var getPathOpType = &operationType{Type: "GET_PATH", NumArgs: 0, Precedence: 50,
|
|||||||
|
|
||||||
var explodeOpType = &operationType{Type: "EXPLODE", NumArgs: 1, Precedence: 50, Handler: explodeOperator}
|
var explodeOpType = &operationType{Type: "EXPLODE", NumArgs: 1, Precedence: 50, Handler: explodeOperator}
|
||||||
var sortByOpType = &operationType{Type: "SORT_BY", NumArgs: 1, Precedence: 50, Handler: sortByOperator}
|
var sortByOpType = &operationType{Type: "SORT_BY", NumArgs: 1, Precedence: 50, Handler: sortByOperator}
|
||||||
|
var reverseOpType = &operationType{Type: "REVERSE", NumArgs: 0, Precedence: 50, Handler: reverseOperator}
|
||||||
var sortOpType = &operationType{Type: "SORT", NumArgs: 0, Precedence: 50, Handler: sortOperator}
|
var sortOpType = &operationType{Type: "SORT", NumArgs: 0, Precedence: 50, Handler: sortOperator}
|
||||||
var sortKeysOpType = &operationType{Type: "SORT_KEYS", NumArgs: 1, Precedence: 50, Handler: sortKeysOperator}
|
var sortKeysOpType = &operationType{Type: "SORT_KEYS", NumArgs: 1, Precedence: 50, Handler: sortKeysOperator}
|
||||||
var joinStringOpType = &operationType{Type: "JOIN", NumArgs: 1, Precedence: 50, Handler: joinStringOperator}
|
var joinStringOpType = &operationType{Type: "JOIN", NumArgs: 1, Precedence: 50, Handler: joinStringOperator}
|
||||||
|
34
pkg/yqlib/operator_reverse.go
Normal file
34
pkg/yqlib/operator_reverse.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func reverseOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
results := list.New()
|
||||||
|
|
||||||
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
|
||||||
|
candidateNode := unwrapDoc(candidate.Node)
|
||||||
|
|
||||||
|
if candidateNode.Kind != yaml.SequenceNode {
|
||||||
|
return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.GetNiceTag())
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseList := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Style: candidateNode.Style}
|
||||||
|
reverseList.Content = make([]*yaml.Node, len(candidateNode.Content))
|
||||||
|
|
||||||
|
for i, originalNode := range candidateNode.Content {
|
||||||
|
reverseList.Content[len(candidateNode.Content)-i-1] = originalNode
|
||||||
|
}
|
||||||
|
results.PushBack(candidate.CreateReplacement(reverseList))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.ChildContext(results), nil
|
||||||
|
|
||||||
|
}
|
54
pkg/yqlib/operator_reverse_test.go
Normal file
54
pkg/yqlib/operator_reverse_test.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var reverseOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Reverse",
|
||||||
|
document: "[1, 2, 3]",
|
||||||
|
expression: `reverse`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[3, 2, 1]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "[]",
|
||||||
|
expression: `reverse`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "[1]",
|
||||||
|
expression: `reverse`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[1]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "[1,2]",
|
||||||
|
expression: `reverse`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[2, 1]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Sort descending by string field",
|
||||||
|
subdescription: "Use sort with reverse to sort in descending order.",
|
||||||
|
document: "[{a: banana},{a: cat},{a: apple}]",
|
||||||
|
expression: `sort_by(.a) | reverse`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[{a: cat}, {a: banana}, {a: apple}]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReverseOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range reverseOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentOperatorScenarios(t, "reverse", reverseOperatorScenarios)
|
||||||
|
}
|
@ -11,6 +11,15 @@ var sortByOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::[{a: apple}, {a: banana}, {a: cat}]\n",
|
"D0, P[], (!!seq)::[{a: apple}, {a: banana}, {a: cat}]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Sort descending by string field",
|
||||||
|
subdescription: "Use sort with reverse to sort in descending order.",
|
||||||
|
document: "[{a: banana},{a: cat},{a: apple}]",
|
||||||
|
expression: `sort_by(.a) | reverse`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[{a: cat}, {a: banana}, {a: apple}]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Sort array in place",
|
description: "Sort array in place",
|
||||||
document: "cool: [{a: banana},{a: cat},{a: apple}]",
|
document: "cool: [{a: banana},{a: cat},{a: apple}]",
|
||||||
|
Loading…
Reference in New Issue
Block a user