From b4463e29e836acb75ad1376d6c28c2ba5fd74b54 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Thu, 7 Mar 2024 12:02:40 +1100 Subject: [PATCH] Adding a EvaluateAll function to StringEvaluator #1966 --- pkg/yqlib/string_evaluator.go | 61 +++++++++++++----------------- pkg/yqlib/string_evaluator_test.go | 18 ++++++++- pkg/yqlib/utils.go | 4 ++ 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/pkg/yqlib/string_evaluator.go b/pkg/yqlib/string_evaluator.go index 40970ffe..b3e32d84 100644 --- a/pkg/yqlib/string_evaluator.go +++ b/pkg/yqlib/string_evaluator.go @@ -4,19 +4,16 @@ import ( "bufio" "bytes" "container/list" - "errors" - "fmt" - "io" "strings" ) type StringEvaluator interface { Evaluate(expression string, input string, encoder Encoder, decoder Decoder) (string, error) + EvaluateAll(expression string, input string, encoder Encoder, decoder Decoder) (string, error) } type stringEvaluator struct { treeNavigator DataTreeNavigator - fileIndex int } func NewStringEvaluator() StringEvaluator { @@ -25,6 +22,29 @@ func NewStringEvaluator() StringEvaluator { } } +func (s *stringEvaluator) EvaluateAll(expression string, input string, encoder Encoder, decoder Decoder) (string, error) { + reader := bufio.NewReader(strings.NewReader(input)) + var documents *list.List + var results *list.List + var err error + + if documents, err = ReadDocuments(reader, decoder); err != nil { + return "", err + } + + evaluator := NewAllAtOnceEvaluator() + if results, err = evaluator.EvaluateCandidateNodes(expression, documents); err != nil { + return "", err + } + + out := new(bytes.Buffer) + printer := NewPrinter(encoder, NewSinglePrinterWriter(out)) + if err := printer.PrintResults(results); err != nil { + return "", err + } + return out.String(), nil +} + func (s *stringEvaluator) Evaluate(expression string, input string, encoder Encoder, decoder Decoder) (string, error) { // Use bytes.Buffer for output of string @@ -38,36 +58,9 @@ func (s *stringEvaluator) Evaluate(expression string, input string, encoder Enco } reader := bufio.NewReader(strings.NewReader(input)) - - var currentIndex uint - err = decoder.Init(reader) - if err != nil { + evaluator := NewStreamEvaluator() + if _, err := evaluator.Evaluate("", reader, node, printer, decoder); err != nil { return "", err } - for { - candidateNode, errorReading := decoder.Decode() - - if errors.Is(errorReading, io.EOF) { - s.fileIndex = s.fileIndex + 1 - return out.String(), nil - } else if errorReading != nil { - return "", fmt.Errorf("bad input '%v': %w", input, errorReading) - } - candidateNode.document = currentIndex - candidateNode.fileIndex = s.fileIndex - - inputList := list.New() - inputList.PushBack(candidateNode) - - result, errorParsing := s.treeNavigator.GetMatchingNodes(Context{MatchingNodes: inputList}, node) - if errorParsing != nil { - return "", errorParsing - } - err = printer.PrintResults(result.MatchingNodes) - - if err != nil { - return "", err - } - currentIndex = currentIndex + 1 - } + return out.String(), nil } diff --git a/pkg/yqlib/string_evaluator_test.go b/pkg/yqlib/string_evaluator_test.go index 34906040..17c14c8f 100644 --- a/pkg/yqlib/string_evaluator_test.go +++ b/pkg/yqlib/string_evaluator_test.go @@ -6,6 +6,20 @@ import ( "github.com/mikefarah/yq/v4/test" ) +func TestStringEvaluator_MultipleDocumentMerge(t *testing.T) { + yamlString := "a: Hello\n---\na: Goodbye\n" + expected_output := "a: Goodbye\n" + + encoder := NewYamlEncoder(ConfiguredYamlPreferences) + decoder := NewYamlDecoder(ConfiguredYamlPreferences) + result, err := NewStringEvaluator().EvaluateAll("select(di==0) * select(di==1)", yamlString, encoder, decoder) + if err != nil { + t.Error(err) + } else { + test.AssertResult(t, expected_output, result) + } +} + func TestStringEvaluator_Evaluate_Nominal(t *testing.T) { expected_output := `` + `yq` + "\n" + @@ -24,7 +38,7 @@ func TestStringEvaluator_Evaluate_Nominal(t *testing.T) { result, err := NewStringEvaluator().Evaluate(expression, input, encoder, decoder) if err != nil { t.Error(err) + } else { + test.AssertResult(t, expected_output, result) } - - test.AssertResult(t, expected_output, result) } diff --git a/pkg/yqlib/utils.go b/pkg/yqlib/utils.go index 3ce2de12..4424582a 100644 --- a/pkg/yqlib/utils.go +++ b/pkg/yqlib/utils.go @@ -31,6 +31,10 @@ func writeString(writer io.Writer, txt string) error { return errorWriting } +func ReadDocuments(reader io.Reader, decoder Decoder) (*list.List, error) { + return readDocuments(reader, "", 0, decoder) +} + func readDocuments(reader io.Reader, filename string, fileIndex int, decoder Decoder) (*list.List, error) { err := decoder.Init(reader) if err != nil {