mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-05 15:37:19 +00:00
feat: support arrays in jp items() function (#6180)
This commit is contained in:
parent
04e73e0e2f
commit
7540daa906
2 changed files with 35 additions and 26 deletions
|
@ -450,14 +450,14 @@ func GetFunctions() []*FunctionEntry {
|
||||||
Entry: &gojmespath.FunctionEntry{
|
Entry: &gojmespath.FunctionEntry{
|
||||||
Name: items,
|
Name: items,
|
||||||
Arguments: []ArgSpec{
|
Arguments: []ArgSpec{
|
||||||
{Types: []JpType{JpObject}},
|
{Types: []JpType{JpObject, JpArray}},
|
||||||
{Types: []JpType{JpString}},
|
{Types: []JpType{JpString}},
|
||||||
{Types: []JpType{JpString}},
|
{Types: []JpType{JpString}},
|
||||||
},
|
},
|
||||||
Handler: jpItems,
|
Handler: jpItems,
|
||||||
},
|
},
|
||||||
ReturnType: []JpType{JpArray},
|
ReturnType: []JpType{JpArray},
|
||||||
Note: "converts a map to an array of objects where each key:value is an item in the array",
|
Note: "converts a map or array to an array of objects where each key:value is an item in the array",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Entry: &gojmespath.FunctionEntry{
|
Entry: &gojmespath.FunctionEntry{
|
||||||
|
@ -984,10 +984,6 @@ func jpParseYAML(arguments []interface{}) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func jpItems(arguments []interface{}) (interface{}, error) {
|
func jpItems(arguments []interface{}) (interface{}, error) {
|
||||||
input, ok := arguments[0].(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 0, "Object")
|
|
||||||
}
|
|
||||||
keyName, ok := arguments[1].(string)
|
keyName, ok := arguments[1].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 1, "String")
|
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 1, "String")
|
||||||
|
@ -996,26 +992,34 @@ func jpItems(arguments []interface{}) (interface{}, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 2, "String")
|
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 2, "String")
|
||||||
}
|
}
|
||||||
|
switch input := arguments[0].(type) {
|
||||||
arrayOfObj := make([]map[string]interface{}, 0)
|
case map[string]interface{}:
|
||||||
|
var keys []string
|
||||||
keys := []string{}
|
// Sort the keys so that the output is deterministic
|
||||||
|
for key := range input {
|
||||||
// Sort the keys so that the output is deterministic
|
keys = append(keys, key)
|
||||||
for key := range input {
|
}
|
||||||
keys = append(keys, key)
|
sort.Strings(keys)
|
||||||
|
var arrayOfObj []map[string]interface{}
|
||||||
|
for _, key := range keys {
|
||||||
|
arrayOfObj = append(arrayOfObj, map[string]interface{}{
|
||||||
|
keyName: key,
|
||||||
|
valName: input[key],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return arrayOfObj, nil
|
||||||
|
case []interface{}:
|
||||||
|
var arrayOfObj []map[string]interface{}
|
||||||
|
for index, value := range input {
|
||||||
|
arrayOfObj = append(arrayOfObj, map[string]interface{}{
|
||||||
|
keyName: float64(index),
|
||||||
|
valName: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return arrayOfObj, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 0, "Object")
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
for _, key := range keys {
|
|
||||||
m := make(map[string]interface{})
|
|
||||||
m[keyName] = key
|
|
||||||
m[valName] = input[key]
|
|
||||||
arrayOfObj = append(arrayOfObj, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
return arrayOfObj, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func jpObjectFromLists(arguments []interface{}) (interface{}, error) {
|
func jpObjectFromLists(arguments []interface{}) (interface{}, error) {
|
||||||
|
@ -1068,7 +1072,6 @@ func validateArg(f string, arguments []interface{}, index int, expectedType refl
|
||||||
if arg.Type().Kind() != expectedType {
|
if arg.Type().Kind() != expectedType {
|
||||||
return reflect.Value{}, fmt.Errorf(invalidArgumentTypeError, f, index+1, expectedType.String())
|
return reflect.Value{}, fmt.Errorf(invalidArgumentTypeError, f, index+1, expectedType.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return arg, nil
|
return arg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1349,6 +1349,12 @@ func Test_Items(t *testing.T) {
|
||||||
valName: `"myValue"`,
|
valName: `"myValue"`,
|
||||||
expectedResult: `[{ "myKey": "key1", "myValue": "value1" }, { "myKey": "key2", "myValue": "value2" }]`,
|
expectedResult: `[{ "myKey": "key1", "myValue": "value1" }, { "myKey": "key2", "myValue": "value2" }]`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
object: `["A", "B", "C"]`,
|
||||||
|
keyName: `"myKey"`,
|
||||||
|
valName: `"myValue"`,
|
||||||
|
expectedResult: `[{ "myKey": 0, "myValue": "A" }, { "myKey": 1, "myValue": "B" }, { "myKey": 2, "myValue": "C" }]`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue