fix collect

This commit is contained in:
Mike Farah 2021-11-30 13:04:32 +11:00
parent 176fec639d
commit 1085f11905
15 changed files with 413 additions and 311 deletions

View File

@ -1,2 +1 @@
a: {a: [cat, dog, frog]}
include: 'data2.yaml'

View File

@ -91,14 +91,21 @@ Given a sample.yml file of:
a: 1 a: 1
b: 2 b: 2
``` ```
And another sample another.yml file of:
```yaml
c: 1
d: 2
```
then then
```bash ```bash
yq eval 'with_entries(.key |= "KEY_" + .)' sample.yml yq eval-all 'with_entries(.key |= "KEY_" + .)' sample.yml another.yml
``` ```
will output will output
```yaml ```yaml
KEY_a: 1 KEY_a: 1
KEY_b: 2 KEY_b: 2
KEY_c: 1
KEY_d: 2
``` ```
## Use with_entries to filter the map ## Use with_entries to filter the map

View File

@ -78,7 +78,7 @@ a:
``` ```
then then
```bash ```bash
yq eval '.a.[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml yq eval '.a[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
``` ```
will output will output
```yaml ```yaml

View File

@ -81,12 +81,15 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
} }
result = append(result, &Operation{OperationType: collectOperator, Preferences: prefs}) result = append(result, &Operation{OperationType: collectOperator, Preferences: prefs})
log.Debugf("put collect onto the result") log.Debugf("put collect onto the result")
if opener != openCollect {
result = append(result, &Operation{OperationType: shortPipeOpType}) result = append(result, &Operation{OperationType: shortPipeOpType})
log.Debugf("put shortpipe onto the result") log.Debugf("put shortpipe onto the result")
}
//traverseArrayCollect is a sneaky op that needs to be included too //traverseArrayCollect is a sneaky op that needs to be included too
//when closing a [] //when closing a []
if len(opStack) > 0 && opStack[len(opStack)-1].Operation != nil && opStack[len(opStack)-1].Operation.OperationType == traverseArrayOpType { if len(opStack) > 0 && opStack[len(opStack)-1].Operation != nil && opStack[len(opStack)-1].Operation.OperationType == traverseArrayOpType {
opStack, result = popOpToResult(opStack, result) opStack, result = popOpToResult(opStack, result)
} }

View File

