Sort item criteria to match listmap key order

This commit is contained in:
Tim Hockin
2025-07-17 00:06:41 -07:00
committed by yongruilin
parent 26283acfb1
commit c047bdf58f
3 changed files with 26 additions and 2 deletions

View File

@@ -33,6 +33,13 @@ type Struct struct {
// +k8s:listMapKey=boolKey
// +k8s:item(stringKey: "target", intKey: 42, boolKey: true)=+k8s:validateFalse="item Items[stringKey=target,intKey=42,boolKey=true]"
Items []Item `json:"items"`
// +k8s:listType=map
// +k8s:listMapKey=stringKey
// +k8s:listMapKey=intKey
// +k8s:listMapKey=boolKey
// +k8s:item(boolKey: true, stringKey: "target", intKey: 42)=+k8s:validateFalse="item OutOfOrder[boolKey=42,stringKey=target,intKey=42]"
OutOfOrder []Item `json:"outOfOrder"`
}
type Item struct {

View File

@@ -68,5 +68,19 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
return
}(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *Struct) []Item { return oldObj.Items }))...)
// field Struct.OutOfOrder
errs = append(errs,
func(fldPath *field.Path, obj, oldObj []Item) (errs field.ErrorList) {
// don't revalidate unchanged data
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// call field-attached validations
errs = append(errs, validate.SliceItem(ctx, op, fldPath, obj, oldObj, func(item *Item) bool { return item.StringKey == "target" && item.IntKey == 42 && item.BoolKey == true }, validate.DirectEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Item) field.ErrorList {
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "item OutOfOrder[boolKey=42,stringKey=target,intKey=42]")
})...)
return
}(fldPath.Child("outOfOrder"), obj.OutOfOrder, safe.Field(oldObj, func(oldObj *Struct) []Item { return oldObj.OutOfOrder }))...)
return errs
}

View File

@@ -221,12 +221,13 @@ func (iv itemValidator) GetValidations(context Context) (Validations, error) {
result := Validations{}
for _, item := range itemMeta.items {
if len(item.criteria) != len(listMeta.keyNames) {
return Validations{}, fmt.Errorf("number of arguments does not match number of listMapKey fields")
if narg, nkey := len(item.criteria), len(listMeta.keyNames); narg != nkey {
return Validations{}, fmt.Errorf("number of arguments (%d) does not match number of listMapKey fields (%d)", narg, nkey)
}
// Validate that all listMapKeys are provided and types match
foundKeys := make(map[string]bool)
sorted := make([]keyValuePair, 0, len(listMeta.keyNames))
for _, keyName := range listMeta.keyNames {
for _, pair := range item.criteria {
if pair.key == keyName {
@@ -238,6 +239,7 @@ func (iv itemValidator) GetValidations(context Context) (Validations, error) {
return Validations{}, fmt.Errorf("key %q: %w", pair.key, err)
}
foundKeys[keyName] = true
sorted = append(sorted, pair)
break
}
}
@@ -251,6 +253,7 @@ func (iv itemValidator) GetValidations(context Context) (Validations, error) {
}
return Validations{}, fmt.Errorf("missing required listMapKey fields: %v", missing)
}
item.criteria = sorted
// Extract validations from the stored tag
itemKey := selectorString(item.criteria)