mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-14 07:08:06 +00:00
Fixed empty array op
This commit is contained in:
parent
aed598c736
commit
3f04a1b52e
@ -100,7 +100,7 @@ a:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.a[] | select(. == "apple") |= "frog"' sample.yml
|
yq eval '.a.[] | select(. == "apple") |= "frog"' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -10,6 +10,7 @@ yq eval --null-input '[]'
|
|||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
[]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Collect single
|
## Collect single
|
||||||
|
@ -34,7 +34,7 @@ pets:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '{.name: .pets[]}' sample.yml
|
yq eval '{.name: .pets.[]}' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@ -57,7 +57,7 @@ pets:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '{.name: .pets[]}' sample.yml
|
yq eval '{.name: .pets.[]}' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
## Retrieve a document index
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
---
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.a | documentIndex' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
0
|
|
||||||
---
|
|
||||||
1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Filter by document index
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
---
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'select(. | documentIndex == 1)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
|
|
||||||
## Print Document Index with matches
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
---
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.a | ({"match": ., "doc": (. | documentIndex)})' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
match: cat
|
|
||||||
doc: 0
|
|
||||||
match: frog
|
|
||||||
doc: 1
|
|
||||||
```
|
|
||||||
|
|
@ -26,7 +26,7 @@ a:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '(.a[] | select(. == "*at")) |= "rabbit"' sample.yml
|
yq eval '(.a.[] | select(. == "*at")) |= "rabbit"' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -73,7 +73,7 @@ var assignOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Update selected results",
|
description: "Update selected results",
|
||||||
document: `{a: {b: apple, c: cactus}}`,
|
document: `{a: {b: apple, c: cactus}}`,
|
||||||
expression: `.a[] | select(. == "apple") |= "frog"`,
|
expression: `.a.[] | select(. == "apple") |= "frog"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n",
|
"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n",
|
||||||
},
|
},
|
||||||
|
@ -3,12 +3,18 @@ package yqlib
|
|||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CollectOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func CollectOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
log.Debugf("-- collectOperation")
|
log.Debugf("-- collectOperation")
|
||||||
|
|
||||||
|
if matchMap.Len() == 0 {
|
||||||
|
node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Value: "[]"}
|
||||||
|
candidate := &CandidateNode{Node: node}
|
||||||
|
return nodeToMap(candidate), nil
|
||||||
|
}
|
||||||
|
|
||||||
var results = list.New()
|
var results = list.New()
|
||||||
|
|
||||||
node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
||||||
|
@ -41,7 +41,7 @@ var collectObjectOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: `Using splat to create multiple objects`,
|
description: `Using splat to create multiple objects`,
|
||||||
document: `{name: Mike, pets: [cat, dog]}`,
|
document: `{name: Mike, pets: [cat, dog]}`,
|
||||||
expression: `{.name: .pets[]}`,
|
expression: `{.name: .pets.[]}`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::Mike: cat\n",
|
"D0, P[], (!!map)::Mike: cat\n",
|
||||||
"D0, P[], (!!map)::Mike: dog\n",
|
"D0, P[], (!!map)::Mike: dog\n",
|
||||||
@ -51,7 +51,7 @@ var collectObjectOperatorScenarios = []expressionScenario{
|
|||||||
description: `Working with multiple documents`,
|
description: `Working with multiple documents`,
|
||||||
dontFormatInputForDoc: false,
|
dontFormatInputForDoc: false,
|
||||||
document: "{name: Mike, pets: [cat, dog]}\n---\n{name: Rosey, pets: [monkey, sheep]}",
|
document: "{name: Mike, pets: [cat, dog]}\n---\n{name: Rosey, pets: [monkey, sheep]}",
|
||||||
expression: `{.name: .pets[]}`,
|
expression: `{.name: .pets.[]}`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::Mike: cat\n",
|
"D0, P[], (!!map)::Mike: cat\n",
|
||||||
"D0, P[], (!!map)::Mike: dog\n",
|
"D0, P[], (!!map)::Mike: dog\n",
|
||||||
@ -62,7 +62,7 @@ var collectObjectOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{name: Mike, pets: [cat, dog], food: [hotdog, burger]}`,
|
document: `{name: Mike, pets: [cat, dog], food: [hotdog, burger]}`,
|
||||||
expression: `{.name: .pets[], "f":.food[]}`,
|
expression: `{.name: .pets.[], "f":.food.[]}`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::Mike: cat\nf: hotdog\n",
|
"D0, P[], (!!map)::Mike: cat\nf: hotdog\n",
|
||||||
"D0, P[], (!!map)::Mike: cat\nf: burger\n",
|
"D0, P[], (!!map)::Mike: cat\nf: burger\n",
|
||||||
|
@ -9,7 +9,9 @@ var collectOperatorScenarios = []expressionScenario{
|
|||||||
description: "Collect empty",
|
description: "Collect empty",
|
||||||
document: ``,
|
document: ``,
|
||||||
expression: `[]`,
|
expression: `[]`,
|
||||||
expected: []string{},
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[]\n",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Collect single",
|
description: "Collect single",
|
||||||
@ -52,7 +54,7 @@ var collectOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
document: `a: {b: [1,2,3]}`,
|
document: `a: {b: [1,2,3]}`,
|
||||||
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[a b], (!!seq)::- 1\n- 2\n- 3\n",
|
||||||
|
@ -21,14 +21,14 @@ var createMapOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
document: `{name: Mike, pets: [cat, dog]}`,
|
document: `{name: Mike, pets: [cat, dog]}`,
|
||||||
expression: `.name: .pets[]`,
|
expression: `.name: .pets.[]`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!seq)::- [{Mike: cat}, {Mike: dog}]\n",
|
"D0, P[], (!!seq)::- [{Mike: cat}, {Mike: dog}]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
document: `{name: Mike, pets: [cat, dog], food: [hotdog, burger]}`,
|
document: `{name: Mike, pets: [cat, dog], food: [hotdog, burger]}`,
|
||||||
expression: `.name: .pets[], "f":.food[]`,
|
expression: `.name: .pets.[], "f":.food.[]`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!seq)::- [{Mike: cat}, {Mike: dog}]\n",
|
"D0, P[], (!!seq)::- [{Mike: cat}, {Mike: dog}]\n",
|
||||||
"D0, P[], (!!seq)::- [{f: hotdog}, {f: burger}]\n",
|
"D0, P[], (!!seq)::- [{f: hotdog}, {f: burger}]\n",
|
||||||
@ -36,7 +36,7 @@ var createMapOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
document: "{name: Mike, pets: [cat, dog], food: [hotdog, burger]}\n---\n{name: Fred, pets: [mouse], food: [pizza, onion, apple]}",
|
document: "{name: Mike, pets: [cat, dog], food: [hotdog, burger]}\n---\n{name: Fred, pets: [mouse], food: [pizza, onion, apple]}",
|
||||||
expression: `.name: .pets[], "f":.food[]`,
|
expression: `.name: .pets.[], "f":.food.[]`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!seq)::- [{Mike: cat}, {Mike: dog}]\n- [{Fred: mouse}]\n",
|
"D0, P[], (!!seq)::- [{Mike: cat}, {Mike: dog}]\n- [{Fred: mouse}]\n",
|
||||||
"D0, P[], (!!seq)::- [{f: hotdog}, {f: burger}]\n- [{f: pizza}, {f: onion}, {f: apple}]\n",
|
"D0, P[], (!!seq)::- [{f: hotdog}, {f: burger}]\n- [{f: pizza}, {f: onion}, {f: apple}]\n",
|
||||||
|
@ -23,7 +23,7 @@ var selectOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `a: [cat,goat,dog]`,
|
document: `a: [cat,goat,dog]`,
|
||||||
expression: `.a[] | select(. == "*at")`,
|
expression: `.a.[] | select(. == "*at")`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[a 0], (!!str)::cat\n",
|
"D0, P[a 0], (!!str)::cat\n",
|
||||||
"D0, P[a 1], (!!str)::goat\n"},
|
"D0, P[a 1], (!!str)::goat\n"},
|
||||||
@ -31,7 +31,7 @@ var selectOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Select and update matching values in map",
|
description: "Select and update matching values in map",
|
||||||
document: `a: { things: cat, bob: goat, horse: dog }`,
|
document: `a: { things: cat, bob: goat, horse: dog }`,
|
||||||
expression: `(.a[] | select(. == "*at")) |= "rabbit"`,
|
expression: `(.a.[] | select(. == "*at")) |= "rabbit"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (doc)::a: {things: rabbit, bob: rabbit, horse: dog}\n",
|
"D0, P[], (doc)::a: {things: rabbit, bob: rabbit, horse: dog}\n",
|
||||||
},
|
},
|
||||||
@ -39,7 +39,7 @@ var selectOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `a: { things: {include: true}, notMe: {include: false}, andMe: {include: fold} }`,
|
document: `a: { things: {include: true}, notMe: {include: false}, andMe: {include: fold} }`,
|
||||||
expression: `.a[] | select(.include)`,
|
expression: `.a.[] | select(.include)`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[a things], (!!map)::{include: true}\n",
|
"D0, P[a things], (!!map)::{include: true}\n",
|
||||||
"D0, P[a andMe], (!!map)::{include: fold}\n",
|
"D0, P[a andMe], (!!map)::{include: fold}\n",
|
||||||
|
@ -29,7 +29,7 @@ func testScenario(t *testing.T, s *expressionScenario) {
|
|||||||
|
|
||||||
node, err := treeCreator.ParsePath(s.expression)
|
node, err := treeCreator.ParsePath(s.expression)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(fmt.Errorf("Error parsing expression %v of %v: %v", s.expression, s.description, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
inputs := list.New()
|
inputs := list.New()
|
||||||
|
@ -37,8 +37,18 @@ var pathTests = []struct {
|
|||||||
// {`.a, .b`, append(make([]interface{}, 0), "a", "OR", "b")},
|
// {`.a, .b`, append(make([]interface{}, 0), "a", "OR", "b")},
|
||||||
// {`[.a, .b]`, append(make([]interface{}, 0), "[", "a", "OR", "b", "]")},
|
// {`[.a, .b]`, append(make([]interface{}, 0), "[", "a", "OR", "b", "]")},
|
||||||
// {`."[a", ."b]"`, append(make([]interface{}, 0), "[a", "OR", "b]")},
|
// {`."[a", ."b]"`, append(make([]interface{}, 0), "[a", "OR", "b]")},
|
||||||
// {`.a[]`, append(make([]interface{}, 0), "a", "PIPE", "[]")},
|
// {`.a.[]`, append(make([]interface{}, 0), "a", "PIPE", "[]")},
|
||||||
// {`.[].a`, append(make([]interface{}, 0), "[]", "PIPE", "a")},
|
// {`.[].a`, append(make([]interface{}, 0), "[]", "PIPE", "a")},
|
||||||
|
// {
|
||||||
|
// `["cat"]`,
|
||||||
|
// append(make([]interface{}, 0), "[", "cat (string)", "]"),
|
||||||
|
// append(make([]interface{}, 0), "cat (string)", "COLLECT", "PIPE"),
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
`[]`,
|
||||||
|
append(make([]interface{}, 0), "[", "]"),
|
||||||
|
append(make([]interface{}, 0), "EMPTY", "COLLECT", "PIPE"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
`d0.a`,
|
`d0.a`,
|
||||||
append(make([]interface{}, 0), "d0", "PIPE", "a"),
|
append(make([]interface{}, 0), "d0", "PIPE", "a"),
|
||||||
@ -85,7 +95,7 @@ var pathTests = []struct {
|
|||||||
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP", "COLLECT_OBJECT", "PIPE"),
|
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP", "COLLECT_OBJECT", "PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`{.a: .c, .b[]: .f.g[]}`,
|
`{.a: .c, .b.[]: .f.g.[]}`,
|
||||||
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "PIPE", "[]", "CREATE_MAP", "f", "PIPE", "g", "PIPE", "[]", "}"),
|
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "PIPE", "[]", "CREATE_MAP", "f", "PIPE", "g", "PIPE", "[]", "}"),
|
||||||
append(make([]interface{}, 0), "a", "c", "CREATE_MAP", "b", "[]", "PIPE", "f", "g", "PIPE", "[]", "PIPE", "CREATE_MAP", "UNION", "COLLECT_OBJECT", "PIPE"),
|
append(make([]interface{}, 0), "a", "c", "CREATE_MAP", "b", "[]", "PIPE", "f", "g", "PIPE", "[]", "PIPE", "CREATE_MAP", "UNION", "COLLECT_OBJECT", "PIPE"),
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,7 @@ package yqlib
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"gopkg.in/op/go-logging.v1"
|
logging "gopkg.in/op/go-logging.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PathPostFixer interface {
|
type PathPostFixer interface {
|
||||||
|
@ -33,6 +33,7 @@ type Token struct {
|
|||||||
|
|
||||||
func (t *Token) toString() string {
|
func (t *Token) toString() string {
|
||||||
if t.TokenType == OperationToken {
|
if t.TokenType == OperationToken {
|
||||||
|
log.Debug("toString, its an op")
|
||||||
return t.Operation.toString()
|
return t.Operation.toString()
|
||||||
} else if t.TokenType == OpenBracket {
|
} else if t.TokenType == OpenBracket {
|
||||||
return "("
|
return "("
|
||||||
@ -58,13 +59,7 @@ func pathToken(wrapped bool) lex.Action {
|
|||||||
if wrapped {
|
if wrapped {
|
||||||
value = unwrap(value)
|
value = unwrap(value)
|
||||||
}
|
}
|
||||||
op := &Operation{OperationType: TraversePath, Value: value, StringValue: value}
|
log.Debug("PathToken %v", value)
|
||||||
return &Token{TokenType: OperationToken, Operation: op, CheckForPostTraverse: true}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func literalPathToken(value string) lex.Action {
|
|
||||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
||||||
op := &Operation{OperationType: TraversePath, Value: value, StringValue: value}
|
op := &Operation{OperationType: TraversePath, Value: value, StringValue: value}
|
||||||
return &Token{TokenType: OperationToken, Operation: op, CheckForPostTraverse: true}, nil
|
return &Token{TokenType: OperationToken, Operation: op, CheckForPostTraverse: true}, nil
|
||||||
}
|
}
|
||||||
@ -78,6 +73,7 @@ func documentToken() lex.Action {
|
|||||||
if errParsingInt != nil {
|
if errParsingInt != nil {
|
||||||
return nil, errParsingInt
|
return nil, errParsingInt
|
||||||
}
|
}
|
||||||
|
log.Debug("documentToken %v", string(m.Bytes))
|
||||||
op := &Operation{OperationType: DocumentFilter, Value: number, StringValue: numberString}
|
op := &Operation{OperationType: DocumentFilter, Value: number, StringValue: numberString}
|
||||||
return &Token{TokenType: OperationToken, Operation: op, CheckForPostTraverse: true}, nil
|
return &Token{TokenType: OperationToken, Operation: op, CheckForPostTraverse: true}, nil
|
||||||
}
|
}
|
||||||
@ -93,6 +89,7 @@ func opAssignableToken(opType *OperationType, assignOpType *OperationType) lex.A
|
|||||||
|
|
||||||
func opTokenWithPrefs(op *OperationType, assignOpType *OperationType, preferences interface{}) lex.Action {
|
func opTokenWithPrefs(op *OperationType, assignOpType *OperationType, preferences interface{}) lex.Action {
|
||||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
log.Debug("opTokenWithPrefs %v", string(m.Bytes))
|
||||||
value := string(m.Bytes)
|
value := string(m.Bytes)
|
||||||
op := &Operation{OperationType: op, Value: op.Type, StringValue: value, Preferences: preferences}
|
op := &Operation{OperationType: op, Value: op.Type, StringValue: value, Preferences: preferences}
|
||||||
var assign *Operation
|
var assign *Operation
|
||||||
@ -187,7 +184,7 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`\(`), literalToken(OpenBracket, false))
|
lexer.Add([]byte(`\(`), literalToken(OpenBracket, false))
|
||||||
lexer.Add([]byte(`\)`), literalToken(CloseBracket, true))
|
lexer.Add([]byte(`\)`), literalToken(CloseBracket, true))
|
||||||
|
|
||||||
lexer.Add([]byte(`\.?\[\]`), literalPathToken("[]"))
|
lexer.Add([]byte(`\.\[\]`), pathToken(false))
|
||||||
lexer.Add([]byte(`\.\.`), opToken(RecursiveDescent))
|
lexer.Add([]byte(`\.\.`), opToken(RecursiveDescent))
|
||||||
|
|
||||||
lexer.Add([]byte(`,`), opToken(Union))
|
lexer.Add([]byte(`,`), opToken(Union))
|
||||||
|
Loading…
Reference in New Issue
Block a user