diff --git a/pkg/yqlib/context.go b/pkg/yqlib/context.go index 7fb09b56..fd3bdfc0 100644 --- a/pkg/yqlib/context.go +++ b/pkg/yqlib/context.go @@ -42,3 +42,13 @@ func (n *Context) ChildContext(results *list.List) Context { clone.MatchingNodes = results return clone } + +func (n *Context) Clone() Context { + clone := Context{} + err := copier.Copy(&clone, n) + if err != nil { + log.Error("Error cloning context :(") + panic(err) + } + return clone +} diff --git a/pkg/yqlib/operator_delete.go b/pkg/yqlib/operator_delete.go index f28569a9..b9648895 100644 --- a/pkg/yqlib/operator_delete.go +++ b/pkg/yqlib/operator_delete.go @@ -7,8 +7,9 @@ import ( ) func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { - - nodesToDelete, err := d.GetMatchingNodes(context, expressionNode.Rhs) + contextToUse := context.Clone() + contextToUse.DontAutoCreate = true + nodesToDelete, err := d.GetMatchingNodes(contextToUse, expressionNode.Rhs) if err != nil { return Context{}, err @@ -17,19 +18,21 @@ func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode * for el := nodesToDelete.MatchingNodes.Back(); el != nil; el = el.Prev() { candidate := el.Value.(*CandidateNode) - deleteImmediateChildOp := &Operation{ - OperationType: deleteImmediateChildOpType, - Value: candidate.Path[len(candidate.Path)-1], - } + if len(candidate.Path) > 0 { + deleteImmediateChildOp := &Operation{ + OperationType: deleteImmediateChildOpType, + Value: candidate.Path[len(candidate.Path)-1], + } - deleteImmediateChildOpNode := &ExpressionNode{ - Operation: deleteImmediateChildOp, - Rhs: createTraversalTree(candidate.Path[0:len(candidate.Path)-1], traversePreferences{}), - } + deleteImmediateChildOpNode := &ExpressionNode{ + Operation: deleteImmediateChildOp, + Rhs: createTraversalTree(candidate.Path[0:len(candidate.Path)-1], traversePreferences{}), + } - _, err := d.GetMatchingNodes(context, deleteImmediateChildOpNode) - if err != nil { - return Context{}, err + _, err := d.GetMatchingNodes(contextToUse, deleteImmediateChildOpNode) + if err != nil { + return Context{}, err + } } } return context, nil diff --git a/pkg/yqlib/operator_delete_test.go b/pkg/yqlib/operator_delete_test.go index 364f271e..109bc2d8 100644 --- a/pkg/yqlib/operator_delete_test.go +++ b/pkg/yqlib/operator_delete_test.go @@ -53,6 +53,22 @@ var deleteOperatorScenarios = []expressionScenario{ "D0, P[], (doc)::a: [x, x]\n", }, }, + { + skipDoc: true, + document: `a: {thing1: yep, thing2: cool, thing3: hi, b: {thing1: cool, great: huh}}`, + expression: `del(..)`, + expected: []string{ + "D0, P[], (!!map)::{}\n", + }, + }, + { + skipDoc: true, + document: `a: {thing1: yep, thing2: cool, thing3: hi, b: {thing1: cool, great: huh}}`, + expression: `del(.. | select(tag == "!!map") | (.b.thing1,.thing2))`, + expected: []string{ + "D0, P[], (!!map)::a: {thing1: yep, thing3: hi, b: {great: huh}}\n", + }, + }, { description: "Delete nested entry in array", document: `[{a: cat, b: dog}]`,