mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Fixing readonly ops not to modify context when paths dont exist
This commit is contained in:
parent
afebf0e621
commit
3f51a44596
@ -12,6 +12,14 @@ type Context struct {
|
|||||||
DontAutoCreate bool
|
DontAutoCreate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Context) SingleReadonlyChildContext(candidate *CandidateNode) Context {
|
||||||
|
list := list.New()
|
||||||
|
list.PushBack(candidate)
|
||||||
|
newContext := n.ChildContext(list)
|
||||||
|
newContext.DontAutoCreate = true
|
||||||
|
return newContext
|
||||||
|
}
|
||||||
|
|
||||||
func (n *Context) SingleChildContext(candidate *CandidateNode) Context {
|
func (n *Context) SingleChildContext(candidate *CandidateNode) Context {
|
||||||
list := list.New()
|
list := list.New()
|
||||||
list.PushBack(candidate)
|
list.PushBack(candidate)
|
||||||
|
@ -20,9 +20,6 @@ type operationType struct {
|
|||||||
Handler operatorHandler
|
Handler operatorHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// operators TODO:
|
|
||||||
// - mergeEmpty (sets only if the document is empty, do I do that now?)
|
|
||||||
|
|
||||||
var orOpType = &operationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: orOperator}
|
var orOpType = &operationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: orOperator}
|
||||||
var andOpType = &operationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: andOperator}
|
var andOpType = &operationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: andOperator}
|
||||||
var reduceOpType = &operationType{Type: "REDUCE", NumArgs: 2, Precedence: 35, Handler: reduceOperator}
|
var reduceOpType = &operationType{Type: "REDUCE", NumArgs: 2, Precedence: 35, Handler: reduceOperator}
|
||||||
|
@ -71,7 +71,7 @@ func findBoolean(wantBool bool, d *dataTreeNavigator, context Context, expressio
|
|||||||
if expressionNode != nil {
|
if expressionNode != nil {
|
||||||
//need to evaluate the expression against the node
|
//need to evaluate the expression against the node
|
||||||
candidate := &CandidateNode{Node: node}
|
candidate := &CandidateNode{Node: node}
|
||||||
rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode)
|
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,22 @@ var booleanOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (doc)::a: true\nb: false\n",
|
"D0, P[], (doc)::a: true\nb: false\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[{pet: cat}]`,
|
||||||
|
expression: `any_c(.name == "harry") as $c`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::[{pet: cat}]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[{pet: cat}]`,
|
||||||
|
expression: `all_c(.name == "harry") as $c`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::[{pet: cat}]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[false, false]`,
|
document: `[false, false]`,
|
||||||
|
@ -12,14 +12,21 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
|
|||||||
log.Debugf("-- hasOperation")
|
log.Debugf("-- hasOperation")
|
||||||
var results = list.New()
|
var results = list.New()
|
||||||
|
|
||||||
rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs)
|
readonlyContext := context.Clone()
|
||||||
wanted := rhs.MatchingNodes.Front().Value.(*CandidateNode).Node
|
readonlyContext.DontAutoCreate = true
|
||||||
wantedKey := wanted.Value
|
rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wantedKey := "null"
|
||||||
|
wanted := &yaml.Node{Tag: "!!null"}
|
||||||
|
if rhs.MatchingNodes.Len() != 0 {
|
||||||
|
wanted = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node
|
||||||
|
wantedKey = wanted.Value
|
||||||
|
}
|
||||||
|
|
||||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
|
||||||
|
@ -13,6 +13,22 @@ var hasOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!bool)::true\n",
|
"D0, P[], (!!bool)::true\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: hello`,
|
||||||
|
expression: `has(.b) as $c`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: hello\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a: hello`,
|
||||||
|
expression: `has(.b)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::false\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Has map key",
|
description: "Has map key",
|
||||||
document: `- a: "yes"
|
document: `- a: "yes"
|
||||||
|
@ -11,9 +11,7 @@ func selectOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
|
|||||||
|
|
||||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
childContext := context.SingleChildContext(candidate)
|
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
|
||||||
childContext.DontAutoCreate = true
|
|
||||||
rhs, err := d.GetMatchingNodes(childContext, expressionNode.Rhs)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
|
@ -10,7 +10,7 @@ func sortKeysOperator(d *dataTreeNavigator, context Context, expressionNode *Exp
|
|||||||
|
|
||||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs)
|
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,14 @@ var sortKeysOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (doc)::{a: blah, b: bing, c: frog}\n",
|
"D0, P[], (doc)::{a: blah, b: bing, c: frog}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{c: frog}`,
|
||||||
|
expression: `sortKeys(.d)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{c: frog}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Sort keys recursively",
|
description: "Sort keys recursively",
|
||||||
subdescription: "Note the array elements are left unsorted, but maps inside arrays are sorted",
|
subdescription: "Note the array elements are left unsorted, but maps inside arrays are sorted",
|
||||||
|
@ -13,7 +13,9 @@ func getSubstituteParameters(d *dataTreeNavigator, block *ExpressionNode, contex
|
|||||||
regEx := ""
|
regEx := ""
|
||||||
replacementText := ""
|
replacementText := ""
|
||||||
|
|
||||||
regExNodes, err := d.GetMatchingNodes(context, block.Lhs)
|
readonlyContext := context.Clone()
|
||||||
|
readonlyContext.DontAutoCreate = true
|
||||||
|
regExNodes, err := d.GetMatchingNodes(readonlyContext, block.Lhs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
@ -78,7 +80,9 @@ func joinStringOperator(d *dataTreeNavigator, context Context, expressionNode *E
|
|||||||
log.Debugf("-- joinStringOperator")
|
log.Debugf("-- joinStringOperator")
|
||||||
joinStr := ""
|
joinStr := ""
|
||||||
|
|
||||||
rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs)
|
readonlyContext := context.Clone()
|
||||||
|
readonlyContext.DontAutoCreate = true
|
||||||
|
rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
@ -119,7 +123,9 @@ func splitStringOperator(d *dataTreeNavigator, context Context, expressionNode *
|
|||||||
log.Debugf("-- splitStringOperator")
|
log.Debugf("-- splitStringOperator")
|
||||||
splitStr := ""
|
splitStr := ""
|
||||||
|
|
||||||
rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs)
|
readonlyContext := context.Clone()
|
||||||
|
readonlyContext.DontAutoCreate = true
|
||||||
|
rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,20 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
|
|||||||
var newMatches = orderedmap.NewOrderedMap()
|
var newMatches = orderedmap.NewOrderedMap()
|
||||||
for _, node := range candidateNode.Content {
|
for _, node := range candidateNode.Content {
|
||||||
child := &CandidateNode{Node: node}
|
child := &CandidateNode{Node: node}
|
||||||
rhs, err := d.GetMatchingNodes(context.SingleChildContext(child), expressionNode.Rhs)
|
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(child), expressionNode.Rhs)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyValue := "null"
|
||||||
|
|
||||||
|
if rhs.MatchingNodes.Len() > 0 {
|
||||||
first := rhs.MatchingNodes.Front()
|
first := rhs.MatchingNodes.Front()
|
||||||
keyCandidate := first.Value.(*CandidateNode)
|
keyCandidate := first.Value.(*CandidateNode)
|
||||||
keyValue := keyCandidate.Node.Value
|
keyValue = keyCandidate.Node.Value
|
||||||
|
}
|
||||||
|
|
||||||
_, exists := newMatches.Get(keyValue)
|
_, exists := newMatches.Get(keyValue)
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
|
@ -39,6 +39,22 @@ var uniqueOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::- {name: harry, pet: cat}\n- {name: billy, pet: dog}\n",
|
"D0, P[], (!!seq)::- {name: harry, pet: cat}\n- {name: billy, pet: dog}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]`,
|
||||||
|
expression: `unique_by(.name)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::- {name: harry, pet: cat}\n- {pet: fish}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]`,
|
||||||
|
expression: `unique_by(.cat.dog)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::- {name: harry, pet: cat}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUniqueOperatorScenarios(t *testing.T) {
|
func TestUniqueOperatorScenarios(t *testing.T) {
|
Loading…
x
Reference in New Issue
Block a user