mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-29 02:25:41 +00:00
document index
This commit is contained in:
parent
05520c2168
commit
b290a65602
@ -2,36 +2,10 @@ package yqlib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
yaml "gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var treeNavigator = NewDataTreeNavigator(NavigationPrefs{})
|
|
||||||
var treeCreator = NewPathTreeCreator()
|
var treeCreator = NewPathTreeCreator()
|
||||||
|
|
||||||
func readDoc(t *testing.T, content string) *list.List {
|
|
||||||
inputList := list.New()
|
|
||||||
if content == "" {
|
|
||||||
return inputList
|
|
||||||
}
|
|
||||||
decoder := yaml.NewDecoder(strings.NewReader(content))
|
|
||||||
var dataBucket yaml.Node
|
|
||||||
err := decoder.Decode(&dataBucket)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(content)
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
inputList.PushBack(&CandidateNode{
|
|
||||||
Document: 0,
|
|
||||||
Filename: "test.yml",
|
|
||||||
Node: &dataBucket,
|
|
||||||
})
|
|
||||||
return inputList
|
|
||||||
}
|
|
||||||
|
|
||||||
func resultsToString(results *list.List) []string {
|
func resultsToString(results *list.List) []string {
|
||||||
var pretty []string = make([]string, 0)
|
var pretty []string = make([]string, 0)
|
||||||
for el := results.Front(); el != nil; el = el.Next() {
|
for el := results.Front(); el != nil; el = el.Next() {
|
||||||
|
20
pkg/yqlib/document_index_operator.go
Normal file
20
pkg/yqlib/document_index_operator.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetDocumentIndexOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
var results = list.New()
|
||||||
|
|
||||||
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Document), Tag: "!!int"}
|
||||||
|
scalar := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
||||||
|
results.PushBack(scalar)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
32
pkg/yqlib/document_index_operator_test.go
Normal file
32
pkg/yqlib/document_index_operator_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var documentIndexScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Retrieve a document index",
|
||||||
|
document: "a: cat\n---\na: frog\n",
|
||||||
|
expression: `.a | documentIndex`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!int)::0\n",
|
||||||
|
"D1, P[a], (!!int)::1\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Filter by document index",
|
||||||
|
document: "a: cat\n---\na: frog\n",
|
||||||
|
expression: `select(. | documentIndex == 1)`,
|
||||||
|
expected: []string{
|
||||||
|
"D1, P[], (doc)::a: frog\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDocumentIndexScenarios(t *testing.T) {
|
||||||
|
for _, tt := range documentIndexScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Document Index Operator", documentIndexScenarios)
|
||||||
|
}
|
@ -18,7 +18,6 @@ type OperationType struct {
|
|||||||
|
|
||||||
// operators TODO:
|
// operators TODO:
|
||||||
// - generator doc from operator tests
|
// - generator doc from operator tests
|
||||||
// - set comments not recursive
|
|
||||||
// - documentIndex - retrieves document index, can be used with select
|
// - documentIndex - retrieves document index, can be used with select
|
||||||
// - mergeAppend (merges and appends arrays)
|
// - mergeAppend (merges and appends arrays)
|
||||||
// - mergeEmpty (sets only if the document is empty, do I do that now?)
|
// - mergeEmpty (sets only if the document is empty, do I do that now?)
|
||||||
@ -48,6 +47,7 @@ var Length = &OperationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler:
|
|||||||
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
|
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
|
||||||
var GetStyle = &OperationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: GetStyleOperator}
|
var GetStyle = &OperationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: GetStyleOperator}
|
||||||
var GetComment = &OperationType{Type: "GET_COMMENT", NumArgs: 0, Precedence: 50, Handler: GetCommentsOperator}
|
var GetComment = &OperationType{Type: "GET_COMMENT", NumArgs: 0, Precedence: 50, Handler: GetCommentsOperator}
|
||||||
|
var GetDocumentIndex = &OperationType{Type: "GET_DOCUMENT_INDEX", NumArgs: 0, Precedence: 50, Handler: GetDocumentIndexOperator}
|
||||||
|
|
||||||
var Explode = &OperationType{Type: "EXPLODE", NumArgs: 1, Precedence: 50, Handler: ExplodeOperator}
|
var Explode = &OperationType{Type: "EXPLODE", NumArgs: 1, Precedence: 50, Handler: ExplodeOperator}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mikefarah/yq/v4/test"
|
"github.com/mikefarah/yq/v4/test"
|
||||||
@ -19,14 +20,12 @@ type expressionScenario struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testScenario(t *testing.T, s *expressionScenario) {
|
func testScenario(t *testing.T, s *expressionScenario) {
|
||||||
|
node, errPath := treeCreator.ParsePath(s.expression)
|
||||||
nodes := readDoc(t, s.document)
|
|
||||||
path, errPath := treeCreator.ParsePath(s.expression)
|
|
||||||
if errPath != nil {
|
if errPath != nil {
|
||||||
t.Error(errPath)
|
t.Error(errPath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
results, errNav := treeNavigator.GetMatchingNodes(nodes, path)
|
results, errNav := EvaluateStream("sample.yaml", strings.NewReader(s.document), node)
|
||||||
|
|
||||||
if errNav != nil {
|
if errNav != nil {
|
||||||
t.Error(errNav)
|
t.Error(errNav)
|
||||||
@ -67,14 +66,13 @@ func documentScenarios(t *testing.T, title string, scenarios []expressionScenari
|
|||||||
|
|
||||||
w.WriteString(fmt.Sprintf("Result\n"))
|
w.WriteString(fmt.Sprintf("Result\n"))
|
||||||
|
|
||||||
nodes := readDoc(t, s.document)
|
node, errPath := treeCreator.ParsePath(s.expression)
|
||||||
path, errPath := treeCreator.ParsePath(s.expression)
|
|
||||||
if errPath != nil {
|
if errPath != nil {
|
||||||
t.Error(errPath)
|
t.Error(errPath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var output bytes.Buffer
|
var output bytes.Buffer
|
||||||
results, err := treeNavigator.GetMatchingNodes(nodes, path)
|
results, err := EvaluateStream("sample.yaml", strings.NewReader(s.document), node)
|
||||||
printer.PrintResults(results, bufio.NewWriter(&output))
|
printer.PrintResults(results, bufio.NewWriter(&output))
|
||||||
|
|
||||||
w.WriteString(fmt.Sprintf("```yaml\n%v```\n", output.String()))
|
w.WriteString(fmt.Sprintf("```yaml\n%v```\n", output.String()))
|
||||||
|
@ -191,6 +191,8 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`or`), opToken(Or))
|
lexer.Add([]byte(`or`), opToken(Or))
|
||||||
lexer.Add([]byte(`not`), opToken(Not))
|
lexer.Add([]byte(`not`), opToken(Not))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`documentIndex`), opToken(GetDocumentIndex))
|
||||||
|
|
||||||
lexer.Add([]byte(`style\s*=`), opToken(AssignStyle))
|
lexer.Add([]byte(`style\s*=`), opToken(AssignStyle))
|
||||||
lexer.Add([]byte(`style`), opToken(GetStyle))
|
lexer.Add([]byte(`style`), opToken(GetStyle))
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List, writer io.Writer
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var previousDocIndex uint = 0
|
var previousDocIndex uint = matchingNodes.Front().Value.(*CandidateNode).Document
|
||||||
|
|
||||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
mappedDoc := el.Value.(*CandidateNode)
|
mappedDoc := el.Value.(*CandidateNode)
|
||||||
|
@ -10,7 +10,9 @@ import (
|
|||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readStream(filename string) (*yaml.Decoder, error) {
|
var treeNavigator = NewDataTreeNavigator(NavigationPrefs{})
|
||||||
|
|
||||||
|
func readStream(filename string) (io.Reader, error) {
|
||||||
if filename == "" {
|
if filename == "" {
|
||||||
return nil, errors.New("Must provide filename")
|
return nil, errors.New("Must provide filename")
|
||||||
}
|
}
|
||||||
@ -26,22 +28,15 @@ func readStream(filename string) (*yaml.Decoder, error) {
|
|||||||
defer safelyCloseFile(file)
|
defer safelyCloseFile(file)
|
||||||
stream = file
|
stream = file
|
||||||
}
|
}
|
||||||
return yaml.NewDecoder(stream), nil
|
return stream, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// put this in lib
|
func EvaluateStream(filename string, reader io.Reader, node *PathTreeNode) (*list.List, error) {
|
||||||
func Evaluate(filename string, node *PathTreeNode) (*list.List, error) {
|
|
||||||
|
|
||||||
var treeNavigator = NewDataTreeNavigator(NavigationPrefs{})
|
|
||||||
|
|
||||||
var matchingNodes = list.New()
|
var matchingNodes = list.New()
|
||||||
|
|
||||||
var currentIndex uint = 0
|
var currentIndex uint = 0
|
||||||
var decoder, err = readStream(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
decoder := yaml.NewDecoder(reader)
|
||||||
for {
|
for {
|
||||||
var dataBucket yaml.Node
|
var dataBucket yaml.Node
|
||||||
errorReading := decoder.Decode(&dataBucket)
|
errorReading := decoder.Decode(&dataBucket)
|
||||||
@ -66,8 +61,16 @@ func Evaluate(filename string, node *PathTreeNode) (*list.List, error) {
|
|||||||
matchingNodes.PushBackList(newMatches)
|
matchingNodes.PushBackList(newMatches)
|
||||||
currentIndex = currentIndex + 1
|
currentIndex = currentIndex + 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Evaluate(filename string, node *PathTreeNode) (*list.List, error) {
|
||||||
|
|
||||||
|
var reader, err = readStream(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return EvaluateStream(filename, reader, node)
|
||||||
|
|
||||||
return matchingNodes, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func safelyRenameFile(from string, to string) {
|
func safelyRenameFile(from string, to string) {
|
||||||
|
Loading…
Reference in New Issue
Block a user