Unique now works on maps and arrays #2068

This commit is contained in:
Mike Farah 2024-06-15 17:04:48 +10:00
parent 1147113fd3
commit 42120e1341
3 changed files with 84 additions and 9 deletions

View File

@ -63,7 +63,29 @@ will output
- ~
```
## Unique array object fields
## Unique array objects
Given a sample.yml file of:
```yaml
- name: harry
pet: cat
- name: billy
pet: dog
- name: harry
pet: cat
```
then
```bash
yq 'unique' sample.yml
```
will output
```yaml
- name: harry
pet: cat
- name: billy
pet: dog
```
## Unique array of objects by a field
Given a sample.yml file of:
```yaml
- name: harry
@ -85,3 +107,25 @@ will output
pet: dog
```
## Unique array of arrays
Given a sample.yml file of:
```yaml
- - cat
- dog
- - cat
- sheep
- - cat
- dog
```
then
```bash
yq 'unique' sample.yml
```
will output
```yaml
- - cat
- dog
- - cat
- sheep
```

View File

@ -23,7 +23,7 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
candidate := el.Value.(*CandidateNode)
if candidate.Kind != SequenceNode {
return Context{}, fmt.Errorf("Only arrays are supported for unique")
return Context{}, fmt.Errorf("only arrays are supported for unique")
}
var newMatches = orderedmap.NewOrderedMap()
@ -34,12 +34,9 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
return Context{}, err
}
keyValue := "null"
if rhs.MatchingNodes.Len() > 0 {
first := rhs.MatchingNodes.Front()
keyCandidate := first.Value.(*CandidateNode)
keyValue = keyCandidate.Value
keyValue, err := getUniqueKeyValue(rhs)
if err != nil {
return Context{}, err
}
_, exists := newMatches.Get(keyValue)
@ -59,3 +56,21 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
return context.ChildContext(results), nil
}
func getUniqueKeyValue(rhs Context) (string, error) {
keyValue := "null"
if rhs.MatchingNodes.Len() > 0 {
first := rhs.MatchingNodes.Front()
keyCandidate := first.Value.(*CandidateNode)
keyValue = keyCandidate.Value
if keyCandidate.Kind != ScalarNode {
var err error
keyValue, err = encodeToString(keyCandidate, encoderPreferences{YamlFormat, 0})
if err != nil {
return "", err
}
}
}
return keyValue, nil
}

View File

@ -33,13 +33,29 @@ var uniqueOperatorScenarios = []expressionScenario{
},
},
{
description: "Unique array object fields",
description: "Unique array objects",
document: `[{name: harry, pet: cat}, {name: billy, pet: dog}, {name: harry, pet: cat}]`,
expression: `unique`,
expected: []string{
"D0, P[], (!!seq)::[{name: harry, pet: cat}, {name: billy, pet: dog}]\n",
},
},
{
description: "Unique array of objects by a field",
document: `[{name: harry, pet: cat}, {name: billy, pet: dog}, {name: harry, pet: dog}]`,
expression: `unique_by(.name)`,
expected: []string{
"D0, P[], (!!seq)::[{name: harry, pet: cat}, {name: billy, pet: dog}]\n",
},
},
{
description: "Unique array of arrays",
document: `[[cat,dog], [cat, sheep], [cat,dog]]`,
expression: `unique`,
expected: []string{
"D0, P[], (!!seq)::[[cat, dog], [cat, sheep]]\n",
},
},
{
skipDoc: true,
document: `[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]`,