mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Add filter operation (#1588)
* add filter operation * add tests * add tests * revert debug * simplify filter * fix tests * remove logs
This commit is contained in:
parent
d30941b575
commit
9539877ff6
18
pkg/yqlib/doc/operators/filter.md
Normal file
18
pkg/yqlib/doc/operators/filter.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
## Filter array
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq 'filter(. < 3)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
```
|
||||||
|
|
@ -37,6 +37,7 @@ var participleYqRules = []*participleYqRule{
|
|||||||
|
|
||||||
{"MapValues", `map_?values`, opToken(mapValuesOpType), 0},
|
{"MapValues", `map_?values`, opToken(mapValuesOpType), 0},
|
||||||
simpleOp("map", mapOpType),
|
simpleOp("map", mapOpType),
|
||||||
|
simpleOp("filter", filterOpType),
|
||||||
simpleOp("pick", pickOpType),
|
simpleOp("pick", pickOpType),
|
||||||
|
|
||||||
{"FlattenWithDepth", `flatten\([0-9]+\)`, flattenWithDepth(), 0},
|
{"FlattenWithDepth", `flatten\([0-9]+\)`, flattenWithDepth(), 0},
|
||||||
|
@ -84,6 +84,7 @@ var expressionOpType = &operationType{Type: "EXP", NumArgs: 0, Precedence: 50, H
|
|||||||
|
|
||||||
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
|
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
|
||||||
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
||||||
|
var filterOpType = &operationType{Type: "FILTER", NumArgs: 1, Precedence: 50, Handler: filterOperator}
|
||||||
var errorOpType = &operationType{Type: "ERROR", NumArgs: 1, Precedence: 50, Handler: errorOperator}
|
var errorOpType = &operationType{Type: "ERROR", NumArgs: 1, Precedence: 50, Handler: errorOperator}
|
||||||
var pickOpType = &operationType{Type: "PICK", NumArgs: 1, Precedence: 50, Handler: pickOperator}
|
var pickOpType = &operationType{Type: "PICK", NumArgs: 1, Precedence: 50, Handler: pickOperator}
|
||||||
var evalOpType = &operationType{Type: "EVAL", NumArgs: 1, Precedence: 50, Handler: evalOperator}
|
var evalOpType = &operationType{Type: "EVAL", NumArgs: 1, Precedence: 50, Handler: evalOperator}
|
||||||
|
33
pkg/yqlib/operator_filter.go
Normal file
33
pkg/yqlib/operator_filter.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
func filterOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
log.Debugf("-- filterOperation")
|
||||||
|
var results = list.New()
|
||||||
|
|
||||||
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
children := context.SingleChildContext(candidate)
|
||||||
|
splatted, err := splat(children, traversePreferences{})
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
filtered, err := selectOperator(d, splatted, expressionNode)
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
selfExpression := &ExpressionNode{Operation: &Operation{OperationType: selfReferenceOpType}}
|
||||||
|
collected, err := collectTogether(d, filtered, selfExpression)
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
collected.Node.Style = unwrapDoc(candidate.Node).Style
|
||||||
|
results.PushBack(collected)
|
||||||
|
}
|
||||||
|
return context.ChildContext(results), nil
|
||||||
|
}
|
||||||
|
|
49
pkg/yqlib/operator_filter_test.go
Normal file
49
pkg/yqlib/operator_filter_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var filterOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Filter array",
|
||||||
|
document: `[1,2,3]`,
|
||||||
|
expression: `filter(. < 3)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[1, 2]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[1,2,3]`,
|
||||||
|
expression: `filter(. > 1)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[2, 3]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Filter array to empty",
|
||||||
|
document: `[1,2,3]`,
|
||||||
|
expression: `filter(. > 4)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Filter empty array",
|
||||||
|
document: `[]`,
|
||||||
|
expression: `filter(. > 1)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range filterOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentOperatorScenarios(t, "filter", filterOperatorScenarios)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user