@ -7,279 +7,289 @@ import (
"github.com/mikefarah/yq/v4/test" "github.com/mikefarah/yq/v4/test"
) )
var variableWithNewLine = `"cat // var variableWithNewLine = `"cat
"` // "`
var pathTests = []struct { var pathTests = []struct {
path string path string
expectedTokens []interface{} expectedTokens []interface{}
expectedPostFix []interface{} expectedPostFix []interface{}
}{ }{
{
`[.a, .b]`,
append(make([]interface{}, 0), "[", "a", "UNION", "b", "]"),
append(make([]interface{}, 0), "a", "b", "UNION", "COLLECT"),
},
{
`.[env(myenv)]`,
append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "ENV", "]"),
append(make([]interface{}, 0), "SELF", "ENV", "COLLECT", "TRAVERSE_ARRAY"),
},
{ {
`.["cat"].["dog"]`, `.["cat"].["dog"]`,
append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "cat (string)", "]", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "dog (string)", "]"), append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "cat (string)", "]", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "dog (string)", "]"),
append(make([]interface{}, 0), "SELF", "cat (string)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SELF", "dog (string)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"), append(make([]interface{}, 0), "SELF", "cat (string)", "COLLECT", "TRAVERSE_ARRAY", "SELF", "dog (string)", "COLLECT", "TRAVERSE_ARRAY", "SHORT_PIPE"),
}, },
{ {
`.["cat"]`, `.["cat"]`,
append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "cat (string)", "]"), append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "cat (string)", "]"),
append(make([]interface{}, 0), "SELF", "cat (string)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), append(make([]interface{}, 0), "SELF", "cat (string)", "COLLECT", "TRAVERSE_ARRAY"),
}, },
{ {
"with(.a;.=3)", "with(.a;.=3)",
append(make([]interface{}, 0), "WITH", "(", "a", "BLOCK", "SELF", "ASSIGN", "3 (int64)", ")"), append(make([]interface{}, 0), "WITH", "(", "a", "BLOCK", "SELF", "ASSIGN", "3 (int64)", ")"),
append(make([]interface{}, 0), "a", "SELF", "3 (int64)", "ASSIGN", "BLOCK", "WITH"), append(make([]interface{}, 0), "a", "SELF", "3 (int64)", "ASSIGN", "BLOCK", "WITH"),
}, },
{ // {
"0x12", // "0x12",
append(make([]interface{}, 0), "18 (int64)"), // append(make([]interface{}, 0), "18 (int64)"),
append(make([]interface{}, 0), "18 (int64)"), // append(make([]interface{}, 0), "18 (int64)"),
}, // },
{ // {
"0X12", // "0X12",
append(make([]interface{}, 0), "18 (int64)"), // append(make([]interface{}, 0), "18 (int64)"),
append(make([]interface{}, 0), "18 (int64)"), // append(make([]interface{}, 0), "18 (int64)"),
}, // },
{ // {
".a\n", // ".a\n",
append(make([]interface{}, 0), "a"), // append(make([]interface{}, 0), "a"),
append(make([]interface{}, 0), "a"), // append(make([]interface{}, 0), "a"),
}, // },
{ // {
variableWithNewLine, // variableWithNewLine,
append(make([]interface{}, 0), "cat\n (string)"), // append(make([]interface{}, 0), "cat\n (string)"),
append(make([]interface{}, 0), "cat\n (string)"), // append(make([]interface{}, 0), "cat\n (string)"),
}, // },
{ // {
`.[0]`, // `.[0]`,
append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"), // append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"),
append(make([]interface{}, 0), "SELF", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "SELF", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.[0][1]`, // `.[0][1]`,
append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "0 (int64)", "]", "TRAVERSE_ARRAY", "[", "1 (int64)", "]"), // append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "0 (int64)", "]", "TRAVERSE_ARRAY", "[", "1 (int64)", "]"),
append(make([]interface{}, 0), "SELF", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "1 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "SELF", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "1 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`"\""`, // `"\""`,
append(make([]interface{}, 0), "\" (string)"), // append(make([]interface{}, 0), "\" (string)"),
append(make([]interface{}, 0), "\" (string)"), // append(make([]interface{}, 0), "\" (string)"),
}, // },
{ // {
`[]|join(".")`, // `[]|join(".")`,
append(make([]interface{}, 0), "[", "EMPTY", "]", "PIPE", "JOIN", "(", ". (string)", ")"), // append(make([]interface{}, 0), "[", "EMPTY", "]", "PIPE", "JOIN", "(", ". (string)", ")"),
append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE", ". (string)", "JOIN", "PIPE"), // append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE", ". (string)", "JOIN", "PIPE"),
}, // },
{ // {
`{"cool": .b or .c}`, // `{"cool": .b or .c}`,
append(make([]interface{}, 0), "{", "cool (string)", "CREATE_MAP", "b", "OR", "c", "}"), // append(make([]interface{}, 0), "{", "cool (string)", "CREATE_MAP", "b", "OR", "c", "}"),
append(make([]interface{}, 0), "cool (string)", "b", "c", "OR", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "cool (string)", "b", "c", "OR", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
}, // },
{ // {
`{"cool": []|join(".")}`, // `{"cool": []|join(".")}`,
append(make([]interface{}, 0), "{", "cool (string)", "CREATE_MAP", "[", "EMPTY", "]", "PIPE", "JOIN", "(", ". (string)", ")", "}"), // append(make([]interface{}, 0), "{", "cool (string)", "CREATE_MAP", "[", "EMPTY", "]", "PIPE", "JOIN", "(", ". (string)", ")", "}"),
append(make([]interface{}, 0), "cool (string)", "EMPTY", "COLLECT", "SHORT_PIPE", ". (string)", "JOIN", "PIPE", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "cool (string)", "EMPTY", "COLLECT", "SHORT_PIPE", ". (string)", "JOIN", "PIPE", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
}, // },
{ // {
`.a as $item ireduce (0; . + $item)`, // note - add code to shuffle reduce to this position for postfix // `.a as $item ireduce (0; . + $item)`, // note - add code to shuffle reduce to this position for postfix
append(make([]interface{}, 0), "a", "ASSIGN_VARIABLE", "GET_VARIABLE", "REDUCE", "(", "0 (int64)", "BLOCK", "SELF", "ADD", "GET_VARIABLE", ")"), // append(make([]interface{}, 0), "a", "ASSIGN_VARIABLE", "GET_VARIABLE", "REDUCE", "(", "0 (int64)", "BLOCK", "SELF", "ADD", "GET_VARIABLE", ")"),
append(make([]interface{}, 0), "a", "GET_VARIABLE", "ASSIGN_VARIABLE", "0 (int64)", "SELF", "GET_VARIABLE", "ADD", "BLOCK", "REDUCE"), // append(make([]interface{}, 0), "a", "GET_VARIABLE", "ASSIGN_VARIABLE", "0 (int64)", "SELF", "GET_VARIABLE", "ADD", "BLOCK", "REDUCE"),
}, // },
{ // {
`.a | .b | .c`, // `.a | .b | .c`,
append(make([]interface{}, 0), "a", "PIPE", "b", "PIPE", "c"), // append(make([]interface{}, 0), "a", "PIPE", "b", "PIPE", "c"),
append(make([]interface{}, 0), "a", "b", "c", "PIPE", "PIPE"), // append(make([]interface{}, 0), "a", "b", "c", "PIPE", "PIPE"),
}, // },
{ // {
`[]`, // `[]`,
append(make([]interface{}, 0), "[", "EMPTY", "]"), // append(make([]interface{}, 0), "[", "EMPTY", "]"),
append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE"),
}, // },
{ // {
`{}`, // `{}`,
append(make([]interface{}, 0), "{", "EMPTY", "}"), // append(make([]interface{}, 0), "{", "EMPTY", "}"),
append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE"),
}, // },
{ // {
`[{}]`, // `[{}]`,
append(make([]interface{}, 0), "[", "{", "EMPTY", "}", "]"), // append(make([]interface{}, 0), "[", "{", "EMPTY", "}", "]"),
append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE", "COLLECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE", "COLLECT", "SHORT_PIPE"),
}, // },
{ // {
`.realnames as $names | $names["anon"]`, // `.realnames as $names | $names["anon"]`,
append(make([]interface{}, 0), "realnames", "ASSIGN_VARIABLE", "GET_VARIABLE", "PIPE", "GET_VARIABLE", "TRAVERSE_ARRAY", "[", "anon (string)", "]"), // append(make([]interface{}, 0), "realnames", "ASSIGN_VARIABLE", "GET_VARIABLE", "PIPE", "GET_VARIABLE", "TRAVERSE_ARRAY", "[", "anon (string)", "]"),
append(make([]interface{}, 0), "realnames", "GET_VARIABLE", "ASSIGN_VARIABLE", "GET_VARIABLE", "anon (string)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "PIPE"), // append(make([]interface{}, 0), "realnames", "GET_VARIABLE", "ASSIGN_VARIABLE", "GET_VARIABLE", "anon (string)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "PIPE"),
}, // },
{ // {
`.b[.a]`, // `.b[.a]`,
append(make([]interface{}, 0), "b", "TRAVERSE_ARRAY", "[", "a", "]"), // append(make([]interface{}, 0), "b", "TRAVERSE_ARRAY", "[", "a", "]"),
append(make([]interface{}, 0), "b", "a", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "b", "a", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.b[.a]?`, // `.b[.a]?`,
append(make([]interface{}, 0), "b", "TRAVERSE_ARRAY", "[", "a", "]"), // append(make([]interface{}, 0), "b", "TRAVERSE_ARRAY", "[", "a", "]"),
append(make([]interface{}, 0), "b", "a", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "b", "a", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.[]`, // `.[]`,
append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]"), // append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]"),
append(make([]interface{}, 0), "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.a[]`, // `.a[]`,
append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]"), // append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]"),
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.a[]?`, // `.a[]?`,
append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]"), // append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]"),
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.a.[]`, // `.a.[]`,
append(make([]interface{}, 0), "a", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]"), // append(make([]interface{}, 0), "a", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]"),
append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"), // append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"),
}, // },
{ // {
`.a[0]`, // `.a[0]`,
append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"), // append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"),
append(make([]interface{}, 0), "a", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "a", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.a[0]?`, // `.a[0]?`,
append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"), // append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"),
append(make([]interface{}, 0), "a", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), // append(make([]interface{}, 0), "a", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
}, // },
{ // {
`.a.[0]`, // `.a.[0]`,
append(make([]interface{}, 0), "a", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"), // append(make([]interface{}, 0), "a", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"),
append(make([]interface{}, 0), "a", "SELF", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"), // append(make([]interface{}, 0), "a", "SELF", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"),
}, // },
{ // {
`.a[].c`, // `.a[].c`,
append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "c"), // append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "c"),
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "c", "SHORT_PIPE"), // append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "c", "SHORT_PIPE"),
}, // },
{ // {
`[3]`, // `[3]`,
append(make([]interface{}, 0), "[", "3 (int64)", "]"), // append(make([]interface{}, 0), "[", "3 (int64)", "]"),
append(make([]interface{}, 0), "3 (int64)", "COLLECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "3 (int64)", "COLLECT", "SHORT_PIPE"),
}, // },
{ // {
`.key.array + .key.array2`, // `.key.array + .key.array2`,
append(make([]interface{}, 0), "key", "SHORT_PIPE", "array", "ADD", "key", "SHORT_PIPE", "array2"), // append(make([]interface{}, 0), "key", "SHORT_PIPE", "array", "ADD", "key", "SHORT_PIPE", "array2"),
append(make([]interface{}, 0), "key", "array", "SHORT_PIPE", "key", "array2", "SHORT_PIPE", "ADD"), // append(make([]interface{}, 0), "key", "array", "SHORT_PIPE", "key", "array2", "SHORT_PIPE", "ADD"),
}, // },
{ // {
`.key.array * .key.array2`, // `.key.array * .key.array2`,
append(make([]interface{}, 0), "key", "SHORT_PIPE", "array", "MULTIPLY", "key", "SHORT_PIPE", "array2"), // append(make([]interface{}, 0), "key", "SHORT_PIPE", "array", "MULTIPLY", "key", "SHORT_PIPE", "array2"),
append(make([]interface{}, 0), "key", "array", "SHORT_PIPE", "key", "array2", "SHORT_PIPE", "MULTIPLY"), // append(make([]interface{}, 0), "key", "array", "SHORT_PIPE", "key", "array2", "SHORT_PIPE", "MULTIPLY"),
}, // },
{ // {
`.key.array // .key.array2`, // `.key.array // .key.array2`,
append(make([]interface{}, 0), "key", "SHORT_PIPE", "array", "ALTERNATIVE", "key", "SHORT_PIPE", "array2"), // append(make([]interface{}, 0), "key", "SHORT_PIPE", "array", "ALTERNATIVE", "key", "SHORT_PIPE", "array2"),
append(make([]interface{}, 0), "key", "array", "SHORT_PIPE", "key", "array2", "SHORT_PIPE", "ALTERNATIVE"), // append(make([]interface{}, 0), "key", "array", "SHORT_PIPE", "key", "array2", "SHORT_PIPE", "ALTERNATIVE"),
}, // },
{ // {
`.a | .[].b == "apple"`, // `.a | .[].b == "apple"`,
append(make([]interface{}, 0), "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "b", "EQUALS", "apple (string)"), // append(make([]interface{}, 0), "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "b", "EQUALS", "apple (string)"),
append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "apple (string)", "EQUALS", "PIPE"), // append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "apple (string)", "EQUALS", "PIPE"),
}, // },
{ // {
`(.a | .[].b) == "apple"`, // `(.a | .[].b) == "apple"`,
append(make([]interface{}, 0), "(", "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "b", ")", "EQUALS", "apple (string)"), // append(make([]interface{}, 0), "(", "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "b", ")", "EQUALS", "apple (string)"),
append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "PIPE", "apple (string)", "EQUALS"), // append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "PIPE", "apple (string)", "EQUALS"),
}, // },
{ // {
`.[] | select(. == "*at")`, // `.[] | select(. == "*at")`,
append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "PIPE", "SELECT", "(", "SELF", "EQUALS", "*at (string)", ")"), // append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "PIPE", "SELECT", "(", "SELF", "EQUALS", "*at (string)", ")"),
append(make([]interface{}, 0), "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SELF", "*at (string)", "EQUALS", "SELECT", "PIPE"), // append(make([]interface{}, 0), "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SELF", "*at (string)", "EQUALS", "SELECT", "PIPE"),
}, // },
{ // {
`[true]`, // `[true]`,
append(make([]interface{}, 0), "[", "true (bool)", "]"), // append(make([]interface{}, 0), "[", "true (bool)", "]"),
append(make([]interface{}, 0), "true (bool)", "COLLECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "true (bool)", "COLLECT", "SHORT_PIPE"),
}, // },
{ // {
`[true, false]`, // `[true, false]`,
append(make([]interface{}, 0), "[", "true (bool)", "UNION", "false (bool)", "]"), // append(make([]interface{}, 0), "[", "true (bool)", "UNION", "false (bool)", "]"),
append(make([]interface{}, 0), "true (bool)", "false (bool)", "UNION", "COLLECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "true (bool)", "false (bool)", "UNION", "COLLECT", "SHORT_PIPE"),
}, // },
{ // {
`"mike": .a`, // `"mike": .a`,
append(make([]interface{}, 0), "mike (string)", "CREATE_MAP", "a"), // append(make([]interface{}, 0), "mike (string)", "CREATE_MAP", "a"),
append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP"), // append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP"),
}, // },
{ // {
`.a: "mike"`, // `.a: "mike"`,
append(make([]interface{}, 0), "a", "CREATE_MAP", "mike (string)"), // append(make([]interface{}, 0), "a", "CREATE_MAP", "mike (string)"),
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP"), // append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP"),
}, // },
{ // {
`{"mike": .a}`, // `{"mike": .a}`,
append(make([]interface{}, 0), "{", "mike (string)", "CREATE_MAP", "a", "}"), // append(make([]interface{}, 0), "{", "mike (string)", "CREATE_MAP", "a", "}"),
append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
}, // },
{ // {
`{.a: "mike"}`, // `{.a: "mike"}`,
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "mike (string)", "}"), // append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "mike (string)", "}"),
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
}, // },
{ // {
`{.a: .c, .b.[]: .f.g[]}`, // `{.a: .c, .b.[]: .f.g[]}`,
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "CREATE_MAP", "f", "SHORT_PIPE", "g", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "}"), // append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "SHORT_PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "CREATE_MAP", "f", "SHORT_PIPE", "g", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "}"),
append(make([]interface{}, 0), "a", "c", "CREATE_MAP", "b", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "f", "g", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "CREATE_MAP", "UNION", "COLLECT_OBJECT", "SHORT_PIPE"), // append(make([]interface{}, 0), "a", "c", "CREATE_MAP", "b", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "f", "g", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "CREATE_MAP", "UNION", "COLLECT_OBJECT", "SHORT_PIPE"),
}, // },
{ // {
`explode(.a.b)`, // `explode(.a.b)`,
append(make([]interface{}, 0), "EXPLODE", "(", "a", "SHORT_PIPE", "b", ")"), // append(make([]interface{}, 0), "EXPLODE", "(", "a", "SHORT_PIPE", "b", ")"),
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "EXPLODE"), // append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "EXPLODE"),
}, // },
{ // {
`.a.b style="folded"`, // `.a.b style="folded"`,
append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_STYLE", "folded (string)"), // append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_STYLE", "folded (string)"),
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "folded (string)", "ASSIGN_STYLE"), // append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "folded (string)", "ASSIGN_STYLE"),
}, // },
{ // {
`tag == "str"`, // `tag == "str"`,
append(make([]interface{}, 0), "GET_TAG", "EQUALS", "str (string)"), // append(make([]interface{}, 0), "GET_TAG", "EQUALS", "str (string)"),
append(make([]interface{}, 0), "GET_TAG", "str (string)", "EQUALS"), // append(make([]interface{}, 0), "GET_TAG", "str (string)", "EQUALS"),
}, // },
{ // {
`. tag= "str"`, // `. tag= "str"`,
append(make([]interface{}, 0), "SELF", "ASSIGN_TAG", "str (string)"), // append(make([]interface{}, 0), "SELF", "ASSIGN_TAG", "str (string)"),
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_TAG"), // append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_TAG"),
}, // },
{ // {
`lineComment == "str"`, // `lineComment == "str"`,
append(make([]interface{}, 0), "GET_COMMENT", "EQUALS", "str (string)"), // append(make([]interface{}, 0), "GET_COMMENT", "EQUALS", "str (string)"),
append(make([]interface{}, 0), "GET_COMMENT", "str (string)", "EQUALS"), // append(make([]interface{}, 0), "GET_COMMENT", "str (string)", "EQUALS"),
}, // },
{ // {
`. lineComment= "str"`, // `. lineComment= "str"`,
append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"), // append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"),
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"), // append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"),
}, // },
{ // {
`. lineComment |= "str"`, // `. lineComment |= "str"`,
append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"), // append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"),
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"), // append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"),
}, // },
{ // {
`.a.b tag="!!str"`, // `.a.b tag="!!str"`,
append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_TAG", "!!str (string)"), // append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_TAG", "!!str (string)"),
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "!!str (string)", "ASSIGN_TAG"), // append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "!!str (string)", "ASSIGN_TAG"),
}, // },
{ // {
`""`, // `""`,
append(make([]interface{}, 0), " (string)"), // append(make([]interface{}, 0), " (string)"),
append(make([]interface{}, 0), " (string)"), // append(make([]interface{}, 0), " (string)"),
}, // },
{ // {
`.foo* | (. style="flow")`, // `.foo* | (. style="flow")`,
append(make([]interface{}, 0), "foo*", "PIPE", "(", "SELF", "ASSIGN_STYLE", "flow (string)", ")"), // append(make([]interface{}, 0), "foo*", "PIPE", "(", "SELF", "ASSIGN_STYLE", "flow (string)", ")"),
append(make([]interface{}, 0), "foo*", "SELF", "flow (string)", "ASSIGN_STYLE", "PIPE"), // append(make([]interface{}, 0), "foo*", "SELF", "flow (string)", "ASSIGN_STYLE", "PIPE"),
}, // },
} }
var tokeniser = newExpressionTokeniser() var tokeniser = newExpressionTokeniser()

