From 7c4cf724687d8e86bb39ca5accccd1289d03e343 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 12 Oct 2020 10:09:13 +1100 Subject: [PATCH] wip --- pkg/yqlib/treeops/data_tree_navigator_test.go | 142 +++++++++++++++++- pkg/yqlib/treeops/delete_operator.go | 4 +- pkg/yqlib/treeops/operators.go | 7 - pkg/yqlib/treeops/path_tokeniser.go | 21 +-- 4 files changed, 150 insertions(+), 24 deletions(-) diff --git a/pkg/yqlib/treeops/data_tree_navigator_test.go b/pkg/yqlib/treeops/data_tree_navigator_test.go index 7d87ebf9..0753eae5 100644 --- a/pkg/yqlib/treeops/data_tree_navigator_test.go +++ b/pkg/yqlib/treeops/data_tree_navigator_test.go @@ -18,7 +18,7 @@ func readDoc(t *testing.T, content string) []*CandidateNode { if err != nil { t.Error(err) } - return []*CandidateNode{&CandidateNode{Node: &dataBucket, Document: 0}} + return []*CandidateNode{&CandidateNode{Node: dataBucket.Content[0], Document: 0}} } func resultsToString(results []*CandidateNode) string { @@ -54,7 +54,7 @@ func TestDataTreeNavigatorSimple(t *testing.T) { test.AssertResult(t, expected, resultsToString(results)) } -func TestDataTreeNavigatorSubtractSimple(t *testing.T) { +func TestDataTreeNavigatorDeleteSimple(t *testing.T) { nodes := readDoc(t, `a: b: apple @@ -79,7 +79,7 @@ func TestDataTreeNavigatorSubtractSimple(t *testing.T) { test.AssertResult(t, expected, resultsToString(results)) } -func TestDataTreeNavigatorSubtractTwice(t *testing.T) { +func TestDataTreeNavigatorDeleteTwice(t *testing.T) { nodes := readDoc(t, `a: b: apple @@ -106,7 +106,7 @@ func TestDataTreeNavigatorSubtractTwice(t *testing.T) { test.AssertResult(t, expected, resultsToString(results)) } -func TestDataTreeNavigatorSubtractWithUnion(t *testing.T) { +func TestDataTreeNavigatorDeleteWithUnion(t *testing.T) { nodes := readDoc(t, `a: b: apple @@ -133,7 +133,7 @@ func TestDataTreeNavigatorSubtractWithUnion(t *testing.T) { test.AssertResult(t, expected, resultsToString(results)) } -func TestDataTreeNavigatorSubtractByIndex(t *testing.T) { +func TestDataTreeNavigatorDeleteByIndex(t *testing.T) { nodes := readDoc(t, `a: - b: apple @@ -160,6 +160,86 @@ func TestDataTreeNavigatorSubtractByIndex(t *testing.T) { test.AssertResult(t, expected, resultsToString(results)) } +func TestDataTreeNavigatorDeleteByFind(t *testing.T) { + + nodes := readDoc(t, `a: + - b: apple + - b: sdfsd + - b: apple`) + + path, errPath := treeCreator.ParsePath("(a .- (* == apple))") + if errPath != nil { + t.Error(errPath) + } + results, errNav := treeNavigator.GetMatchingNodes(nodes, path) + + if errNav != nil { + t.Error(errNav) + } + + expected := ` +-- Node -- + Document 0, path: [a] + Tag: !!seq, Kind: SequenceNode, Anchor: + - b: sdfsd +` + + test.AssertResult(t, expected, resultsToString(results)) +} + +func TestDataTreeNavigatorDeleteArrayByFind(t *testing.T) { + + nodes := readDoc(t, `a: + - apple + - sdfsd + - apple`) + + path, errPath := treeCreator.ParsePath("(a .- (. == apple))") + if errPath != nil { + t.Error(errPath) + } + results, errNav := treeNavigator.GetMatchingNodes(nodes, path) + + if errNav != nil { + t.Error(errNav) + } + + expected := ` +-- Node -- + Document 0, path: [a] + Tag: !!seq, Kind: SequenceNode, Anchor: + - sdfsd +` + + test.AssertResult(t, expected, resultsToString(results)) +} + +func TestDataTreeNavigatorDeleteViaSelf(t *testing.T) { + + nodes := readDoc(t, `- apple +- sdfsd +- apple`) + + path, errPath := treeCreator.ParsePath("(. .- .)") + if errPath != nil { + t.Error(errPath) + } + results, errNav := treeNavigator.GetMatchingNodes(nodes, path) + + if errNav != nil { + t.Error(errNav) + } + + expected := ` +-- Node -- + Document 0, path: [] + Tag: !!seq, Kind: SequenceNode, Anchor: + - sdfsd +` + + test.AssertResult(t, expected, resultsToString(results)) +} + func TestDataTreeNavigatorDeleteAndWrite(t *testing.T) { nodes := readDoc(t, `a: @@ -192,7 +272,7 @@ func TestDataTreeNavigatorDeleteAndWrite(t *testing.T) { test.AssertResult(t, expected, resultsToString(results)) } -func TestDataTreeNavigatorSubtractArray(t *testing.T) { +func TestDataTreeNavigatorDeleteArray(t *testing.T) { nodes := readDoc(t, `a: - b: apple @@ -268,6 +348,56 @@ func TestDataTreeNavigatorSimpleAssign(t *testing.T) { test.AssertResult(t, expected, resultsToString(results)) } +func TestDataTreeNavigatorSimpleAssignSelf(t *testing.T) { + + nodes := readDoc(t, `a: + b: apple`) + + path, errPath := treeCreator.ParsePath("a(. == apple)(. := frog)") + if errPath != nil { + t.Error(errPath) + } + results, errNav := treeNavigator.GetMatchingNodes(nodes, path) + + if errNav != nil { + t.Error(errNav) + } + + expected := ` +-- Node -- + Document 0, path: [a b] + Tag: !!str, Kind: ScalarNode, Anchor: + frog +` + + test.AssertResult(t, expected, resultsToString(results)) +} + +func TestDataTreeNavigatorSimpleAssignByFind(t *testing.T) { + + nodes := readDoc(t, `a: + b: apple`) + + path, errPath := treeCreator.ParsePath("(b == apple) := frog)") + if errPath != nil { + t.Error(errPath) + } + results, errNav := treeNavigator.GetMatchingNodes(nodes, path) + + if errNav != nil { + t.Error(errNav) + } + + expected := ` +-- Node -- + Document 0, path: [a b] + Tag: !!str, Kind: ScalarNode, Anchor: + frog +` + + test.AssertResult(t, expected, resultsToString(results)) +} + func TestDataTreeNavigatorArraySplat(t *testing.T) { nodes := readDoc(t, `- b: apple diff --git a/pkg/yqlib/treeops/delete_operator.go b/pkg/yqlib/treeops/delete_operator.go index de3faf1e..c86354a5 100644 --- a/pkg/yqlib/treeops/delete_operator.go +++ b/pkg/yqlib/treeops/delete_operator.go @@ -26,8 +26,10 @@ func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *orderedmap.Ordered if candidate.Node.Kind == yaml.SequenceNode { deleteFromArray(candidate, nodesToDelete) - } else { + } else if candidate.Node.Kind == yaml.MappingNode { deleteFromMap(candidate, nodesToDelete) + } else { + log.Debug("Cannot delete from node that's not a map or array %v", NodeToString(candidate)) } } return lhs, nil diff --git a/pkg/yqlib/treeops/operators.go b/pkg/yqlib/treeops/operators.go index 35648359..c2de7180 100644 --- a/pkg/yqlib/treeops/operators.go +++ b/pkg/yqlib/treeops/operators.go @@ -84,17 +84,10 @@ func EqualsOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathN valuePattern := pathNode.Rhs.PathElement.StringValue log.Debug("checking %v", candidate) - // if pathNode.Lhs.PathElement.PathElementType == SelfReference { - // if Match(candidate.Node.Value, valuePattern) { - // results.Set(el.Key, el.Value) - // } - // } else { errInChild := findMatchingChildren(d, results, candidate, pathNode.Lhs, valuePattern) if errInChild != nil { return nil, errInChild } - // } - } return results, nil diff --git a/pkg/yqlib/treeops/path_tokeniser.go b/pkg/yqlib/treeops/path_tokeniser.go index 591ca12b..57bca21c 100644 --- a/pkg/yqlib/treeops/path_tokeniser.go +++ b/pkg/yqlib/treeops/path_tokeniser.go @@ -16,7 +16,7 @@ type Token struct { OperationType OperationType Value interface{} StringValue string - AgainstSelf bool + PrefixSelf bool CheckForPreTraverse bool // this token can sometimes have the traverse '.' missing in frnot of it // e.g. a[1] should really be a.[1] @@ -37,13 +37,13 @@ func pathToken(wrapped bool) lex.Action { func opToken(op OperationType, againstSelf bool) lex.Action { return func(s *lex.Scanner, m *machines.Match) (interface{}, error) { value := string(m.Bytes) - return &Token{PathElementType: Operation, OperationType: op, Value: value, StringValue: value, AgainstSelf: againstSelf}, nil + return &Token{PathElementType: Operation, OperationType: op, Value: value, StringValue: value, PrefixSelf: againstSelf}, nil } } -func literalToken(pType PathElementType, literal string, checkForPre bool, checkForPost bool) lex.Action { +func literalToken(pType PathElementType, literal string, checkForPre bool, checkForPost bool, againstSelf bool) lex.Action { return func(s *lex.Scanner, m *machines.Match) (interface{}, error) { - return &Token{PathElementType: pType, Value: literal, StringValue: literal, CheckForPreTraverse: checkForPre, CheckForPostTraverse: checkForPost}, nil + return &Token{PathElementType: pType, Value: literal, StringValue: literal, CheckForPreTraverse: checkForPre, CheckForPostTraverse: checkForPost, PrefixSelf: againstSelf}, nil } } @@ -68,12 +68,13 @@ func arrayIndextoken(wrapped bool, checkForPre bool, checkForPost bool) lex.Acti // Creates the lexer object and compiles the NFA. func initLexer() (*lex.Lexer, error) { lexer := lex.NewLexer() - lexer.Add([]byte(`\(`), literalToken(OpenBracket, "(", true, false)) - lexer.Add([]byte(`\)`), literalToken(CloseBracket, ")", false, true)) + lexer.Add([]byte(`\(`), literalToken(OpenBracket, "(", true, false, false)) + lexer.Add([]byte(`\)`), literalToken(CloseBracket, ")", false, true, false)) + lexer.Add([]byte(`\.\s*\)`), literalToken(CloseBracket, ")", false, true, true)) - lexer.Add([]byte(`\[\+\]`), literalToken(PathKey, "[+]", true, true)) - lexer.Add([]byte(`\[\*\]`), literalToken(PathKey, "[*]", true, true)) - lexer.Add([]byte(`\*\*`), literalToken(PathKey, "**", false, false)) + lexer.Add([]byte(`\[\+\]`), literalToken(PathKey, "[+]", true, true, false)) + lexer.Add([]byte(`\[\*\]`), literalToken(PathKey, "[*]", true, true, false)) + lexer.Add([]byte(`\*\*`), literalToken(PathKey, "**", false, false, false)) lexer.Add([]byte(`([Oo][Rr])`), opToken(Or, false)) lexer.Add([]byte(`([Aa][Nn][Dd])`), opToken(And, false)) @@ -143,7 +144,7 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) { (tokens[index-1].PathElementType == PathKey || tokens[index-1].PathElementType == CloseBracket) { postProcessedTokens = append(postProcessedTokens, &Token{PathElementType: Operation, OperationType: Traverse, Value: "."}) } - if token.PathElementType == Operation && token.AgainstSelf { + if token.PrefixSelf { postProcessedTokens = append(postProcessedTokens, &Token{PathElementType: SelfReference, Value: "SELF"}) }