mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-13 22:38:04 +00:00
Added keys operator
This commit is contained in:
parent
62acee54c3
commit
0707525b29
35
pkg/yqlib/doc/Keys.md
Normal file
35
pkg/yqlib/doc/Keys.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Keys
|
||||
|
||||
Use the `keys` operator to return map keys or array indices.
|
||||
## Map keys
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
dog: woof
|
||||
cat: meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'keys' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
- dog
|
||||
- cat
|
||||
```
|
||||
|
||||
## Array keys
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- apple
|
||||
- banana
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'keys' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
- 0
|
||||
- 1
|
||||
```
|
||||
|
3
pkg/yqlib/doc/headers/Keys.md
Normal file
3
pkg/yqlib/doc/headers/Keys.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Keys
|
||||
|
||||
Use the `keys` operator to return map keys or array indices.
|
@ -245,6 +245,7 @@ func initLexer() (*lex.Lexer, error) {
|
||||
|
||||
lexer.Add([]byte(`join`), opToken(joinStringOpType))
|
||||
lexer.Add([]byte(`split`), opToken(splitStringOpType))
|
||||
lexer.Add([]byte(`keys`), opToken(keysOpType))
|
||||
|
||||
lexer.Add([]byte(`style`), opAssignableToken(getStyleOpType, assignStyleOpType))
|
||||
|
||||
|
@ -67,6 +67,8 @@ var sortKeysOpType = &operationType{Type: "SORT_KEYS", NumArgs: 1, Precedence: 5
|
||||
var joinStringOpType = &operationType{Type: "JOIN", NumArgs: 1, Precedence: 50, Handler: joinStringOperator}
|
||||
var splitStringOpType = &operationType{Type: "SPLIT", NumArgs: 1, Precedence: 50, Handler: splitStringOperator}
|
||||
|
||||
var keysOpType = &operationType{Type: "KEYS", NumArgs: 0, Precedence: 50, Handler: keysOperator}
|
||||
|
||||
var collectObjectOpType = &operationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: collectObjectOperator}
|
||||
var traversePathOpType = &operationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 50, Handler: traversePathOperator}
|
||||
var traverseArrayOpType = &operationType{Type: "TRAVERSE_ARRAY", NumArgs: 1, Precedence: 50, Handler: traverseArrayOperator}
|
||||
|
54
pkg/yqlib/operator_keys.go
Normal file
54
pkg/yqlib/operator_keys.go
Normal file
@ -0,0 +1,54 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func keysOperator(d *dataTreeNavigator, matchMap *list.List, expressionNode *ExpressionNode) (*list.List, error) {
|
||||
log.Debugf("-- keysOperator")
|
||||
|
||||
var results = list.New()
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
node := unwrapDoc(candidate.Node)
|
||||
var targetNode *yaml.Node
|
||||
if node.Kind == yaml.MappingNode {
|
||||
targetNode = getMapKeys(node)
|
||||
} else if node.Kind == yaml.SequenceNode {
|
||||
targetNode = getIndicies(node)
|
||||
} else {
|
||||
return nil, fmt.Errorf("Cannot get keys of %v, keys only works for maps and arrays", node.Tag)
|
||||
}
|
||||
|
||||
result := candidate.CreateChild(nil, targetNode)
|
||||
results.PushBack(result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func getMapKeys(node *yaml.Node) *yaml.Node {
|
||||
contents := make([]*yaml.Node, 0)
|
||||
for index := 0; index < len(node.Content); index = index + 2 {
|
||||
contents = append(contents, node.Content[index])
|
||||
}
|
||||
return &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Content: contents}
|
||||
}
|
||||
|
||||
func getIndicies(node *yaml.Node) *yaml.Node {
|
||||
var contents = make([]*yaml.Node, len(node.Content))
|
||||
|
||||
for index := range node.Content {
|
||||
contents[index] = &yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Tag: "!!int",
|
||||
Value: fmt.Sprintf("%v", index),
|
||||
}
|
||||
}
|
||||
|
||||
return &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Content: contents}
|
||||
}
|
47
pkg/yqlib/operator_keys_test.go
Normal file
47
pkg/yqlib/operator_keys_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var keysOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Map keys",
|
||||
document: `{dog: woof, cat: meow}`,
|
||||
expression: `keys`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::- dog\n- cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{}`,
|
||||
expression: `keys`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::[]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Array keys",
|
||||
document: `[apple, banana]`,
|
||||
expression: `keys`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::- 0\n- 1\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `[]`,
|
||||
expression: `keys`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::[]\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestKeysOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range keysOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentScenarios(t, "Keys", keysOperatorScenarios)
|
||||
}
|
Loading…
Reference in New Issue
Block a user