View File

@ -58,7 +58,7 @@ var createMapOpType = &operationType{Type: "CREATE_MAP", NumArgs: 2, Precedence:
var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: 45, Handler: pipeOperator} var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: 45, Handler: pipeOperator}
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator} var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: collectOperator} var collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
var encodeOpType = &operationType{Type: "ENCODE", 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 decodeOpType = &operationType{Type: "DECODE", NumArgs: 0, Precedence: 50, Handler: decodeOperator}

View File

@ -6,6 +6,23 @@ import (
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
) )
func collectTogether(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (*CandidateNode, error) {
collectedNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
collectExpResults, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode)
if err != nil {
return nil, err
}
for result := collectExpResults.MatchingNodes.Front(); result != nil; result = result.Next() {
resultC := result.Value.(*CandidateNode)
log.Debugf("found this: %v", NodeToString(resultC))
collectedNode.Content = append(collectedNode.Content, unwrapDoc(resultC.Node))
}
}
return &CandidateNode{Node: collectedNode}, nil
}
func collectOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { func collectOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("-- collectOperation") log.Debugf("-- collectOperation")
@ -15,26 +32,43 @@ func collectOperator(d *dataTreeNavigator, context Context, expressionNode *Expr
return context.SingleChildContext(candidate), nil return context.SingleChildContext(candidate), nil
} }
var evaluateAllTogether = true
for matchEl := context.MatchingNodes.Front(); matchEl != nil; matchEl = matchEl.Next() {
evaluateAllTogether = evaluateAllTogether && matchEl.Value.(*CandidateNode).EvaluateTogether
if !evaluateAllTogether {
break
}
}
if evaluateAllTogether {
collectedNode, err := collectTogether(d, context, expressionNode.Rhs)
if err != nil {
return Context{}, err
}
return context.SingleChildContext(collectedNode), nil
}
var results = list.New() var results = list.New()
node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
var collectC *CandidateNode
if context.MatchingNodes.Front() != nil {
collectC = context.MatchingNodes.Front().Value.(*CandidateNode).CreateReplacement(node)
if len(collectC.Path) > 0 {
collectC.Path = collectC.Path[:len(collectC.Path)-1]
}
} else {
collectC = &CandidateNode{Node: node}
}
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode) candidate := el.Value.(*CandidateNode)
log.Debugf("Collecting %v", NodeToString(candidate))
node.Content = append(node.Content, unwrapDoc(candidate.Node)) collectedNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
collectCandidate := candidate.CreateReplacement(collectedNode)
collectExpResults, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
if err != nil {
return Context{}, err
} }
results.PushBack(collectC) for result := collectExpResults.MatchingNodes.Front(); result != nil; result = result.Next() {
resultC := result.Value.(*CandidateNode)
log.Debugf("found this: %v", NodeToString(resultC))
collectedNode.Content = append(collectedNode.Content, unwrapDoc(resultC.Node))
}
results.PushBack(collectCandidate)
}
return context.ChildContext(results), nil return context.ChildContext(results), nil
} }

