yq/pkg/yqlib/operator_multiply.go

125 lines
4.0 KiB
Go
Raw Normal View History

2020-11-03 23:48:43 +00:00
package yqlib
2020-10-19 05:14:29 +00:00
import (
"fmt"
2020-10-21 01:54:58 +00:00
"container/list"
2020-11-20 11:57:32 +00:00
yaml "gopkg.in/yaml.v3"
2020-10-19 05:14:29 +00:00
)
type crossFunctionCalculation func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error)
2020-10-20 05:27:30 +00:00
2021-01-12 23:18:53 +00:00
func crossFunction(d *dataTreeNavigator, matchingNodes *list.List, expressionNode *ExpressionNode, calculation crossFunctionCalculation) (*list.List, error) {
lhs, err := d.GetMatchingNodes(matchingNodes, expressionNode.Lhs)
2020-10-19 05:14:29 +00:00
if err != nil {
return nil, err
}
2020-11-20 11:57:32 +00:00
log.Debugf("crossFunction LHS len: %v", lhs.Len())
2020-10-19 05:14:29 +00:00
2021-01-12 23:18:53 +00:00
rhs, err := d.GetMatchingNodes(matchingNodes, expressionNode.Rhs)
2020-10-19 05:14:29 +00:00
if err != nil {
return nil, err
}
2020-11-20 11:57:32 +00:00
log.Debugf("crossFunction RHS len: %v", rhs.Len())
2020-10-19 05:14:29 +00:00
2020-10-21 01:54:58 +00:00
var results = list.New()
2020-10-19 05:14:29 +00:00
for el := lhs.Front(); el != nil; el = el.Next() {
lhsCandidate := el.Value.(*CandidateNode)
for rightEl := rhs.Front(); rightEl != nil; rightEl = rightEl.Next() {
2020-11-20 11:57:32 +00:00
log.Debugf("Applying calc")
2020-10-19 05:14:29 +00:00
rhsCandidate := rightEl.Value.(*CandidateNode)
2020-10-20 05:27:30 +00:00
resultCandidate, err := calculation(d, lhsCandidate, rhsCandidate)
2020-10-19 05:14:29 +00:00
if err != nil {
return nil, err
}
2020-10-21 01:54:58 +00:00
results.PushBack(resultCandidate)
2020-10-19 05:14:29 +00:00
}
}
2020-10-20 05:27:30 +00:00
return results, nil
}
type multiplyPreferences struct {
2020-11-27 23:41:09 +00:00
AppendArrays bool
}
2021-01-12 23:18:53 +00:00
func multiplyOperator(d *dataTreeNavigator, matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error) {
2020-10-20 05:27:30 +00:00
log.Debugf("-- MultiplyOperator")
2021-01-12 23:18:53 +00:00
return crossFunction(d, matchingNodes, expressionNode, multiply(expressionNode.Operation.Preferences.(*multiplyPreferences)))
2020-10-19 05:14:29 +00:00
}
func multiply(preferences *multiplyPreferences) func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
2020-11-27 23:41:09 +00:00
return func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
2021-01-12 23:00:51 +00:00
lhs.Node = unwrapDoc(lhs.Node)
rhs.Node = unwrapDoc(rhs.Node)
2020-11-27 23:41:09 +00:00
log.Debugf("Multipling LHS: %v", lhs.Node.Tag)
log.Debugf("- RHS: %v", rhs.Node.Tag)
2020-10-27 05:45:16 +00:00
2020-11-27 23:41:09 +00:00
shouldAppendArrays := preferences.AppendArrays
2020-10-19 05:14:29 +00:00
2020-11-27 23:41:09 +00:00
if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode ||
(lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) {
var newBlank = lhs.CreateChild(nil, &yaml.Node{})
2020-11-27 23:41:09 +00:00
var newThing, err = mergeObjects(d, newBlank, lhs, false)
if err != nil {
return nil, err
}
return mergeObjects(d, newThing, rhs, shouldAppendArrays)
2020-10-28 02:00:26 +00:00
2020-11-27 23:41:09 +00:00
}
return nil, fmt.Errorf("Cannot multiply %v with %v", lhs.Node.Tag, rhs.Node.Tag)
2020-10-19 05:14:29 +00:00
}
}
2020-11-27 23:41:09 +00:00
func mergeObjects(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode, shouldAppendArrays bool) (*CandidateNode, error) {
2020-10-28 02:00:26 +00:00
var results = list.New()
2020-11-27 23:41:09 +00:00
// shouldn't recurse arrays if appending
prefs := &recursiveDescentPreferences{RecurseArray: !shouldAppendArrays,
TraversePreferences: &traversePreferences{FollowAlias: false}}
2020-12-28 00:24:42 +00:00
err := recursiveDecent(d, results, nodeToMap(rhs), prefs)
2020-11-13 03:07:11 +00:00
if err != nil {
return nil, err
}
2020-10-28 02:00:26 +00:00
var pathIndexToStartFrom int = 0
if results.Front() != nil {
pathIndexToStartFrom = len(results.Front().Value.(*CandidateNode).Path)
}
for el := results.Front(); el != nil; el = el.Next() {
2020-11-27 23:41:09 +00:00
err := applyAssignment(d, pathIndexToStartFrom, lhs, el.Value.(*CandidateNode), shouldAppendArrays)
2020-10-28 02:00:26 +00:00
if err != nil {
return nil, err
}
}
return lhs, nil
}
2020-11-27 23:41:09 +00:00
func applyAssignment(d *dataTreeNavigator, pathIndexToStartFrom int, lhs *CandidateNode, rhs *CandidateNode, shouldAppendArrays bool) error {
2020-10-19 05:14:29 +00:00
log.Debugf("merge - applyAssignment lhs %v, rhs: %v", NodeToString(lhs), NodeToString(rhs))
lhsPath := rhs.Path[pathIndexToStartFrom:]
assignmentOp := &Operation{OperationType: assignAttributesOpType}
2020-10-29 23:56:45 +00:00
if rhs.Node.Kind == yaml.ScalarNode || rhs.Node.Kind == yaml.AliasNode {
assignmentOp.OperationType = assignOpType
2021-01-06 09:22:50 +00:00
assignmentOp.UpdateAssign = false
2020-11-27 23:41:09 +00:00
} else if shouldAppendArrays && rhs.Node.Kind == yaml.SequenceNode {
assignmentOp.OperationType = addAssignOpType
2020-10-19 05:14:29 +00:00
}
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhs}
2020-10-19 05:14:29 +00:00
2021-01-12 23:18:53 +00:00
assignmentOpNode := &ExpressionNode{Operation: assignmentOp, Lhs: createTraversalTree(lhsPath), Rhs: &ExpressionNode{Operation: rhsOp}}
2020-10-19 05:14:29 +00:00
2020-10-27 05:45:16 +00:00
_, err := d.GetMatchingNodes(nodeToMap(lhs), assignmentOpNode)
2020-10-19 05:14:29 +00:00
return err
}