diff --git a/pkg/yqlib/doc/Split into Documents.md b/pkg/yqlib/doc/Split into Documents.md new file mode 100644 index 00000000..a902b43c --- /dev/null +++ b/pkg/yqlib/doc/Split into Documents.md @@ -0,0 +1,31 @@ +# Split into Documents + +This operator splits all matches into separate documents + +## Split empty +Running +```bash +yq eval --null-input 'splitDoc' +``` +will output +```yaml + +``` + +## Split array +Given a sample.yml file of: +```yaml +- a: cat +- b: dog +``` +then +```bash +yq eval '.[] | splitDoc' sample.yml +``` +will output +```yaml +a: cat +--- +b: dog +``` + diff --git a/pkg/yqlib/doc/headers/Split into Documents.md b/pkg/yqlib/doc/headers/Split into Documents.md new file mode 100644 index 00000000..e62712da --- /dev/null +++ b/pkg/yqlib/doc/headers/Split into Documents.md @@ -0,0 +1,3 @@ +# Split into Documents + +This operator splits all matches into separate documents diff --git a/pkg/yqlib/expression_tokeniser.go b/pkg/yqlib/expression_tokeniser.go index 475d0225..5339bd4f 100644 --- a/pkg/yqlib/expression_tokeniser.go +++ b/pkg/yqlib/expression_tokeniser.go @@ -241,6 +241,7 @@ func initLexer() (*lex.Lexer, error) { lexer.Add([]byte(`documentIndex`), opToken(getDocumentIndexOpType)) lexer.Add([]byte(`di`), opToken(getDocumentIndexOpType)) + lexer.Add([]byte(`splitDoc`), opToken(splitDocumentOpType)) lexer.Add([]byte(`style`), opAssignableToken(getStyleOpType, assignStyleOpType)) diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index 976eff7e..f5f9428f 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -51,6 +51,7 @@ var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator} var collectOpType = &operationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: collectOperator} +var splitDocumentOpType = &operationType{Type: "SPLIT_DOC", NumArgs: 0, Precedence: 50, Handler: splitDocumentOperator} var getStyleOpType = &operationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: getStyleOperator} var getTagOpType = &operationType{Type: "GET_TAG", NumArgs: 0, Precedence: 50, Handler: getTagOperator} var getCommentOpType = &operationType{Type: "GET_COMMENT", NumArgs: 0, Precedence: 50, Handler: getCommentsOperator} diff --git a/pkg/yqlib/operator_split_document.go b/pkg/yqlib/operator_split_document.go new file mode 100644 index 00000000..851fa7c0 --- /dev/null +++ b/pkg/yqlib/operator_split_document.go @@ -0,0 +1,18 @@ +package yqlib + +import ( + "container/list" +) + +func splitDocumentOperator(d *dataTreeNavigator, matchMap *list.List, expressionNode *ExpressionNode) (*list.List, error) { + log.Debugf("-- splitDocumentOperator") + + var index uint = 0 + for el := matchMap.Front(); el != nil; el = el.Next() { + candidate := el.Value.(*CandidateNode) + candidate.Document = index + index = index + 1 + } + + return matchMap, nil +} diff --git a/pkg/yqlib/operator_split_document_test.go b/pkg/yqlib/operator_split_document_test.go new file mode 100644 index 00000000..5b2b3c0b --- /dev/null +++ b/pkg/yqlib/operator_split_document_test.go @@ -0,0 +1,32 @@ +package yqlib + +import ( + "testing" +) + +var splitDocOperatorScenarios = []expressionScenario{ + { + description: "Split empty", + document: ``, + expression: `splitDoc`, + expected: []string{ + "D0, P[], (!!null)::\n", + }, + }, + { + description: "Split array", + document: `[{a: cat}, {b: dog}]`, + expression: `.[] | splitDoc`, + expected: []string{ + "D0, P[0], (!!map)::{a: cat}\n", + "D1, P[1], (!!map)::{b: dog}\n", + }, + }, +} + +func TestSplitDocOperatorScenarios(t *testing.T) { + for _, tt := range splitDocOperatorScenarios { + testScenario(t, &tt) + } + documentScenarios(t, "Split into Documents", splitDocOperatorScenarios) +} diff --git a/pkg/yqlib/operators_test.go b/pkg/yqlib/operators_test.go index 904c81ac..71019c15 100644 --- a/pkg/yqlib/operators_test.go +++ b/pkg/yqlib/operators_test.go @@ -55,7 +55,7 @@ func testScenario(t *testing.T, s *expressionScenario) { candidateNode := &CandidateNode{ Document: 0, Filename: "", - Node: &yaml.Node{Tag: "!!null"}, + Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode}, FileIndex: 0, } inputs.PushBack(candidateNode) @@ -245,7 +245,7 @@ func documentOutput(t *testing.T, w *bufio.Writer, s expressionScenario, formatt candidateNode := &CandidateNode{ Document: 0, Filename: "", - Node: &yaml.Node{Tag: "!!null"}, + Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode}, FileIndex: 0, } inputs.PushBack(candidateNode) diff --git a/pkg/yqlib/stream_evaluator.go b/pkg/yqlib/stream_evaluator.go index 355a7ab3..1fc1e0c1 100644 --- a/pkg/yqlib/stream_evaluator.go +++ b/pkg/yqlib/stream_evaluator.go @@ -35,7 +35,7 @@ func (s *streamEvaluator) EvaluateNew(expression string, printer Printer) error candidateNode := &CandidateNode{ Document: 0, Filename: "", - Node: &yaml.Node{Tag: "!!null"}, + Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode}, FileIndex: 0, } inputList := list.New()