mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
wip
This commit is contained in:
parent
6a698332dd
commit
65e6e492cd
2
go.mod
2
go.mod
@ -1,7 +1,7 @@
|
||||
module github.com/mikefarah/yq/v3
|
||||
|
||||
require (
|
||||
github.com/elliotchance/orderedmap v1.3.0
|
||||
github.com/elliotchance/orderedmap v1.3.0 // indirect
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/goccy/go-yaml v1.8.1
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
|
@ -3,7 +3,8 @@ package treeops
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
@ -24,10 +25,10 @@ func NewDataTreeNavigator(navigationPrefs NavigationPrefs) DataTreeNavigator {
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes []*CandidateNode, pathNode *PathTreeNode) ([]*CandidateNode, error) {
|
||||
var matchingNodeMap = orderedmap.NewOrderedMap()
|
||||
var matchingNodeMap = list.New()
|
||||
|
||||
for _, n := range matchingNodes {
|
||||
matchingNodeMap.Set(n.GetKey(), n)
|
||||
matchingNodeMap.PushBack(n)
|
||||
}
|
||||
|
||||
matchedNodes, err := d.getMatchingNodes(matchingNodeMap, pathNode)
|
||||
@ -43,7 +44,7 @@ func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes []*CandidateNode, pat
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (d *dataTreeNavigator) getMatchingNodes(matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func (d *dataTreeNavigator) getMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
if pathNode == nil {
|
||||
log.Debugf("getMatchingNodes - nothing to do")
|
||||
return matchingNodes, nil
|
||||
|
@ -2,9 +2,9 @@ package treeops
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@ -22,17 +22,18 @@ var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOpera
|
||||
var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: AndOperator}
|
||||
|
||||
var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: UnionOperator}
|
||||
var Intersection = &OperationType{Type: "INTERSECTION", NumArgs: 2, Precedence: 20, Handler: IntersectionOperator}
|
||||
|
||||
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignOperator}
|
||||
var AssignAttributes = &OperationType{Type: "ASSIGN_ATTRIBUTES", NumArgs: 2, Precedence: 40, Handler: AssignAttributesOperator}
|
||||
var Multiply = &OperationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 40, Handler: MultiplyOperator}
|
||||
|
||||
var Equals = &OperationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: EqualsOperator}
|
||||
var CreateMap = &OperationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 40, Handler: CreateMapOperator}
|
||||
var Pipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 45, Handler: PipeOperator}
|
||||
|
||||
var Length = &OperationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: LengthOperator}
|
||||
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
|
||||
var CollectObject = &OperationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: CollectObjectOperator}
|
||||
var TraversePath = &OperationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
||||
|
||||
var DocumentFilter = &OperationType{Type: "DOCUMENT_FILTER", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
||||
@ -129,7 +130,7 @@ func (l *lib) Get(document int, documentNode *yaml.Node, path string) ([]*Candid
|
||||
}
|
||||
|
||||
//use for debugging only
|
||||
func NodesToString(collection *orderedmap.OrderedMap) string {
|
||||
func NodesToString(collection *list.List) string {
|
||||
if !log.IsEnabledFor(logging.DEBUG) {
|
||||
return ""
|
||||
}
|
||||
|
2
pkg/yqlib/treeops/operation_collection_object_test.go
Normal file
2
pkg/yqlib/treeops/operation_collection_object_test.go
Normal file
@ -0,0 +1,2 @@
|
||||
package treeops
|
||||
|
@ -1,8 +1,8 @@
|
||||
package treeops
|
||||
|
||||
import "github.com/elliotchance/orderedmap"
|
||||
import "container/list"
|
||||
|
||||
func AssignOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func AssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -27,7 +27,7 @@ func AssignOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap,
|
||||
}
|
||||
|
||||
// does not update content or values
|
||||
func AssignAttributesOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func AssignAttributesOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1,7 +1,8 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -23,8 +24,8 @@ func isTruthy(c *CandidateNode) (bool, error) {
|
||||
|
||||
type boolOp func(bool, bool) bool
|
||||
|
||||
func booleanOp(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode, op boolOp) (*orderedmap.OrderedMap, error) {
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
func booleanOp(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode, op boolOp) (*list.List, error) {
|
||||
var results = list.New()
|
||||
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
@ -52,7 +53,7 @@ func booleanOp(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathN
|
||||
}
|
||||
boolResult := createBooleanCandidate(lhsCandidate, op(lhsTrue, rhsTrue))
|
||||
|
||||
results.Set(boolResult.GetKey(), boolResult)
|
||||
results.PushBack(boolResult)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,14 +61,14 @@ func booleanOp(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathN
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func OrOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func OrOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- orOp")
|
||||
return booleanOp(d, matchingNodes, pathNode, func(b1 bool, b2 bool) bool {
|
||||
return b1 || b2
|
||||
})
|
||||
}
|
||||
|
||||
func AndOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func AndOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- AndOp")
|
||||
return booleanOp(d, matchingNodes, pathNode, func(b1 bool, b2 bool) bool {
|
||||
return b1 && b2
|
||||
|
@ -21,6 +21,7 @@ var booleanOperatorScenarios = []expressionScenario{
|
||||
document: `{a: true, b: false}`,
|
||||
expression: `.[] or (false, true)`,
|
||||
expected: []string{
|
||||
"D0, P[a], (!!bool)::true\n",
|
||||
"D0, P[a], (!!bool)::true\n",
|
||||
"D0, P[b], (!!bool)::false\n",
|
||||
"D0, P[b], (!!bool)::true\n",
|
||||
|
@ -1,14 +1,15 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func CollectOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func CollectOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- collectOperation")
|
||||
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
var results = list.New()
|
||||
|
||||
node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
||||
|
||||
@ -26,7 +27,7 @@ func CollectOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, path
|
||||
}
|
||||
|
||||
collectC := &CandidateNode{Node: node, Document: document, Path: path}
|
||||
results.Set(collectC.GetKey(), collectC)
|
||||
results.PushBack(collectC)
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
8
pkg/yqlib/treeops/operator_collect_object.go
Normal file
8
pkg/yqlib/treeops/operator_collect_object.go
Normal file
@ -0,0 +1,8 @@
|
||||
package treeops
|
||||
|
||||
import "container/list"
|
||||
|
||||
func CollectObjectOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- collectObjectOperation")
|
||||
return nil, nil
|
||||
}
|
43
pkg/yqlib/treeops/operator_create_map.go
Normal file
43
pkg/yqlib/treeops/operator_create_map.go
Normal file
@ -0,0 +1,43 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func CreateMapOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- createMapOperation")
|
||||
var path []interface{} = nil
|
||||
var document uint = 0
|
||||
if matchingNodes.Front() != nil {
|
||||
sample := matchingNodes.Front().Value.(*CandidateNode)
|
||||
path = sample.Path
|
||||
document = sample.Document
|
||||
}
|
||||
|
||||
mapPairs, err := crossFunction(d, matchingNodes, pathNode,
|
||||
func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
node := yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
|
||||
log.Debugf("LHS:", lhs.Node.Value)
|
||||
log.Debugf("RHS:", rhs.Node.Value)
|
||||
node.Content = []*yaml.Node{
|
||||
lhs.Node,
|
||||
rhs.Node,
|
||||
}
|
||||
|
||||
return &CandidateNode{Node: &node, Document: document, Path: path}, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//wrap up all the pairs into an array
|
||||
node := yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
||||
for mapPair := mapPairs.Front(); mapPair != nil; mapPair = mapPair.Next() {
|
||||
mapPairCandidate := mapPair.Value.(*CandidateNode)
|
||||
log.Debugf("Collecting %v into sequence", NodeToString(mapPairCandidate))
|
||||
node.Content = append(node.Content, mapPairCandidate.Node)
|
||||
}
|
||||
return nodeToMap(&CandidateNode{Node: &node, Document: document, Path: path}), nil
|
||||
}
|
28
pkg/yqlib/treeops/operator_create_map_test.go
Normal file
28
pkg/yqlib/treeops/operator_create_map_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var createMapOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
document: `{name: Mike, age: 32}`,
|
||||
expression: `.name: .age`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::- Mike: 32\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{name: Mike, pets: [cat, dog]}`,
|
||||
expression: `.name: .pets[]`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::- Mike: cat\n- Mike: dog\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestCreateMapOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range createMapOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -16,8 +17,8 @@ func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *orderedmap.Ordered
|
||||
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
elMap := orderedmap.NewOrderedMap()
|
||||
elMap.Set(candidate.GetKey(), candidate)
|
||||
elMap := list.New()
|
||||
elMap.PushBack(candidate)
|
||||
nodesToDelete, err := d.getMatchingNodes(elMap, pathNode.Rhs)
|
||||
log.Debug("nodesToDelete:\n%v", NodesToString(nodesToDelete))
|
||||
if err != nil {
|
||||
@ -35,7 +36,7 @@ func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *orderedmap.Ordered
|
||||
return lhs, nil
|
||||
}
|
||||
|
||||
func deleteFromMap(candidate *CandidateNode, nodesToDelete *orderedmap.OrderedMap) {
|
||||
func deleteFromMap(candidate *CandidateNode, nodesToDelete *list.List) {
|
||||
log.Debug("deleteFromMap")
|
||||
node := candidate.Node
|
||||
contents := node.Content
|
||||
@ -50,7 +51,8 @@ func deleteFromMap(candidate *CandidateNode, nodesToDelete *orderedmap.OrderedMa
|
||||
Document: candidate.Document,
|
||||
Path: append(candidate.Path, key.Value),
|
||||
}
|
||||
_, shouldDelete := nodesToDelete.Get(childCandidate.GetKey())
|
||||
// _, shouldDelete := nodesToDelete.Get(childCandidate.GetKey())
|
||||
shouldDelete := true
|
||||
|
||||
log.Debugf("shouldDelete %v ? %v", childCandidate.GetKey(), shouldDelete)
|
||||
|
||||
@ -61,7 +63,7 @@ func deleteFromMap(candidate *CandidateNode, nodesToDelete *orderedmap.OrderedMa
|
||||
node.Content = newContents
|
||||
}
|
||||
|
||||
func deleteFromArray(candidate *CandidateNode, nodesToDelete *orderedmap.OrderedMap) {
|
||||
func deleteFromArray(candidate *CandidateNode, nodesToDelete *list.List) {
|
||||
log.Debug("deleteFromArray")
|
||||
node := candidate.Node
|
||||
contents := node.Content
|
||||
@ -70,13 +72,14 @@ func deleteFromArray(candidate *CandidateNode, nodesToDelete *orderedmap.Ordered
|
||||
for index := 0; index < len(contents); index = index + 1 {
|
||||
value := contents[index]
|
||||
|
||||
childCandidate := &CandidateNode{
|
||||
Node: value,
|
||||
Document: candidate.Document,
|
||||
Path: append(candidate.Path, index),
|
||||
}
|
||||
// childCandidate := &CandidateNode{
|
||||
// Node: value,
|
||||
// Document: candidate.Document,
|
||||
// Path: append(candidate.Path, index),
|
||||
// }
|
||||
|
||||
_, shouldDelete := nodesToDelete.Get(childCandidate.GetKey())
|
||||
// _, shouldDelete := nodesToDelete.Get(childCandidate.GetKey())
|
||||
shouldDelete := true
|
||||
if !shouldDelete {
|
||||
newContents = append(newContents, value)
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
)
|
||||
|
||||
func EqualsOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func EqualsOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- equalsOperation")
|
||||
return crossFunction(d, matchingNodes, pathNode, isEquals)
|
||||
}
|
||||
|
@ -5,35 +5,30 @@ import (
|
||||
)
|
||||
|
||||
var equalsOperatorScenarios = []expressionScenario{
|
||||
// {
|
||||
// document: `[cat,goat,dog]`,
|
||||
// expression: `(.[] == "*at")`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!bool)::true\n",
|
||||
// },
|
||||
// }, {
|
||||
// document: `[cat,goat,dog]`,
|
||||
// expression: `.[] | (. == "*at")`,
|
||||
// expected: []string{
|
||||
// "D0, P[0], (!!bool)::true\n",
|
||||
// "D0, P[1], (!!bool)::true\n",
|
||||
// "D0, P[2], (!!bool)::false\n",
|
||||
// },
|
||||
// }, {
|
||||
// document: `[3, 4, 5]`,
|
||||
// expression: `.[] | (. == 4)`,
|
||||
// expected: []string{
|
||||
// "D0, P[0], (!!bool)::false\n",
|
||||
// "D0, P[1], (!!bool)::true\n",
|
||||
// "D0, P[2], (!!bool)::false\n",
|
||||
// },
|
||||
// }, {
|
||||
// document: `a: { cat: {b: apple, c: whatever}, pat: {b: banana} }`,
|
||||
// expression: `.a | (.[].b == "apple")`,
|
||||
// expected: []string{
|
||||
// "D0, P[a], (!!bool)::true\n",
|
||||
// },
|
||||
// },
|
||||
{
|
||||
document: `[cat,goat,dog]`,
|
||||
expression: `.[] | (. == "*at")`,
|
||||
expected: []string{
|
||||
"D0, P[0], (!!bool)::true\n",
|
||||
"D0, P[1], (!!bool)::true\n",
|
||||
"D0, P[2], (!!bool)::false\n",
|
||||
},
|
||||
}, {
|
||||
document: `[3, 4, 5]`,
|
||||
expression: `.[] | (. == 4)`,
|
||||
expected: []string{
|
||||
"D0, P[0], (!!bool)::false\n",
|
||||
"D0, P[1], (!!bool)::true\n",
|
||||
"D0, P[2], (!!bool)::false\n",
|
||||
},
|
||||
}, {
|
||||
document: `a: { cat: {b: apple, c: whatever}, pat: {b: banana} }`,
|
||||
expression: `.a | (.[].b == "apple")`,
|
||||
expected: []string{
|
||||
"D0, P[a cat b], (!!bool)::true\n",
|
||||
"D0, P[a pat b], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: ``,
|
||||
expression: `null == null`,
|
||||
@ -41,13 +36,13 @@ var equalsOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (!!bool)::true\n",
|
||||
},
|
||||
},
|
||||
// {
|
||||
// document: ``,
|
||||
// expression: `null == ~`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!bool)::true\n",
|
||||
// },
|
||||
// },
|
||||
{
|
||||
document: ``,
|
||||
expression: `null == ~`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::true\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestEqualOperatorScenarios(t *testing.T) {
|
||||
|
@ -3,13 +3,14 @@ package treeops
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
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) {
|
||||
func crossFunction(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode, calculation CrossFunctionCalculation) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -21,7 +22,7 @@ func crossFunction(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, p
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
var results = list.New()
|
||||
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
lhsCandidate := el.Value.(*CandidateNode)
|
||||
@ -32,14 +33,14 @@ func crossFunction(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, p
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results.Set(resultCandidate.GetKey(), resultCandidate)
|
||||
results.PushBack(resultCandidate)
|
||||
}
|
||||
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func MultiplyOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func MultiplyOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- MultiplyOperator")
|
||||
return crossFunction(d, matchingNodes, pathNode, multiply)
|
||||
}
|
||||
@ -47,7 +48,7 @@ func MultiplyOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap
|
||||
func multiply(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode ||
|
||||
(lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) {
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
var results = list.New()
|
||||
recursiveDecent(d, results, nodeToMap(rhs))
|
||||
|
||||
var pathIndexToStartFrom int = 0
|
||||
|
@ -1,10 +1,10 @@
|
||||
package treeops
|
||||
|
||||
import "github.com/elliotchance/orderedmap"
|
||||
import "container/list"
|
||||
|
||||
func NotOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func NotOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- notOperation")
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
var results = list.New()
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
@ -14,7 +14,7 @@ func NotOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode
|
||||
return nil, errDecoding
|
||||
}
|
||||
result := createBooleanCandidate(candidate, !truthy)
|
||||
results.Set(result.GetKey(), result)
|
||||
results.PushBack(result)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
)
|
||||
|
||||
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
var results = list.New()
|
||||
|
||||
err := recursiveDecent(d, results, matchMap)
|
||||
if err != nil {
|
||||
@ -15,13 +15,13 @@ func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *orderedmap.Ordered
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func recursiveDecent(d *dataTreeNavigator, results *orderedmap.OrderedMap, matchMap *orderedmap.OrderedMap) error {
|
||||
func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.List) error {
|
||||
splatOperation := &Operation{OperationType: TraversePath, Value: "[]"}
|
||||
splatTreeNode := &PathTreeNode{Operation: splatOperation}
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
results.Set(candidate.GetKey(), candidate)
|
||||
results.PushBack(candidate)
|
||||
|
||||
children, err := TraversePathOperator(d, nodeToMap(candidate), splatTreeNode)
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
)
|
||||
|
||||
func SelectOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func SelectOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
|
||||
log.Debugf("-- selectOperation")
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
var results = list.New()
|
||||
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
@ -29,7 +29,7 @@ func SelectOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap,
|
||||
}
|
||||
|
||||
if includeResult {
|
||||
results.Set(candidate.GetKey(), candidate)
|
||||
results.PushBack(candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package treeops
|
||||
|
||||
import "github.com/elliotchance/orderedmap"
|
||||
import "container/list"
|
||||
|
||||
func SelfOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func SelfOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
return matchMap, nil
|
||||
}
|
||||
|
@ -3,13 +3,14 @@ package treeops
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TraversePathOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func TraversePathOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- Traversing")
|
||||
var matchingNodeMap = orderedmap.NewOrderedMap()
|
||||
var matchingNodeMap = list.New()
|
||||
var newNodes []*CandidateNode
|
||||
var err error
|
||||
|
||||
@ -19,7 +20,7 @@ func TraversePathOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap,
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range newNodes {
|
||||
matchingNodeMap.Set(n.GetKey(), n)
|
||||
matchingNodeMap.PushBack(n)
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +31,7 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, pathNode *Opera
|
||||
log.Debug("Traversing %v", NodeToString(matchingNode))
|
||||
value := matchingNode.Node
|
||||
|
||||
if value.Kind == 0 {
|
||||
if value.Tag == "!!null" {
|
||||
log.Debugf("Guessing kind")
|
||||
// we must ahve added this automatically, lets guess what it should be now
|
||||
switch pathNode.Value.(type) {
|
||||
@ -41,6 +42,7 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, pathNode *Opera
|
||||
log.Debugf("probabel a map")
|
||||
value.Kind = yaml.MappingNode
|
||||
}
|
||||
value.Tag = ""
|
||||
}
|
||||
|
||||
switch value.Kind {
|
||||
@ -110,7 +112,7 @@ func traverseMap(candidate *CandidateNode, pathNode *Operation) ([]*CandidateNod
|
||||
}
|
||||
if len(newMatches) == 0 {
|
||||
//no matches, create one automagically
|
||||
valueNode := &yaml.Node{Tag: "!!null"}
|
||||
valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}
|
||||
node.Content = append(node.Content, &yaml.Node{Kind: yaml.ScalarNode, Value: pathNode.StringValue}, valueNode)
|
||||
newMatches = append(newMatches, &CandidateNode{
|
||||
Node: valueNode,
|
||||
@ -145,7 +147,7 @@ func traverseArray(candidate *CandidateNode, pathNode *Operation) ([]*CandidateN
|
||||
indexToUse := index
|
||||
contentLength := int64(len(candidate.Node.Content))
|
||||
for contentLength <= index {
|
||||
candidate.Node.Content = append(candidate.Node.Content, &yaml.Node{Tag: "!!null"})
|
||||
candidate.Node.Content = append(candidate.Node.Content, &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"})
|
||||
contentLength = int64(len(candidate.Node.Content))
|
||||
}
|
||||
|
||||
|
@ -24,21 +24,21 @@ var traversePathOperatorScenarios = []expressionScenario{
|
||||
document: `{}`,
|
||||
expression: `.a.b`,
|
||||
expected: []string{
|
||||
"D0, P[a b], ()::null\n",
|
||||
"D0, P[a b], (!!null)::null\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{}`,
|
||||
expression: `.[1].a`,
|
||||
expected: []string{
|
||||
"D0, P[1 a], ()::null\n",
|
||||
"D0, P[1 a], (!!null)::null\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{}`,
|
||||
expression: `.a.[1]`,
|
||||
expected: []string{
|
||||
"D0, P[a 1], ()::null\n",
|
||||
"D0, P[a 1], (!!null)::null\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -55,7 +55,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
||||
expected: []string{
|
||||
"D0, P[a cat b], (!!int)::3\n",
|
||||
"D0, P[a mad b], (!!int)::4\n",
|
||||
"D0, P[a fad b], ()::null\n",
|
||||
"D0, P[a fad b], (!!null)::null\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -72,7 +72,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
||||
expected: []string{
|
||||
"D0, P[a cat], (!!str)::apple\n",
|
||||
"D0, P[a mad], (!!str)::things\n",
|
||||
"D0, P[a fad], ()::null\n",
|
||||
"D0, P[a fad], (!!null)::null\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1,8 +1,8 @@
|
||||
package treeops
|
||||
|
||||
import "github.com/elliotchance/orderedmap"
|
||||
import "container/list"
|
||||
|
||||
func UnionOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func UnionOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -13,7 +13,7 @@ func UnionOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, p
|
||||
}
|
||||
for el := rhs.Front(); el != nil; el = el.Next() {
|
||||
node := el.Value.(*CandidateNode)
|
||||
lhs.Set(node.GetKey(), node)
|
||||
lhs.PushBack(node)
|
||||
}
|
||||
return lhs, nil
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package treeops
|
||||
|
||||
import "github.com/elliotchance/orderedmap"
|
||||
import "container/list"
|
||||
|
||||
func ValueOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func ValueOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debug("value = %v", pathNode.Operation.CandidateNode.Node.Value)
|
||||
return nodeToMap(pathNode.Operation.CandidateNode), nil
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
"github.com/elliotchance/orderedmap"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type OperatorHandler func(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error)
|
||||
type OperatorHandler func(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error)
|
||||
|
||||
func PipeOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func PipeOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -26,34 +26,15 @@ func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
|
||||
return &CandidateNode{Node: node, Document: owner.Document, Path: owner.Path}
|
||||
}
|
||||
|
||||
func nodeToMap(candidate *CandidateNode) *orderedmap.OrderedMap {
|
||||
elMap := orderedmap.NewOrderedMap()
|
||||
elMap.Set(candidate.GetKey(), candidate)
|
||||
func nodeToMap(candidate *CandidateNode) *list.List {
|
||||
elMap := list.New()
|
||||
elMap.PushBack(candidate)
|
||||
return elMap
|
||||
}
|
||||
|
||||
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 LengthOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
func LengthOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- lengthOperation")
|
||||
var results = orderedmap.NewOrderedMap()
|
||||
var results = list.New()
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
@ -71,7 +52,7 @@ func LengthOperator(d *dataTreeNavigator, matchMap *orderedmap.OrderedMap, pathN
|
||||
|
||||
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"}
|
||||
lengthCand := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
||||
results.Set(candidate.GetKey(), lengthCand)
|
||||
results.PushBack(lengthCand)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
|
@ -59,6 +59,16 @@ var pathTests = []struct {
|
||||
append(make([]interface{}, 0), "[", "true (bool)", "]"),
|
||||
append(make([]interface{}, 0), "true (bool)", "COLLECT", "PIPE"),
|
||||
},
|
||||
{
|
||||
`"mike": .a`,
|
||||
append(make([]interface{}, 0), "mike (string)", "CREATE_MAP", "a"),
|
||||
append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP"),
|
||||
},
|
||||
{
|
||||
`.a: "mike"`,
|
||||
append(make([]interface{}, 0), "a", "CREATE_MAP", "mike (string)"),
|
||||
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP"),
|
||||
},
|
||||
|
||||
// {".animals | .==cat", append(make([]interface{}, 0), "animals", "TRAVERSE", "SELF", "EQUALS", "cat")},
|
||||
// {".animals | (. == cat)", append(make([]interface{}, 0), "animals", "TRAVERSE", "(", "SELF", "EQUALS", "cat", ")")},
|
||||
|
@ -20,6 +20,8 @@ const (
|
||||
CloseBracket
|
||||
OpenCollect
|
||||
CloseCollect
|
||||
OpenCollectObject
|
||||
CloseCollectObject
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
@ -40,6 +42,10 @@ func (t *Token) toString() string {
|
||||
return "["
|
||||
} else if t.TokenType == CloseCollect {
|
||||
return "]"
|
||||
} else if t.TokenType == OpenCollectObject {
|
||||
return "{"
|
||||
} else if t.TokenType == CloseCollectObject {
|
||||
return "}"
|
||||
} else {
|
||||
return fmt.Sprintf("NFI")
|
||||
}
|
||||
@ -174,6 +180,7 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`\.\.`), opToken(RecursiveDescent))
|
||||
|
||||
lexer.Add([]byte(`,`), opToken(Union))
|
||||
lexer.Add([]byte(`:\s*`), opToken(CreateMap))
|
||||
lexer.Add([]byte(`length`), opToken(Length))
|
||||
lexer.Add([]byte(`select`), opToken(Select))
|
||||
lexer.Add([]byte(`or`), opToken(Or))
|
||||
@ -195,7 +202,7 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`d[0-9]+`), documentToken()) // $0
|
||||
|
||||
lexer.Add([]byte(`\."[^ "]+"`), pathToken(true))
|
||||
lexer.Add([]byte(`\.[^ \[\],\|\.\[\(\)=]+`), pathToken(false))
|
||||
lexer.Add([]byte(`\.[^ \}\{\:\[\],\|\.\[\(\)=]+`), pathToken(false))
|
||||
lexer.Add([]byte(`\.`), selfToken())
|
||||
|
||||
lexer.Add([]byte(`\|`), opToken(Pipe))
|
||||
@ -214,6 +221,8 @@ func initLexer() (*lex.Lexer, error) {
|
||||
|
||||
lexer.Add([]byte(`\[`), literalToken(OpenCollect, false))
|
||||
lexer.Add([]byte(`\]`), literalToken(CloseCollect, true))
|
||||
lexer.Add([]byte(`\{`), literalToken(OpenCollectObject, false))
|
||||
lexer.Add([]byte(`\}`), literalToken(CloseCollectObject, true))
|
||||
lexer.Add([]byte(`\*`), opToken(Multiply))
|
||||
|
||||
// lexer.Add([]byte(`[^ \,\|\.\[\(\)=]+`), stringValue(false))
|
||||
|
@ -1 +1 @@
|
||||
{a: {also: [1]}, b: {also: me}}
|
||||
{name: Mike, pets: [cat, dog]}
|
@ -1,10 +1,7 @@
|
||||
{
|
||||
"a": {
|
||||
"also": [
|
||||
1
|
||||
"name": "Mike",
|
||||
"pets": [
|
||||
"cat",
|
||||
"dog"
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"also": "me"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user