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