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: Given a sample.yml file of:
```yaml ```yaml
- name: harry - name: harry
@ -85,3 +107,25 @@ will output
pet: dog 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) candidate := el.Value.(*CandidateNode)
if candidate.Kind != SequenceNode { 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() var newMatches = orderedmap.NewOrderedMap()
@ -34,12 +34,9 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
return Context{}, err return Context{}, err
} }
keyValue := "null" keyValue, err := getUniqueKeyValue(rhs)
if err != nil {
if rhs.MatchingNodes.Len() > 0 { return Context{}, err
first := rhs.MatchingNodes.Front()
keyCandidate := first.Value.(*CandidateNode)
keyValue = keyCandidate.Value
} }
_, exists := newMatches.Get(keyValue) _, exists := newMatches.Get(keyValue)
@ -59,3 +56,21 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
return context.ChildContext(results), nil 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}]`, document: `[{name: harry, pet: cat}, {name: billy, pet: dog}, {name: harry, pet: dog}]`,
expression: `unique_by(.name)`, expression: `unique_by(.name)`,
expected: []string{ expected: []string{
"D0, P[], (!!seq)::[{name: harry, pet: cat}, {name: billy, pet: dog}]\n", "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, skipDoc: true,
document: `[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]`, document: `[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]`,