mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
extracted out operators
This commit is contained in:
parent
23083ed974
commit
8170eec6d1
@ -1,11 +1,14 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/elliotchance/orderedmap"
|
||||
)
|
||||
|
||||
type dataTreeNavigator struct {
|
||||
traverser Traverser
|
||||
leafTraverser LeafTraverser
|
||||
operatorHandlers map[OperationType]OperatorHandler
|
||||
}
|
||||
|
||||
type NavigationPrefs struct {
|
||||
@ -17,8 +20,15 @@ type DataTreeNavigator interface {
|
||||
}
|
||||
|
||||
func NewDataTreeNavigator(navigationPrefs NavigationPrefs) DataTreeNavigator {
|
||||
traverse := NewTraverser(navigationPrefs)
|
||||
return &dataTreeNavigator{traverse}
|
||||
leafTraverser := NewLeafTraverser(navigationPrefs)
|
||||
operatorHandlers := make(map[OperationType]OperatorHandler)
|
||||
|
||||
operatorHandlers[Traverse] = TraverseOperator
|
||||
operatorHandlers[Equals] = EqualsOperator
|
||||
operatorHandlers[Or] = UnionOperator
|
||||
operatorHandlers[And] = IntersectionOperator
|
||||
|
||||
return &dataTreeNavigator{leafTraverser, operatorHandlers}
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) traverse(matchMap *orderedmap.OrderedMap, pathNode *PathElement) (*orderedmap.OrderedMap, error) {
|
||||
@ -28,7 +38,7 @@ func (d *dataTreeNavigator) traverse(matchMap *orderedmap.OrderedMap, pathNode *
|
||||
var err error
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
newNodes, err = d.traverser.Traverse(el.Value.(*CandidateNode), pathNode)
|
||||
newNodes, err = d.leafTraverser.Traverse(el.Value.(*CandidateNode), pathNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -40,73 +50,6 @@ func (d *dataTreeNavigator) traverse(matchMap *orderedmap.OrderedMap, pathNode *
|
||||
return matchingNodeMap, nil
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) equalsOperation(matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
log.Debugf("-- equalsOperation")
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
elMap := orderedmap.NewOrderedMap()
|
||||
elMap.Set(el.Key, el.Value)
|
||||
//need to splat matching nodes, then search through them
|
||||
splatter := &PathTreeNode{PathElement: &PathElement{
|
||||
PathElementType: PathKey,
|
||||
Value: "*",
|
||||
StringValue: "*",
|
||||
}}
|
||||
children, err := d.getMatchingNodes(elMap, splatter)
|
||||
log.Debugf("-- splatted matches, ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for childEl := children.Front(); childEl != nil; childEl = childEl.Next() {
|
||||
childMap := orderedmap.NewOrderedMap()
|
||||
childMap.Set(childEl.Key, childEl.Value)
|
||||
childMatches, errChild := d.getMatchingNodes(childMap, pathNode.Lhs)
|
||||
if errChild != nil {
|
||||
return nil, errChild
|
||||
}
|
||||
|
||||
if d.containsMatchingValue(childMatches, pathNode.Rhs.PathElement.StringValue) {
|
||||
results.Set(childEl.Key, childEl.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) containsMatchingValue(matchMap *orderedmap.OrderedMap, valuePattern string) bool {
|
||||
log.Debugf("-- findMatchingValues")
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
node := el.Value.(*CandidateNode)
|
||||
if Match(node.Node.Value, valuePattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) setFunction(op OperationType, lhs *orderedmap.OrderedMap, rhs *orderedmap.OrderedMap) *orderedmap.OrderedMap {
|
||||
|
||||
if op == Or {
|
||||
for el := rhs.Front(); el != nil; el = el.Next() {
|
||||
node := el.Value.(*CandidateNode)
|
||||
lhs.Set(node.getKey(), node)
|
||||
}
|
||||
return lhs
|
||||
}
|
||||
var matchingNodeMap = orderedmap.NewOrderedMap()
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
_, exists := rhs.Get(el.Key)
|
||||
if exists {
|
||||
matchingNodeMap.Set(el.Key, el.Value)
|
||||
}
|
||||
}
|
||||
return matchingNodeMap
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes []*CandidateNode, pathNode *PathTreeNode) ([]*CandidateNode, error) {
|
||||
var matchingNodeMap = orderedmap.NewOrderedMap()
|
||||
|
||||
@ -132,33 +75,12 @@ func (d *dataTreeNavigator) getMatchingNodes(matchingNodes *orderedmap.OrderedMa
|
||||
if pathNode.PathElement.PathElementType == PathKey || pathNode.PathElement.PathElementType == ArrayIndex {
|
||||
return d.traverse(matchingNodes, pathNode.PathElement)
|
||||
} else {
|
||||
var lhs, rhs *orderedmap.OrderedMap
|
||||
var err error
|
||||
switch pathNode.PathElement.OperationType {
|
||||
case Traverse:
|
||||
lhs, err = d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
handler := d.operatorHandlers[pathNode.PathElement.OperationType]
|
||||
if handler != nil {
|
||||
return handler(d, matchingNodes, pathNode)
|
||||
} else {
|
||||
return nil, fmt.Errorf("Unknown operator %v", pathNode.PathElement.OperationType)
|
||||
}
|
||||
return d.getMatchingNodes(lhs, pathNode.Rhs)
|
||||
case Or, And:
|
||||
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
|
||||
}
|
||||
return d.setFunction(pathNode.PathElement.OperationType, lhs, rhs), nil
|
||||
case Equals:
|
||||
return d.equalsOperation(matchingNodes, pathNode)
|
||||
// case EqualsSelf:
|
||||
// return d.findMatchingValues(matchingNodes, pathNode.Rhs)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,11 +8,11 @@ type traverser struct {
|
||||
prefs NavigationPrefs
|
||||
}
|
||||
|
||||
type Traverser interface {
|
||||
type LeafTraverser interface {
|
||||
Traverse(matchingNode *CandidateNode, pathNode *PathElement) ([]*CandidateNode, error)
|
||||
}
|
||||
|
||||
func NewTraverser(navigationPrefs NavigationPrefs) Traverser {
|
||||
func NewLeafTraverser(navigationPrefs NavigationPrefs) LeafTraverser {
|
||||
return &traverser{navigationPrefs}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var log = logging.MustGetLogger("yq-treeops")
|
||||
|
||||
type CandidateNode struct {
|
||||
Node *yaml.Node // the actual node
|
||||
Path []interface{} /// the path we took to get to this node
|
||||
@ -22,7 +24,19 @@ func (n *CandidateNode) getKey() string {
|
||||
return fmt.Sprintf("%v - %v", n.Document, n.Path)
|
||||
}
|
||||
|
||||
var log = logging.MustGetLogger("yq-treeops")
|
||||
type YqTreeLib interface {
|
||||
Get(rootNode *yaml.Node, path string) ([]*CandidateNode, error)
|
||||
// GetForMerge(rootNode *yaml.Node, path string, arrayMergeStrategy ArrayMergeStrategy) ([]*NodeContext, error)
|
||||
// Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreate bool) error
|
||||
// New(path string) yaml.Node
|
||||
|
||||
// PathStackToString(pathStack []interface{}) string
|
||||
// MergePathStackToString(pathStack []interface{}, arrayMergeStrategy ArrayMergeStrategy) string
|
||||
}
|
||||
|
||||
type lib struct {
|
||||
treeCreator PathTreeCreator
|
||||
}
|
||||
|
||||
func NodeToString(node *CandidateNode) string {
|
||||
if !log.IsEnabledFor(logging.DEBUG) {
|
||||
|
96
pkg/yqlib/treeops/operators.go
Normal file
96
pkg/yqlib/treeops/operators.go
Normal file
@ -0,0 +1,96 @@
|
||||
package treeops
|
||||
|
||||
import "github.com/elliotchance/orderedmap"
|
||||
|
||||
type OperatorHandler func(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error)
|
||||
|
||||
func TraverseOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.getMatchingNodes(lhs, pathNode.Rhs)
|
||||
}
|
||||
|
||||
func UnionOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
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
|
||||
}
|
||||
for el := rhs.Front(); el != nil; el = el.Next() {
|
||||
node := el.Value.(*CandidateNode)
|
||||
lhs.Set(node.getKey(), node)
|
||||
}
|
||||
return lhs, nil
|
||||
}
|
||||
|
||||
func IntersectionOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
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 matchingNodeMap = orderedmap.NewOrderedMap()
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
_, exists := rhs.Get(el.Key)
|
||||
if exists {
|
||||
matchingNodeMap.Set(el.Key, el.Value)
|
||||
}
|
||||
}
|
||||
return matchingNodeMap, nil
|
||||
}
|
||||
|
||||
func EqualsOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
log.Debugf("-- equalsOperation")
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
elMap := orderedmap.NewOrderedMap()
|
||||
elMap.Set(el.Key, el.Value)
|
||||
//need to splat matching nodes, then search through them
|
||||
splatter := &PathTreeNode{PathElement: &PathElement{
|
||||
PathElementType: PathKey,
|
||||
Value: "*",
|
||||
StringValue: "*",
|
||||
}}
|
||||
children, err := d.getMatchingNodes(elMap, splatter)
|
||||
log.Debugf("-- splatted matches, ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for childEl := children.Front(); childEl != nil; childEl = childEl.Next() {
|
||||
childMap := orderedmap.NewOrderedMap()
|
||||
childMap.Set(childEl.Key, childEl.Value)
|
||||
childMatches, errChild := d.getMatchingNodes(childMap, pathNode.Lhs)
|
||||
if errChild != nil {
|
||||
return nil, errChild
|
||||
}
|
||||
|
||||
if containsMatchingValue(childMatches, pathNode.Rhs.PathElement.StringValue) {
|
||||
results.Set(childEl.Key, childEl.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func containsMatchingValue(matchMap *orderedmap.OrderedMap, valuePattern string) bool {
|
||||
log.Debugf("-- findMatchingValues")
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
node := el.Value.(*CandidateNode)
|
||||
if Match(node.Node.Value, valuePattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
Loading…
Reference in New Issue
Block a user