yq/pkg/yqlib/treeops/operator_multilpy.go

99 lines
3.2 KiB
Go
Raw Normal View History

2020-10-19 05:14:29 +00:00
package treeops
import (
"fmt"
"github.com/elliotchance/orderedmap"
"gopkg.in/yaml.v3"
)
2020-10-20 05:27:30 +00:00
type CrossFunctionCalculation func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error)
func crossFunction(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode, calculation CrossFunctionCalculation) (*orderedmap.OrderedMap, error) {
2020-10-19 05:14:29 +00:00
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
if err != nil {
return nil, err
}
rhs, err := d.getMatchingNodes(matchingNodes, pathNode.Rhs)
if err != nil {
return nil, err
}
var results = orderedmap.NewOrderedMap()
for el := lhs.Front(); el != nil; el = el.Next() {
lhsCandidate := el.Value.(*CandidateNode)
for rightEl := rhs.Front(); rightEl != nil; rightEl = rightEl.Next() {
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
}
results.Set(resultCandidate.GetKey(), resultCandidate)
}
}
2020-10-20 05:27:30 +00:00
return results, nil
}
func MultiplyOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
log.Debugf("-- MultiplyOperator")
return crossFunction(d, matchingNodes, pathNode, multiply)
2020-10-19 05:14:29 +00:00
}
func multiply(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
2020-10-19 09:05:38 +00:00
if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode ||
(lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) {
2020-10-19 05:14:29 +00:00
var results = orderedmap.NewOrderedMap()
recursiveDecent(d, results, nodeToMap(rhs))
var pathIndexToStartFrom int = 0
if results.Front() != nil {
pathIndexToStartFrom = len(results.Front().Value.(*CandidateNode).Path)
}
for el := results.Front(); el != nil; el = el.Next() {
err := applyAssignment(d, pathIndexToStartFrom, lhs, el.Value.(*CandidateNode))
if err != nil {
return nil, err
}
}
return lhs, nil
}
return nil, fmt.Errorf("Cannot multiply %v with %v", NodeToString(lhs), NodeToString(rhs))
}
func createTraversalTree(path []interface{}) *PathTreeNode {
if len(path) == 0 {
2020-10-20 04:33:20 +00:00
return &PathTreeNode{Operation: &Operation{OperationType: SelfReference}}
2020-10-19 05:14:29 +00:00
} else if len(path) == 1 {
2020-10-20 04:33:20 +00:00
return &PathTreeNode{Operation: &Operation{OperationType: TraversePath, Value: path[0], StringValue: fmt.Sprintf("%v", path[0])}}
2020-10-19 05:14:29 +00:00
}
return &PathTreeNode{
2020-10-20 04:33:20 +00:00
Operation: &Operation{OperationType: Pipe},
2020-10-20 05:27:30 +00:00
Lhs: createTraversalTree(path[0:1]),
Rhs: createTraversalTree(path[1:])}
2020-10-19 05:14:29 +00:00
}
func applyAssignment(d *dataTreeNavigator, pathIndexToStartFrom int, lhs *CandidateNode, rhs *CandidateNode) error {
log.Debugf("merge - applyAssignment lhs %v, rhs: %v", NodeToString(lhs), NodeToString(rhs))
lhsPath := rhs.Path[pathIndexToStartFrom:]
2020-10-20 04:33:20 +00:00
assignmentOp := &Operation{OperationType: AssignAttributes}
2020-10-19 05:14:29 +00:00
if rhs.Node.Kind == yaml.ScalarNode {
assignmentOp.OperationType = Assign
}
2020-10-20 04:33:20 +00:00
rhsOp := &Operation{OperationType: ValueOp, CandidateNode: rhs}
2020-10-19 05:14:29 +00:00
2020-10-20 04:33:20 +00:00
assignmentOpNode := &PathTreeNode{Operation: assignmentOp, Lhs: createTraversalTree(lhsPath), Rhs: &PathTreeNode{Operation: rhsOp}}
2020-10-19 05:14:29 +00:00
_, err := d.getMatchingNodes(nodeToMap(lhs), assignmentOpNode)
return err
}