mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Array to map operator for #1415
This commit is contained in:
parent
c915113120
commit
bd5e5dc965
28
pkg/yqlib/doc/operators/array-to-map.md
Normal file
28
pkg/yqlib/doc/operators/array-to-map.md
Normal file
@ -0,0 +1,28 @@
|
||||
# Array to Map
|
||||
|
||||
Use this operator to convert an array to..a map. Skips over null values.
|
||||
|
||||
Behind the scenes, this is implemented using reduce:
|
||||
|
||||
```
|
||||
(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)
|
||||
```
|
||||
|
||||
## Simple example
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
cool:
|
||||
- null
|
||||
- null
|
||||
- hello
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.cool |= array_to_map' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cool:
|
||||
2: hello
|
||||
```
|
||||
|
9
pkg/yqlib/doc/operators/headers/array-to-map.md
Normal file
9
pkg/yqlib/doc/operators/headers/array-to-map.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Array to Map
|
||||
|
||||
Use this operator to convert an array to..a map. Skips over null values.
|
||||
|
||||
Behind the scenes, this is implemented using reduce:
|
||||
|
||||
```
|
||||
(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)
|
||||
```
|
@ -149,6 +149,23 @@ person:
|
||||
- pizza
|
||||
```
|
||||
|
||||
## Decode properties - array should be a map
|
||||
If you have a numeric map key in your property files, use array_to_map to convert them to maps.
|
||||
|
||||
Given a sample.properties file of:
|
||||
```properties
|
||||
things.10 = mike
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -p=props '.things |= array_to_map' sample.properties
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
things:
|
||||
10: mike
|
||||
```
|
||||
|
||||
## Roundtrip
|
||||
Given a sample.properties file of:
|
||||
```properties
|
||||
|
@ -55,6 +55,8 @@ var participleYqRules = []*participleYqRule{
|
||||
simpleOp("sortKeys", sortKeysOpType),
|
||||
simpleOp("sort_?keys", sortKeysOpType),
|
||||
|
||||
{"ArrayToMap", "array_?to_?map", expressionOpToken(`(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)`), 0},
|
||||
|
||||
{"YamlEncodeWithIndent", `to_?yaml\([0-9]+\)`, encodeParseIndent(YamlOutputFormat), 0},
|
||||
{"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLOutputFormat), 0},
|
||||
{"JSONEncodeWithIndent", `to_?json\([0-9]+\)`, encodeParseIndent(JSONOutputFormat), 0},
|
||||
@ -291,6 +293,14 @@ func opTokenWithPrefs(opType *operationType, assignOpType *operationType, prefer
|
||||
}
|
||||
}
|
||||
|
||||
func expressionOpToken(expression string) yqAction {
|
||||
return func(rawToken lexer.Token) (*token, error) {
|
||||
prefs := expressionOpPreferences{expression: expression}
|
||||
expressionOp := &Operation{OperationType: expressionOpType, Preferences: prefs}
|
||||
return &token{TokenType: operationToken, Operation: expressionOp}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func flattenWithDepth() yqAction {
|
||||
return func(rawToken lexer.Token) (*token, error) {
|
||||
value := rawToken.Value
|
||||
|
@ -80,6 +80,8 @@ var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Ha
|
||||
var lineOpType = &operationType{Type: "LINE", NumArgs: 0, Precedence: 50, Handler: lineOperator}
|
||||
var columnOpType = &operationType{Type: "LINE", NumArgs: 0, Precedence: 50, Handler: columnOperator}
|
||||
|
||||
var expressionOpType = &operationType{Type: "EXP", NumArgs: 0, Precedence: 50, Handler: expressionOperator}
|
||||
|
||||
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
|
||||
var sliceArrayOpType = &operationType{Type: "SLICE", NumArgs: 0, Precedence: 50, Handler: sliceArrayOperator}
|
||||
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
||||
|
23
pkg/yqlib/operator_array_to_map_test.go
Normal file
23
pkg/yqlib/operator_array_to_map_test.go
Normal file
@ -0,0 +1,23 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var arrayToMapScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Simple example",
|
||||
document: `cool: [null, null, hello]`,
|
||||
expression: `.cool |= array_to_map`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::cool:\n 2: hello\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestArrayToMapScenarios(t *testing.T) {
|
||||
for _, tt := range arrayToMapScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentOperatorScenarios(t, "array-to-map", arrayToMapScenarios)
|
||||
}
|
16
pkg/yqlib/operator_expression.go
Normal file
16
pkg/yqlib/operator_expression.go
Normal file
@ -0,0 +1,16 @@
|
||||
package yqlib
|
||||
|
||||
type expressionOpPreferences struct {
|
||||
expression string
|
||||
}
|
||||
|
||||
func expressionOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
|
||||
prefs := expressionNode.Operation.Preferences.(expressionOpPreferences)
|
||||
expNode, err := ExpressionParser.ParseExpression(prefs.expression)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
return d.GetMatchingNodes(context, expNode)
|
||||
}
|
@ -147,6 +147,14 @@ var propertyScenarios = []formatScenario{
|
||||
expected: expectedDecodedYaml,
|
||||
scenarioType: "decode",
|
||||
},
|
||||
{
|
||||
description: "Decode properties - array should be a map",
|
||||
subdescription: "If you have a numeric map key in your property files, use array_to_map to convert them to maps.",
|
||||
input: `things.10 = mike`,
|
||||
expression: `.things |= array_to_map`,
|
||||
expected: "things:\n 10: mike\n",
|
||||
scenarioType: "decode",
|
||||
},
|
||||
{
|
||||
description: "does not expand automatically",
|
||||
skipDoc: true,
|
||||
|
Loading…
Reference in New Issue
Block a user