mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 13:48:06 +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
|
- 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
|
## Roundtrip
|
||||||
Given a sample.properties file of:
|
Given a sample.properties file of:
|
||||||
```properties
|
```properties
|
||||||
|
@ -55,6 +55,8 @@ var participleYqRules = []*participleYqRule{
|
|||||||
simpleOp("sortKeys", sortKeysOpType),
|
simpleOp("sortKeys", sortKeysOpType),
|
||||||
simpleOp("sort_?keys", 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},
|
{"YamlEncodeWithIndent", `to_?yaml\([0-9]+\)`, encodeParseIndent(YamlOutputFormat), 0},
|
||||||
{"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLOutputFormat), 0},
|
{"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLOutputFormat), 0},
|
||||||
{"JSONEncodeWithIndent", `to_?json\([0-9]+\)`, encodeParseIndent(JSONOutputFormat), 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 {
|
func flattenWithDepth() yqAction {
|
||||||
return func(rawToken lexer.Token) (*token, error) {
|
return func(rawToken lexer.Token) (*token, error) {
|
||||||
value := rawToken.Value
|
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 lineOpType = &operationType{Type: "LINE", NumArgs: 0, Precedence: 50, Handler: lineOperator}
|
||||||
var columnOpType = &operationType{Type: "LINE", NumArgs: 0, Precedence: 50, Handler: columnOperator}
|
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 collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
|
||||||
var sliceArrayOpType = &operationType{Type: "SLICE", NumArgs: 0, Precedence: 50, Handler: sliceArrayOperator}
|
var sliceArrayOpType = &operationType{Type: "SLICE", NumArgs: 0, Precedence: 50, Handler: sliceArrayOperator}
|
||||||
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
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,
|
expected: expectedDecodedYaml,
|
||||||
scenarioType: "decode",
|
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",
|
description: "does not expand automatically",
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user