Skip to content

Commit

Permalink
Can specify parent levels #1970
Browse files Browse the repository at this point in the history
  • Loading branch information
mikefarah committed Mar 11, 2024
1 parent 9e9cb65 commit 8a07e3d
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 4 deletions.
37 changes: 37 additions & 0 deletions pkg/yqlib/doc/operators/parent.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,43 @@ fruit: banana
name: sam
```

## N-th parent
You can optionally supply the number of levels to go up for the parent, the default being 1.

Given a sample.yml file of:
```yaml
a:
b:
c: cat
```
then
```bash
yq '.a.b.c | parent(2)' sample.yml
```
will output
```yaml
b:
c: cat
```

## N-th parent - another level
Given a sample.yml file of:
```yaml
a:
b:
c: cat
```
then
```bash
yq '.a.b.c | parent(3)' sample.yml
```
will output
```yaml
a:
b:
c: cat
```

## No parent
Given a sample.yml file of:
```yaml
Expand Down
26 changes: 25 additions & 1 deletion pkg/yqlib/lexer_participle.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ var participleYqRules = []*participleYqRule{

simpleOp("contains", containsOpType),
simpleOp("split", splitStringOpType),
simpleOp("parent", getParentOpType),

{"ParentWithLevel", `parent\([0-9]+\)`, parentWithLevel(), 0},
{"ParentWithDefaultLevel", `parent`, parentWithDefaultLevel(), 0},

simpleOp("keys", keysOpType),
simpleOp("key", getKeyOpType),
Expand Down Expand Up @@ -501,6 +503,28 @@ func numberValue() yqAction {
}
}

func parentWithLevel() yqAction {
return func(rawToken lexer.Token) (*token, error) {
value := rawToken.Value
var level, errParsingInt = extractNumberParameter(value)
if errParsingInt != nil {
return nil, errParsingInt
}

prefs := parentOpPreferences{Level: level}
op := &Operation{OperationType: getParentOpType, Value: getParentOpType.Type, StringValue: value, Preferences: prefs}
return &token{TokenType: operationToken, Operation: op}, nil
}
}

func parentWithDefaultLevel() yqAction {
return func(rawToken lexer.Token) (*token, error) {
prefs := parentOpPreferences{Level: 1}
op := &Operation{OperationType: getParentOpType, Value: getParentOpType.Type, StringValue: getParentOpType.Type, Preferences: prefs}
return &token{TokenType: operationToken, Operation: op}, nil
}
}

func encodeParseIndent(outputFormat *Format) yqAction {
return func(rawToken lexer.Token) (*token, error) {
value := rawToken.Value
Expand Down
21 changes: 18 additions & 3 deletions pkg/yqlib/operator_parent.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,30 @@ package yqlib

import "container/list"

func getParentOperator(_ *dataTreeNavigator, context Context, _ *ExpressionNode) (Context, error) {
type parentOpPreferences struct {
Level int
}

func getParentOperator(_ *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("getParentOperator")

var results = list.New()

prefs := expressionNode.Operation.Preferences.(parentOpPreferences)

for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
if candidate.Parent != nil {
results.PushBack(candidate.Parent)
currentLevel := 0
for currentLevel < prefs.Level && candidate != nil {
log.Debugf("currentLevel: %v, desired: %v", currentLevel, prefs.Level)
log.Debugf("candidate: %v", NodeToString(candidate))
candidate = candidate.Parent
currentLevel++
}

log.Debugf("found candidate: %v", NodeToString(candidate))
if candidate != nil {
results.PushBack(candidate)
}
}

Expand Down
17 changes: 17 additions & 0 deletions pkg/yqlib/operator_parent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@ var parentOperatorScenarios = []expressionScenario{
"D0, P[b], (!!map)::{fruit: banana, name: sam}\n",
},
},
{
description: "N-th parent",
subdescription: "You can optionally supply the number of levels to go up for the parent, the default being 1.",
document: "a:\n b:\n c: cat\n",
expression: `.a.b.c | parent(2)`,
expected: []string{
"D0, P[a], (!!map)::b:\n c: cat\n",
},
},
{
description: "N-th parent - another level",
document: "a:\n b:\n c: cat\n",
expression: `.a.b.c | parent(3)`,
expected: []string{
"D0, P[], (!!map)::a:\n b:\n c: cat\n",
},
},
{
description: "No parent",
document: `{}`,
Expand Down

0 comments on commit 8a07e3d

Please sign in to comment.