diff --git a/pkg/yqlib/operator_add.go b/pkg/yqlib/operator_add.go index a0ca9711..2f850ee0 100644 --- a/pkg/yqlib/operator_add.go +++ b/pkg/yqlib/operator_add.go @@ -39,7 +39,7 @@ func toNodes(candidate *CandidateNode) []*yaml.Node { func addOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("Add operator") - return crossFunction(d, context, expressionNode, add, false) + return crossFunction(d, context.ReadOnlyClone(), expressionNode, add, false) } func add(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { diff --git a/pkg/yqlib/operator_add_test.go b/pkg/yqlib/operator_add_test.go index 74415c79..da7d5852 100644 --- a/pkg/yqlib/operator_add_test.go +++ b/pkg/yqlib/operator_add_test.go @@ -14,6 +14,22 @@ var addOperatorScenarios = []expressionScenario{ "D0, P[1 a], (!!int)::3\n", }, }, + { + skipDoc: true, + document: `{}`, + expression: "(.a + .b) as $x", + expected: []string{ + "D0, P[], (doc)::{}\n", + }, + }, + { + skipDoc: true, + document: `a: 0`, + expression: ".a += .b.c", + expected: []string{ + "D0, P[], (doc)::a: 0\n", + }, + }, { description: "Concatenate and assign arrays", document: `{a: {val: thing, b: [cat,dog]}}`, diff --git a/pkg/yqlib/operator_alternative.go b/pkg/yqlib/operator_alternative.go index 85ae2670..39d084ca 100644 --- a/pkg/yqlib/operator_alternative.go +++ b/pkg/yqlib/operator_alternative.go @@ -2,7 +2,7 @@ package yqlib func alternativeOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("-- alternative") - return crossFunction(d, context, expressionNode, alternativeFunc, true) + return crossFunction(d, context.ReadOnlyClone(), expressionNode, alternativeFunc, true) } func alternativeFunc(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { diff --git a/pkg/yqlib/operator_alternative_test.go b/pkg/yqlib/operator_alternative_test.go index b76c19d2..902fe170 100644 --- a/pkg/yqlib/operator_alternative_test.go +++ b/pkg/yqlib/operator_alternative_test.go @@ -5,6 +5,14 @@ import ( ) var alternativeOperatorScenarios = []expressionScenario{ + { + skipDoc: true, + expression: `(.b // "hello") as $x`, + document: `a: bridge`, + expected: []string{ + "D0, P[], (doc)::a: bridge\n", + }, + }, { description: "LHS is defined", expression: `.a // "hello"`, diff --git a/pkg/yqlib/operator_equals.go b/pkg/yqlib/operator_equals.go index 157baf4d..313c7a4d 100644 --- a/pkg/yqlib/operator_equals.go +++ b/pkg/yqlib/operator_equals.go @@ -4,7 +4,7 @@ import "gopkg.in/yaml.v3" func equalsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("-- equalsOperation") - return crossFunction(d, context, expressionNode, isEquals(false), true) + return crossFunction(d, context.ReadOnlyClone(), expressionNode, isEquals(false), true) } func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { @@ -50,5 +50,5 @@ func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *Candid func notEqualsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("-- notEqualsOperator") - return crossFunction(d, context, expressionNode, isEquals(true), true) + return crossFunction(d, context.ReadOnlyClone(), expressionNode, isEquals(true), true) } diff --git a/pkg/yqlib/operator_equals_test.go b/pkg/yqlib/operator_equals_test.go index 2741fdfc..07cd3cf0 100644 --- a/pkg/yqlib/operator_equals_test.go +++ b/pkg/yqlib/operator_equals_test.go @@ -14,6 +14,38 @@ var equalsOperatorScenarios = []expressionScenario{ "D0, P[], (!!bool)::false\n", }, }, + { + skipDoc: true, + document: "{}", + expression: "(.a == .b) as $x", + expected: []string{ + "D0, P[], (doc)::{}\n", + }, + }, + { + skipDoc: true, + document: "{}", + expression: ".a == .b", + expected: []string{ + "D0, P[], (!!bool)::true\n", + }, + }, + { + skipDoc: true, + document: "{}", + expression: "(.a != .b) as $x", + expected: []string{ + "D0, P[], (doc)::{}\n", + }, + }, + { + skipDoc: true, + document: "{}", + expression: ".a != .b", + expected: []string{ + "D0, P[], (!!bool)::false\n", + }, + }, { skipDoc: true, document: "{a: {b: 10}}", diff --git a/pkg/yqlib/operator_subtract.go b/pkg/yqlib/operator_subtract.go index cb779896..af152771 100644 --- a/pkg/yqlib/operator_subtract.go +++ b/pkg/yqlib/operator_subtract.go @@ -25,7 +25,7 @@ func subtractAssignOperator(d *dataTreeNavigator, context Context, expressionNod func subtractOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("Subtract operator") - return crossFunction(d, context, expressionNode, subtract, false) + return crossFunction(d, context.ReadOnlyClone(), expressionNode, subtract, false) } func subtract(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { diff --git a/pkg/yqlib/operator_subtract_test.go b/pkg/yqlib/operator_subtract_test.go index a78d633d..ba511f1d 100644 --- a/pkg/yqlib/operator_subtract_test.go +++ b/pkg/yqlib/operator_subtract_test.go @@ -5,6 +5,14 @@ import ( ) var subtractOperatorScenarios = []expressionScenario{ + { + skipDoc: true, + document: `{}`, + expression: "(.a - .b) as $x", + expected: []string{ + "D0, P[], (doc)::{}\n", + }, + }, { description: "Number subtraction - float", subdescription: "If the lhs or rhs are floats then the expression will be calculated with floats.", diff --git a/pkg/yqlib/operator_traverse_path.go b/pkg/yqlib/operator_traverse_path.go index c2c82174..d0cb1ec0 100644 --- a/pkg/yqlib/operator_traverse_path.go +++ b/pkg/yqlib/operator_traverse_path.go @@ -89,7 +89,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode // rhs is a collect expression that will yield indexes to retreive of the arrays - rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err diff --git a/pkg/yqlib/operator_traverse_path_test.go b/pkg/yqlib/operator_traverse_path_test.go index b2a31f9a..7b8f4432 100644 --- a/pkg/yqlib/operator_traverse_path_test.go +++ b/pkg/yqlib/operator_traverse_path_test.go @@ -78,6 +78,14 @@ var traversePathOperatorScenarios = []expressionScenario{ "D0, P[flying fox], (!!str)::frog\n", }, }, + { + skipDoc: true, + document: `c: dog`, + expression: `.[.a.b] as $x`, + expected: []string{ + "D0, P[], (doc)::c: dog\n", + }, + }, { description: "Dynamic keys", subdescription: `Expressions within [] can be used to dynamically lookup / calculate keys`,