From 69a6785bfe1375905a4d67a56c49e59741e45ac0 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Mon, 6 Mar 2023 10:12:32 -0500 Subject: [PATCH] add filter operation --- pkg/yqlib/lexer_participle.go | 1 + pkg/yqlib/lib.go | 4 +++ pkg/yqlib/operator_filter.go | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 pkg/yqlib/operator_filter.go diff --git a/pkg/yqlib/lexer_participle.go b/pkg/yqlib/lexer_participle.go index 33756fef..e6d4d58f 100644 --- a/pkg/yqlib/lexer_participle.go +++ b/pkg/yqlib/lexer_participle.go @@ -37,6 +37,7 @@ var participleYqRules = []*participleYqRule{ {"MapValues", `map_?values`, opToken(mapValuesOpType), 0}, simpleOp("map", mapOpType), + simpleOp("filter", filterOpType), simpleOp("pick", pickOpType), {"FlattenWithDepth", `flatten\([0-9]+\)`, flattenWithDepth(), 0}, diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index 144fed9f..0c4b73bc 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -22,6 +22,9 @@ func InitExpressionParser() { } var log = logging.MustGetLogger("yq-lib") +func init() { + logging.SetLevel(logging.DEBUG, "yq-lib") +} var PrettyPrintExp = `(... | (select(tag != "!!str"), select(tag == "!!str") | select(test("(?i)^(y|yes|n|no|on|off)$") | not)) ) style=""` @@ -84,6 +87,7 @@ var expressionOpType = &operationType{Type: "EXP", NumArgs: 0, Precedence: 50, H var collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator} 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 pickOpType = &operationType{Type: "PICK", NumArgs: 1, Precedence: 50, Handler: pickOperator} var evalOpType = &operationType{Type: "EVAL", NumArgs: 1, Precedence: 50, Handler: evalOperator} diff --git a/pkg/yqlib/operator_filter.go b/pkg/yqlib/operator_filter.go new file mode 100644 index 00000000..55ead973 --- /dev/null +++ b/pkg/yqlib/operator_filter.go @@ -0,0 +1,56 @@ +package yqlib + +import ( + "errors" + "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 + } + + if err != nil { + return Context{}, err + } + + for resultEl := splatted.MatchingNodes.Front(); resultEl != nil; resultEl = resultEl.Next() { + result := resultEl.Value.(*CandidateNode) + childCtx := context.SingleReadonlyChildContext(result) + include, err := d.GetMatchingNodes(childCtx, expressionNode.RHS) + if err != nil { + return Context{}, err + } + var includeResult bool + var errDecoding error + includeEl := include.MatchingNodes.Front() + if includeEl.Next() != nil { + return Context{}, errors.New("Only expected one child") + } + includeVal := includeEl.Value.(*CandidateNode) + includeResult, errDecoding = isTruthy(includeVal) + if errDecoding != nil { + return Context{}, errDecoding + } + log.Debug("isTruthy %v", includeResult) + if includeResult { + selfExpression := &ExpressionNode{Operation: &Operation{OperationType: selfReferenceOpType}} + collected, err := collectTogether(d, childCtx, selfExpression) + if err != nil { + return Context{}, err + } + collected.Node.Style = unwrapDoc(result.Node).Style + results.PushBack(collected) + } + } + } + return context.ChildContext(results), nil +} +