mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 13:48: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).
|
||||
|
||||
To sort by descending order, pipe the results through the `reverse` operator after sorting.
|
||||
|
||||
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).
|
||||
|
||||
To sort by descending order, pipe the results through the `reverse` operator after sorting.
|
||||
|
||||
Note that at this stage, `yq` only sorts scalar fields.
|
||||
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
@ -28,6 +31,26 @@ will output
|
||||
- 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
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
|
@ -416,6 +416,7 @@ func initLexer() (*lex.Lexer, error) {
|
||||
|
||||
lexer.Add([]byte(`sort`), opToken(sortOpType))
|
||||
lexer.Add([]byte(`sort_by`), opToken(sortByOpType))
|
||||
lexer.Add([]byte(`reverse`), opToken(reverseOpType))
|
||||
|
||||
lexer.Add([]byte(`any`), opToken(anyOpType))
|
||||
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 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 sortKeysOpType = &operationType{Type: "SORT_KEYS", NumArgs: 1, Precedence: 50, Handler: sortKeysOperator}
|
||||
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",
|
||||
},
|
||||
},
|
||||
{
|
||||
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",
|
||||
document: "cool: [{a: banana},{a: cat},{a: apple}]",
|
||||
|
Loading…
Reference in New Issue
Block a user