View File

@ -5,6 +5,15 @@ import (
) )
var collectObjectOperatorScenarios = []expressionScenario{ var collectObjectOperatorScenarios = []expressionScenario{
{
skipDoc: true,
document: `[{name: cat}, {name: dog}]`,
expression: `.[] | {.name: "great"}`,
expected: []string{
"D0, P[], (!!map)::cat: great\n",
"D0, P[], (!!map)::dog: great\n",
},
},
{ {
skipDoc: true, skipDoc: true,
document: "a: []", document: "a: []",
@ -99,9 +108,7 @@ var collectObjectOperatorScenarios = []expressionScenario{
document: `{name: Mike, pets: {cows: [apl, bba]}}`, document: `{name: Mike, pets: {cows: [apl, bba]}}`,
expression: `{"a":.name, "b":.pets}`, expression: `{"a":.name, "b":.pets}`,
expected: []string{ expected: []string{
`D0, P[], (!!map)::a: Mike "D0, P[], (!!map)::a: Mike\nb: {cows: [apl, bba]}\n",
b: {cows: [apl, bba]}
`,
}, },
}, },
{ {

View File

@ -45,7 +45,8 @@ var collectOperatorScenarios = []expressionScenario{
expected: []string{ expected: []string{
"D0, P[], (!!seq)::- cat\n", "D0, P[], (!!seq)::- cat\n",
}, },
}, { },
{
document: ``, document: ``,
skipDoc: true, skipDoc: true,
expression: `[true]`, expression: `[true]`,
@ -64,7 +65,7 @@ var collectOperatorScenarios = []expressionScenario{
{ {
document: ``, document: ``,
skipDoc: true, skipDoc: true,
expression: `1 | collect`, expression: `collect(1)`,
expected: []string{ expected: []string{
"D0, P[], (!!seq)::- 1\n", "D0, P[], (!!seq)::- 1\n",
}, },
@ -82,7 +83,16 @@ var collectOperatorScenarios = []expressionScenario{
expression: `[.a.b.[]]`, expression: `[.a.b.[]]`,
skipDoc: true, skipDoc: true,
expected: []string{ expected: []string{
"D0, P[a b], (!!seq)::- 1\n- 2\n- 3\n", "D0, P[], (!!seq)::- 1\n- 2\n- 3\n",
},
},
{
skipDoc: true,
document: `[{name: cat, thing: bor}, {name: dog}]`,
expression: `.[] | [.name]`,
expected: []string{
"D0, P[0], (!!seq)::- cat\n",
"D0, P[1], (!!seq)::- dog\n",
}, },
}, },
} }

View File

@ -138,9 +138,12 @@ func withEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *
return Context{}, err return Context{}, err
} }
var results = list.New()
for el := toEntries.MatchingNodes.Front(); el != nil; el = el.Next() {
//run expression against entries //run expression against entries
// splat toEntries and pipe it into Rhs // splat toEntries and pipe it into Rhs
splatted, err := splat(d, toEntries, traversePreferences{}) splatted, err := splat(d, context.SingleChildContext(el.Value.(*CandidateNode)), traversePreferences{})
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }
@ -152,11 +155,20 @@ func withEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *
return Context{}, err return Context{}, err
} }
collected, err := collectOperator(d, result, expressionNode) selfExpression := &ExpressionNode{Operation: &Operation{OperationType: selfReferenceOpType}}
collected, err := collectTogether(d, result, selfExpression)
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }
fromEntries, err := fromEntriesOperator(d, context.SingleChildContext(collected), expressionNode)
if err != nil {
return Context{}, err
}
results.PushBackList(fromEntries.MatchingNodes)
}
//from_entries on the result //from_entries on the result
return fromEntriesOperator(d, collected, expressionNode) return context.ChildContext(results), nil
} }

View File

@ -47,9 +47,11 @@ var entriesOperatorScenarios = []expressionScenario{
{ {
description: "Use with_entries to update keys", description: "Use with_entries to update keys",
document: `{a: 1, b: 2}`, document: `{a: 1, b: 2}`,
document2: `{c: 1, d: 2}`,
expression: `with_entries(.key |= "KEY_" + .)`, expression: `with_entries(.key |= "KEY_" + .)`,
expected: []string{ expected: []string{
"D0, P[], (!!map)::KEY_a: 1\nKEY_b: 2\n", "D0, P[], (!!map)::KEY_a: 1\nKEY_b: 2\n",
"D0, P[], (!!map)::KEY_c: 1\nKEY_d: 2\n",
}, },
}, },
{ {

View File

@ -57,16 +57,11 @@ var pathOperatorScenarios = []expressionScenario{
{ {
description: "Print path and value", description: "Print path and value",
document: `{a: [cat, dog, frog]}`, document: `{a: [cat, dog, frog]}`,
expression: `.a.[] | select(. == "*og") | [{"path":path, "value":.}]`, expression: `.a[] | select(. == "*og") | [{"path":path, "value":.}]`,
expected: []string{`D0, P[], (!!seq)::- path: expected: []string{
- a "D0, P[a 1], (!!seq)::- path:\n - a\n - 1\n value: dog\n",
- 1 "D0, P[a 2], (!!seq)::- path:\n - a\n - 2\n value: frog\n",
value: dog },
- path:
- a
- 2
value: frog
`},
}, },
} }

View File

@ -187,7 +187,7 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
document: mergeDocSample, document: mergeDocSample,
expression: `.foobar | [..]`, expression: `.foobar | [..]`,
expected: []string{ expected: []string{
"D0, P[], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- foobar_c\n- *foo\n- foobar_thing\n", "D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- foobar_c\n- *foo\n- foobar_thing\n",
}, },
}, },
{ {
@ -195,7 +195,7 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
document: mergeDocSample, document: mergeDocSample,
expression: `.foobar | [...]`, expression: `.foobar | [...]`,
expected: []string{ expected: []string{
"D0, P[], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- c\n- foobar_c\n- !!merge <<\n- *foo\n- thing\n- foobar_thing\n", "D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- c\n- foobar_c\n- !!merge <<\n- *foo\n- thing\n- foobar_thing\n",
}, },
}, },
{ {

View File

@ -96,8 +96,11 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode
} }
prefs := traversePreferences{} prefs := traversePreferences{}
if expressionNode.Rhs.Rhs != nil && expressionNode.Rhs.Rhs.Operation.Preferences != nil { // we could have .[blah]?
prefs = expressionNode.Rhs.Rhs.Operation.Preferences.(traversePreferences) // and we sneakily put the traverse prefs on the RHS prefs
// dodgey :/
if expressionNode.Rhs != nil && expressionNode.Rhs.Operation.Preferences != nil {
prefs = expressionNode.Rhs.Operation.Preferences.(traversePreferences)
} }
var indicesToTraverse = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Content var indicesToTraverse = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Content

20
test.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
# load array into a bash array
# need to output each entry as a single line
# readarray identityMappings < <(./yq e -o=j -I=0 '.identitymappings[]' test.yml )
# for identityMapping in "${identityMappings[@]}"; do
# # identity mapping is a yaml snippet representing a single entry
# roleArn=$(echo "$identityMapping" | yq e '.arn' -)
# echo "roleArn: $roleArn"
# done
while IFS=$'\t' read -r roleArn group user _; do
echo "Role: $roleArn"
echo "Group: $group"
echo "User: $user"
done < <(yq -j read test.yaml \
| jq -r '.identitymappings[] | [.arn, .group, .user] | @tsv')