mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Added map, map_values
This commit is contained in:
parent
54b355bffb
commit
14f8f92b76
3
pkg/yqlib/doc/headers/map.md
Normal file
3
pkg/yqlib/doc/headers/map.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Map
|
||||
|
||||
Maps values of an array. Use `map_values` to map values of an object.
|
40
pkg/yqlib/doc/map.md
Normal file
40
pkg/yqlib/doc/map.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Map
|
||||
|
||||
Maps values of an array. Use `map_values` to map values of an object.
|
||||
|
||||
## Map array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'map(. + 1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
|
||||
## Map object values
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 1
|
||||
b: 2
|
||||
c: 3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'map_values(. + 1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 2
|
||||
b: 3
|
||||
c: 4
|
||||
```
|
||||
|
@ -312,6 +312,9 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
||||
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
||||
|
||||
lexer.Add([]byte(`map`), opToken(mapOpType))
|
||||
lexer.Add([]byte(`map_values`), opToken(mapValuesOpType))
|
||||
|
||||
lexer.Add([]byte(`flatten\([0-9]+\)`), flattenWithDepth())
|
||||
lexer.Add([]byte(`flatten`), opTokenWithPrefs(flattenOpType, nil, flattenPreferences{depth: -1}))
|
||||
|
||||
|
@ -64,6 +64,8 @@ var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence:
|
||||
|
||||
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
||||
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
|
||||
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
||||
var mapValuesOpType = &operationType{Type: "MAP_VALUES", NumArgs: 1, Precedence: 50, Handler: mapValuesOperator}
|
||||
var encodeOpType = &operationType{Type: "ENCODE", NumArgs: 0, Precedence: 50, Handler: encodeOperator}
|
||||
var decodeOpType = &operationType{Type: "DECODE", NumArgs: 0, Precedence: 50, Handler: decodeOperator}
|
||||
|
||||
|
64
pkg/yqlib/operator_map.go
Normal file
64
pkg/yqlib/operator_map.go
Normal file
@ -0,0 +1,64 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
)
|
||||
|
||||
func mapValuesOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
|
||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
//run expression against entries
|
||||
// splat toEntries and pipe it into Rhs
|
||||
splatted, err := splat(d, context.SingleChildContext(candidate), traversePreferences{})
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
assignUpdateExp := &ExpressionNode{
|
||||
Operation: &Operation{OperationType: assignOpType, UpdateAssign: true},
|
||||
Rhs: expressionNode.Rhs,
|
||||
}
|
||||
_, err = assignUpdateOperator(d, splatted, assignUpdateExp)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return context, nil
|
||||
}
|
||||
|
||||
func mapOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
|
||||
var results = list.New()
|
||||
|
||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
//run expression against entries
|
||||
// splat toEntries and pipe it into Rhs
|
||||
splatted, err := splat(d, context.SingleChildContext(candidate), traversePreferences{})
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
result, err := d.GetMatchingNodes(splatted, expressionNode.Rhs)
|
||||
log.Debug("expressionNode.Rhs %v", expressionNode.Rhs.Operation.OperationType)
|
||||
log.Debug("result %v", result)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
selfExpression := &ExpressionNode{Operation: &Operation{OperationType: selfReferenceOpType}}
|
||||
collected, err := collectTogether(d, result, selfExpression)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
collected.Node.Style = unwrapDoc(candidate.Node).Style
|
||||
|
||||
results.PushBack(collected)
|
||||
|
||||
}
|
||||
|
||||
return context.ChildContext(results), nil
|
||||
}
|
51
pkg/yqlib/operator_map_test.go
Normal file
51
pkg/yqlib/operator_map_test.go
Normal file
@ -0,0 +1,51 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var mapOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `[1,2,3]`,
|
||||
document2: `[5,6,7]`,
|
||||
expression: `map(. + 1)`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::[2, 3, 4]\n",
|
||||
"D0, P[], (!!seq)::[6, 7, 8]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Map array",
|
||||
document: `[1,2,3]`,
|
||||
expression: `map(. + 1)`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::[2, 3, 4]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{a: 1, b: 2, c: 3}`,
|
||||
document2: `{x: 10, y: 20, z: 30}`,
|
||||
expression: `map_values(. + 1)`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: 2, b: 3, c: 4}\n",
|
||||
"D0, P[], (doc)::{x: 11, y: 21, z: 31}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Map object values",
|
||||
document: `{a: 1, b: 2, c: 3}`,
|
||||
expression: `map_values(. + 1)`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: 2, b: 3, c: 4}\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMapOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range mapOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentScenarios(t, "map", mapOperatorScenarios)
|
||||
}
|
Loading…
Reference in New Issue
Block a user