From 8b04d972f39a16e37c403c0f01ade67636618638 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Sun, 5 Dec 2021 10:53:37 +1100 Subject: [PATCH] Improved error message --- pkg/yqlib/candidate_node.go | 16 ++++++++++++ pkg/yqlib/doc/headers/sort.md | 2 +- pkg/yqlib/doc/sort.md | 44 ++++++++++++++++++++++++++++++++- pkg/yqlib/operator_sort.go | 2 +- pkg/yqlib/operator_sort_test.go | 17 +++++++++++++ 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/pkg/yqlib/candidate_node.go b/pkg/yqlib/candidate_node.go index 547e955f..428bbeca 100644 --- a/pkg/yqlib/candidate_node.go +++ b/pkg/yqlib/candidate_node.go @@ -3,6 +3,7 @@ package yqlib import ( "container/list" "fmt" + "strings" "github.com/jinzhu/copier" yaml "gopkg.in/yaml.v3" @@ -33,6 +34,21 @@ func (n *CandidateNode) GetKey() string { return fmt.Sprintf("%v%v - %v", keyPrefix, n.Document, n.Path) } +func (n *CandidateNode) GetNiceTag() string { + return unwrapDoc(n.Node).Tag +} + +func (n *CandidateNode) GetNicePath() string { + if n.Path != nil && len(n.Path) >= 0 { + pathStr := make([]string, len(n.Path)) + for i, v := range n.Path { + pathStr[i] = fmt.Sprintf("%v", v) + } + return strings.Join(pathStr, ".") + } + return "" +} + func (n *CandidateNode) AsList() *list.List { elMap := list.New() elMap.PushBack(n) diff --git a/pkg/yqlib/doc/headers/sort.md b/pkg/yqlib/doc/headers/sort.md index 61868e5d..509aca0d 100644 --- a/pkg/yqlib/doc/headers/sort.md +++ b/pkg/yqlib/doc/headers/sort.md @@ -1,5 +1,5 @@ # Sort -Sorts an array. Use `sort` to sort an array as is, or `sort_by` to sort by a particular subfield. +Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield). Note that at this stage, `yq` only sorts scalar fields. diff --git a/pkg/yqlib/doc/sort.md b/pkg/yqlib/doc/sort.md index fbecdefc..4e9d292f 100644 --- a/pkg/yqlib/doc/sort.md +++ b/pkg/yqlib/doc/sort.md @@ -1,6 +1,6 @@ # Sort -Sorts an array. Use `sort` to sort an array as is, or `sort_by` to sort by a particular subfield. +Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield). Note that at this stage, `yq` only sorts scalar fields. @@ -22,6 +22,48 @@ will output - a: cat ``` +## Sort array in place +Given a sample.yml file of: +```yaml +cool: + - a: banana + - a: cat + - a: apple +``` +then +```bash +yq eval '.cool |= sort_by(.a)' sample.yml +``` +will output +```yaml +cool: + - a: apple + - a: banana + - a: cat +``` + +## Sort array of objects by key +Note that you can give sort_by complex expressions, not just paths + +Given a sample.yml file of: +```yaml +cool: + - b: banana + - a: banana + - c: banana +``` +then +```bash +yq eval '.cool |= sort_by(keys | .[0])' sample.yml +``` +will output +```yaml +cool: + - a: banana + - b: banana + - c: banana +``` + ## Sort is stable Note the order of the elements in unchanged when equal in sorting. diff --git a/pkg/yqlib/operator_sort.go b/pkg/yqlib/operator_sort.go index d4070e79..2225c8d6 100644 --- a/pkg/yqlib/operator_sort.go +++ b/pkg/yqlib/operator_sort.go @@ -28,7 +28,7 @@ func sortByOperator(d *dataTreeNavigator, context Context, expressionNode *Expre candidateNode := unwrapDoc(candidate.Node) if candidateNode.Kind != yaml.SequenceNode { - return context, fmt.Errorf("%v is not an array", candidate.GetKey()) + return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.GetNiceTag()) } sortableArray := make(sortableNodeArray, len(candidateNode.Content)) diff --git a/pkg/yqlib/operator_sort_test.go b/pkg/yqlib/operator_sort_test.go index 097a4379..6828d73e 100644 --- a/pkg/yqlib/operator_sort_test.go +++ b/pkg/yqlib/operator_sort_test.go @@ -11,6 +11,23 @@ var sortByOperatorScenarios = []expressionScenario{ "D0, P[], (!!seq)::[{a: apple}, {a: banana}, {a: cat}]\n", }, }, + { + description: "Sort array in place", + document: "cool: [{a: banana},{a: cat},{a: apple}]", + expression: `.cool |= sort_by(.a)`, + expected: []string{ + "D0, P[], (doc)::cool: [{a: apple}, {a: banana}, {a: cat}]\n", + }, + }, + { + description: "Sort array of objects by key", + subdescription: "Note that you can give sort_by complex expressions, not just paths", + document: "cool: [{b: banana},{a: banana},{c: banana}]", + expression: `.cool |= sort_by(keys | .[0])`, + expected: []string{ + "D0, P[], (doc)::cool: [{a: banana}, {b: banana}, {c: banana}]\n", + }, + }, { description: "Sort is stable", subdescription: "Note the order of the elements in unchanged when equal in sorting.",