Added decoder op

This commit is contained in:
Mike Farah 2021-10-22 12:37:47 +11:00
parent cdc5ef7b15
commit 7288d34778
8 changed files with 162 additions and 83 deletions

View File

@ -0,0 +1,110 @@
Encode operators will take the piped in object structure and encode it as a string in the desired format. The decode operators do the opposite, they take a formatted string and decode it into the relevant object structure.
## Encode value as yaml string
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_yaml)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
cool: thing
```
## Encode value as yaml string, using toyaml
Does the same thing as to_yaml, matching jq naming convention.
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_yaml)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
cool: thing
```
## Encode value as json string
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_json)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
{
"cool": "thing"
}
```
## Encode value as props string
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_props)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
cool = thing
```
## Decode a yaml encoded string
Given a sample.yml file of:
```yaml
a: 'foo: bar'
```
then
```bash
yq eval '.b = (.a | from_yaml)' sample.yml
```
will output
```yaml
a: 'foo: bar'
b:
foo: bar
```
## Update an encoded yaml string
Given a sample.yml file of:
```yaml
a: |
foo: bar
```
then
```bash
yq eval '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
```
will output
```yaml
a: |
foo: cat
```

View File

@ -1,77 +0,0 @@
Encode operators will take the piped in object structure and encode it as a string in the desired format.
## Encode value as yaml string
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_yaml)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
cool: thing
```
## Encode value as yaml string, using toyaml
Does the same thing as to_yaml, matching jq naming convention.
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_yaml)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
cool: thing
```
## Encode value as json string
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_json)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
{
"cool": "thing"
}
```
## Encode value as props string
Given a sample.yml file of:
```yaml
a:
cool: thing
```
then
```bash
yq eval '.b = (.a | to_props)' sample.yml
```
will output
```yaml
a:
cool: thing
b: |
cool = thing
```

View File

@ -0,0 +1 @@
Encode operators will take the piped in object structure and encode it as a string in the desired format. The decode operators do the opposite, they take a formatted string and decode it into the relevant object structure.

View File

@ -1 +0,0 @@
Encode operators will take the piped in object structure and encode it as a string in the desired format.

View File

@ -281,6 +281,12 @@ func initLexer() (*lex.Lexer, error) {
lexer.Add([]byte(`to_json`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: JsonOutputFormat}))
lexer.Add([]byte(`to_props`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: PropsOutputFormat}))
lexer.Add([]byte(`fromyaml`), opToken(decodeOpType))
lexer.Add([]byte(`fromjson`), opToken(decodeOpType))
lexer.Add([]byte(`from_yaml`), opToken(decodeOpType))
lexer.Add([]byte(`from_json`), opToken(decodeOpType))
lexer.Add([]byte(`sortKeys`), opToken(sortKeysOpType))
lexer.Add([]byte(`select`), opToken(selectOpType))
lexer.Add([]byte(`has`), opToken(hasOpType))

View File

@ -59,7 +59,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: 0, Precedence: 50, Handler: collectOperator}
var encodeOpType = &operationType{Type: "TO_YAML", NumArgs: 0, Precedence: 50, Handler: encodeOperator}
var encodeOpType = &operationType{Type: "ENCODE", NumArgs: 0, Precedence: 50, Handler: encodeOperator}
var decodeOpType = &operationType{Type: "DECODE", NumArgs: 0, Precedence: 50, Handler: decodeOperator}
var anyOpType = &operationType{Type: "ANY", NumArgs: 0, Precedence: 50, Handler: anyOperator}
var allOpType = &operationType{Type: "ALL", NumArgs: 0, Precedence: 50, Handler: allOperator}

View File

@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"container/list"
"strings"
"gopkg.in/yaml.v3"
)
@ -38,3 +39,24 @@ func encodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
}
return context.ChildContext(results), nil
}
/* takes a string and decodes it back into an object */
func decodeOperator(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)
var dataBucket yaml.Node
log.Debugf("got: [%v]", candidate.Node.Value)
decoder := yaml.NewDecoder(strings.NewReader(unwrapDoc(candidate.Node).Value))
errorReading := decoder.Decode(&dataBucket)
if errorReading != nil {
return Context{}, errorReading
}
//first node is a doc
node := unwrapDoc(&dataBucket)
results.PushBack(candidate.CreateChild(nil, node))
}
return context.ChildContext(results), nil
}

View File

@ -4,7 +4,7 @@ import (
"testing"
)
var encoderOperatorScenarios = []expressionScenario{
var encoderDecoderOperatorScenarios = []expressionScenario{
{
description: "Encode value as yaml string",
document: `{a: {cool: "thing"}}`,
@ -42,11 +42,28 @@ var encoderOperatorScenarios = []expressionScenario{
`,
},
},
{
description: "Decode a yaml encoded string",
document: `a: "foo: bar"`,
expression: `.b = (.a | from_yaml)`,
expected: []string{
"D0, P[], (doc)::a: \"foo: bar\"\nb:\n foo: bar\n",
},
},
{
description: "Update an encoded yaml string",
dontFormatInputForDoc: true,
document: "a: |\n foo: bar",
expression: `.a |= (from_yaml | .foo = "cat" | to_yaml)`,
expected: []string{
"D0, P[], (doc)::a: |\n foo: cat\n",
},
},
}
func TestEncoderOperatorScenarios(t *testing.T) {
for _, tt := range encoderOperatorScenarios {
func TestEncoderDecoderOperatorScenarios(t *testing.T) {
for _, tt := range encoderDecoderOperatorScenarios {
testScenario(t, &tt)
}
documentScenarios(t, "Encoder", encoderOperatorScenarios)
documentScenarios(t, "Encoder and Decoder", encoderDecoderOperatorScenarios)
}