mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-22 01:23:18 +00:00
Pass equiv func to subfield, like item and eachVal
Update comments to be similar. Co-Authored-by: Yongrui Lin <yongrlin@outlook.com>
This commit is contained in:
@@ -169,3 +169,18 @@ func SemanticDeepEqual[T any](a, b T) bool {
|
||||
func DirectEqual[T comparable](a, b T) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
// DirectEqualPtr is a MatchFunc that dereferences two pointers and uses the ==
|
||||
// operator to compare the values. If both pointers are nil, it returns true.
|
||||
// If one pointer is nil and the other is not, it returns false.
|
||||
// It can be used by any other function that needs to compare two pointees
|
||||
// directly.
|
||||
func DirectEqualPtr[T comparable](a, b *T) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
return *a == *b
|
||||
}
|
||||
|
||||
@@ -26,16 +26,21 @@ import (
|
||||
// MatchItemFn takes a pointer to an item and returns true if it matches the criteria.
|
||||
type MatchItemFn[T any] func(*T) bool
|
||||
|
||||
// SliceItem finds the first item in newList that satisfies the 'matches' predicate,
|
||||
// and if found, also looks for a matching item in oldList. It then invokes
|
||||
// 'itemValidator' on these items.
|
||||
// The fldPath passed to itemValidator is indexed to the matched item's position in newList.
|
||||
// This function processes only the *first* matching item found in newList.
|
||||
// It assumes that the 'matches' predicate targets a unique identifier (primary key) and
|
||||
// will match at most one element per list.
|
||||
// If this assumption is violated, changes in list order can lead this function
|
||||
// to have inconsistent behavior.
|
||||
// This function does not validate items that were removed (present in oldList but not in newList).
|
||||
// SliceItem finds the first item in newList that satisfies the match function,
|
||||
// and if found, also looks for a matching item in oldList. If the value of the
|
||||
// item is the same as the previous value, as per the equiv function, then no
|
||||
// validation is performed. Otherwise, it invokes 'itemValidator' on these items.
|
||||
//
|
||||
// This function processes only the *first* matching item found in newList. It
|
||||
// assumes that the match functions targets a unique identifier (primary key)
|
||||
// and will match at most one element per list. If this assumption is violated,
|
||||
// changes in list order can lead this function to have inconsistent behavior.
|
||||
//
|
||||
// The fldPath passed to itemValidator is indexed to the matched item's
|
||||
// position in newList.
|
||||
//
|
||||
// This function does not validate items that were removed (present in oldList
|
||||
// but not in newList).
|
||||
func SliceItem[TList ~[]TItem, TItem any](
|
||||
ctx context.Context, op operation.Operation, fldPath *field.Path,
|
||||
newList, oldList TList,
|
||||
|
||||
@@ -27,18 +27,25 @@ import (
|
||||
// nilable value.
|
||||
type GetFieldFunc[Tstruct any, Tfield any] func(*Tstruct) Tfield
|
||||
|
||||
// Subfield validates a subfield of a struct against a validator function.
|
||||
func Subfield[Tstruct any, Tfield any](ctx context.Context, op operation.Operation, fldPath *field.Path, newStruct, oldStruct *Tstruct,
|
||||
fldName string, getField GetFieldFunc[Tstruct, Tfield], validator ValidateFunc[Tfield]) field.ErrorList {
|
||||
// Subfield validates a subfield of a struct against a validator function. If
|
||||
// the value of the subfield is the same as the previous value, as per the
|
||||
// equiv function, then no validation is performed.
|
||||
//
|
||||
// The fldPath passed to the validator includes the subfield name.
|
||||
func Subfield[Tstruct any, Tfield any](
|
||||
ctx context.Context, op operation.Operation, fldPath *field.Path,
|
||||
newStruct, oldStruct *Tstruct,
|
||||
fldName string, getField GetFieldFunc[Tstruct, Tfield],
|
||||
equiv MatchFunc[Tfield],
|
||||
validator ValidateFunc[Tfield],
|
||||
) field.ErrorList {
|
||||
var errs field.ErrorList
|
||||
newVal := getField(newStruct)
|
||||
var oldVal Tfield
|
||||
if oldStruct != nil {
|
||||
oldVal = getField(oldStruct)
|
||||
}
|
||||
// TODO: passing an equiv function to Subfield for direct comparison instead of
|
||||
// SemanticDeepEqual if fields can be compared directly, to improve performance.
|
||||
if op.Type == operation.Update && SemanticDeepEqual(newVal, oldVal) {
|
||||
if op.Type == operation.Update && oldStruct != nil && equiv(newVal, oldVal) {
|
||||
return nil
|
||||
}
|
||||
errs = append(errs, validator(ctx, op, fldPath.Child(fldName), newVal, oldVal)...)
|
||||
|
||||
@@ -70,10 +70,10 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intField", func(o *SubStruct) *int { return &o.IntField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intField", func(o *SubStruct) *int { return &o.IntField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field IntField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intPtrField", func(o *SubStruct) *int { return o.IntPtrField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intPtrField", func(o *SubStruct) *int { return o.IntPtrField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field IntPtrField")
|
||||
})...)
|
||||
return
|
||||
@@ -85,10 +85,10 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
// Validate_StructWithSubfield validates an instance of StructWithSubfield according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_StructWithSubfield(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *StructWithSubfield) (errs field.ErrorList) {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intField", func(o *StructWithSubfield) *int { return &o.IntField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intField", func(o *StructWithSubfield) *int { return &o.IntField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field IntField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intPtrField", func(o *StructWithSubfield) *int { return o.IntPtrField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "intPtrField", func(o *StructWithSubfield) *int { return o.IntPtrField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *int) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field IntPtrField")
|
||||
})...)
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.SliceItem(ctx, op, fldPath, obj, oldObj, func(item *Item) bool { return item.Key1 == "a" }, validate.DirectEqual, validate.ImmutableByCompare)...)
|
||||
errs = append(errs, validate.SliceItem(ctx, op, fldPath, obj, oldObj, func(item *Item) bool { return item.Key1 == "b" }, validate.DirectEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Item) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *Item) *string { return &o.StringField }, validate.ImmutableByCompare)
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *Item) *string { return &o.StringField }, validate.DirectEqualPtr, validate.ImmutableByCompare)
|
||||
})...)
|
||||
return
|
||||
}(fldPath.Child("listField"), obj.ListField, safe.Field(oldObj, func(oldObj *Struct) []Item { return oldObj.ListField }))...)
|
||||
|
||||
@@ -63,7 +63,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.SliceItem(ctx, op, fldPath, obj, oldObj, func(item *Item) bool { return item.Key == "target" }, validate.DirectEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Item) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *Item) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *Item) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "item Items[key=target].stringField")
|
||||
})
|
||||
})...)
|
||||
@@ -79,7 +79,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.SliceItem(ctx, op, fldPath, obj, oldObj, func(item *RatchetItem) bool { return item.Key == "ratchet" }, validate.DirectEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *RatchetItem) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "status", func(o *RatchetItem) *string { return &o.Status }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "status", func(o *RatchetItem) *string { return &o.Status }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.NEQ(ctx, op, fldPath, obj, oldObj, "forbidden")
|
||||
})
|
||||
})...)
|
||||
|
||||
@@ -62,7 +62,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *InnerStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *InnerStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.NEQ(ctx, op, fldPath, obj, oldObj, "disallowed-subfield")
|
||||
})...)
|
||||
return
|
||||
@@ -79,7 +79,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
return // do not proceed
|
||||
}
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *InnerStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *InnerStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.NEQ(ctx, op, fldPath, obj, oldObj, "disallowed-subfield-ptr")
|
||||
})...)
|
||||
return
|
||||
@@ -157,7 +157,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
// Validate_ValidatedInnerStruct validates an instance of ValidatedInnerStruct according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_ValidatedInnerStruct(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *ValidatedInnerStruct) (errs field.ErrorList) {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *ValidatedInnerStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *ValidatedInnerStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.NEQ(ctx, op, fldPath, obj, oldObj, "disallowed-typedef-struct")
|
||||
})...)
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.IfOption(ctx, op, fldPath, obj, oldObj, "FeatureX", true, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *ObjectMeta) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "xEnabledField", func(o *ObjectMeta) *string { return &o.XEnabledField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "xEnabledField", func(o *ObjectMeta) *string { return &o.XEnabledField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.ObjectMeta.XEnabledField")
|
||||
})
|
||||
})...)
|
||||
|
||||
@@ -62,21 +62,21 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "StructField.StructField")
|
||||
})
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []SmallStruct { return o.SliceField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []SmallStruct) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []SmallStruct { return o.SliceField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []SmallStruct) field.ErrorList {
|
||||
return validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "StructField.SliceField")
|
||||
})
|
||||
})
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]SmallStruct { return o.MapField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]SmallStruct) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]SmallStruct { return o.MapField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]SmallStruct) field.ErrorList {
|
||||
return validate.EachMapVal(ctx, op, fldPath, obj, oldObj, validate.DirectEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "StructField.MapField")
|
||||
})
|
||||
})
|
||||
@@ -92,21 +92,21 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "StructPtrField.StructField")
|
||||
})
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []SmallStruct { return o.SliceField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []SmallStruct) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []SmallStruct { return o.SliceField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []SmallStruct) field.ErrorList {
|
||||
return validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "StructPtrField.SliceField")
|
||||
})
|
||||
})
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]SmallStruct { return o.MapField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]SmallStruct) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]SmallStruct { return o.MapField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]SmallStruct) field.ErrorList {
|
||||
return validate.EachMapVal(ctx, op, fldPath, obj, oldObj, validate.DirectEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *SmallStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "StructPtrField.MapField")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -60,7 +60,7 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *other.StructType) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *other.StructType) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.(other.StructType).StringField")
|
||||
})...)
|
||||
return
|
||||
|
||||
@@ -62,19 +62,19 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *OtherStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *OtherStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructField.StringField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "pointerField", func(o *OtherStruct) *string { return o.PointerField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "pointerField", func(o *OtherStruct) *string { return o.PointerField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructField.PointerField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructField.StructField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []string { return o.SliceField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []string { return o.SliceField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructField.SliceField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]string { return o.MapField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]string { return o.MapField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructField.MapField")
|
||||
})...)
|
||||
return
|
||||
@@ -88,19 +88,19 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *OtherStruct) *string { return &o.StringField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "stringField", func(o *OtherStruct) *string { return &o.StringField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructPtrField.StringField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "pointerField", func(o *OtherStruct) *string { return o.PointerField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "pointerField", func(o *OtherStruct) *string { return o.PointerField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructPtrField.PointerField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "structField", func(o *OtherStruct) *SmallStruct { return &o.StructField }, validate.DirectEqualPtr, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *SmallStruct) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructPtrField.StructField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []string { return o.SliceField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "sliceField", func(o *OtherStruct) []string { return o.SliceField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj []string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructPtrField.SliceField")
|
||||
})...)
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]string { return o.MapField }, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]string) field.ErrorList {
|
||||
errs = append(errs, validate.Subfield(ctx, op, fldPath, obj, oldObj, "mapField", func(o *OtherStruct) map[string]string { return o.MapField }, validate.SemanticDeepEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj map[string]string) field.ErrorList {
|
||||
return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "subfield Struct.StructPtrField.MapField")
|
||||
})...)
|
||||
return
|
||||
|
||||
@@ -379,6 +379,7 @@ var (
|
||||
validateEachMapVal = types.Name{Package: libValidationPkg, Name: "EachMapVal"}
|
||||
validateSemanticDeepEqual = types.Name{Package: libValidationPkg, Name: "SemanticDeepEqual"}
|
||||
validateDirectEqual = types.Name{Package: libValidationPkg, Name: "DirectEqual"}
|
||||
validateDirectEqualPtr = types.Name{Package: libValidationPkg, Name: "DirectEqualPtr"}
|
||||
)
|
||||
|
||||
func (evtv eachValTagValidator) GetValidations(context Context, tag codetags.Tag) (Validations, error) {
|
||||
|
||||
@@ -84,26 +84,47 @@ func (stv subfieldTagValidator) GetValidations(context Context, tag codetags.Tag
|
||||
return Validations{}, fmt.Errorf("variable generation is not supported")
|
||||
}
|
||||
|
||||
for _, vfn := range validations.Functions {
|
||||
nilableStructType := context.Type
|
||||
if !util.IsNilableType(nilableStructType) {
|
||||
nilableStructType = types.PointerTo(nilableStructType)
|
||||
}
|
||||
nilableFieldType := submemb.Type
|
||||
fieldExprPrefix := ""
|
||||
if !util.IsNilableType(nilableFieldType) {
|
||||
nilableFieldType = types.PointerTo(nilableFieldType)
|
||||
fieldExprPrefix = "&"
|
||||
}
|
||||
result.Variables = append(result.Variables, validations.Variables...)
|
||||
|
||||
getFn := FunctionLiteral{
|
||||
Parameters: []ParamResult{{"o", nilableStructType}},
|
||||
Results: []ParamResult{{"", nilableFieldType}},
|
||||
}
|
||||
getFn.Body = fmt.Sprintf("return %so.%s", fieldExprPrefix, submemb.Name)
|
||||
f := Function(subfieldTagName, vfn.Flags, validateSubfield, subname, getFn, WrapperFunction{vfn, submemb.Type})
|
||||
result.Functions = append(result.Functions, f)
|
||||
result.Variables = append(result.Variables, validations.Variables...)
|
||||
nilableStructType := context.Type
|
||||
if !util.IsNilableType(nilableStructType) {
|
||||
nilableStructType = types.PointerTo(nilableStructType)
|
||||
}
|
||||
|
||||
nilableFieldType := submemb.Type
|
||||
fieldExprPrefix := ""
|
||||
if !util.IsNilableType(nilableFieldType) {
|
||||
nilableFieldType = types.PointerTo(nilableFieldType)
|
||||
fieldExprPrefix = "&"
|
||||
}
|
||||
|
||||
// getFn is the function that retrieves the subfield value from the
|
||||
// struct.
|
||||
getFn := FunctionLiteral{
|
||||
Parameters: []ParamResult{{"o", nilableStructType}},
|
||||
Results: []ParamResult{{"", nilableFieldType}},
|
||||
}
|
||||
getFn.Body = fmt.Sprintf("return %so.%s", fieldExprPrefix, submemb.Name)
|
||||
|
||||
// equivArg is the function that is used to compare the correlated
|
||||
// elements in the old and new lists, for ratcheting.
|
||||
var equivArg any
|
||||
|
||||
// directComparable is used to determine whether we can use the direct
|
||||
// comparison operator "==" or need to use the semantic DeepEqual when
|
||||
// looking up and comparing correlated list elements for validation ratcheting.
|
||||
directComparable := util.IsDirectComparable(util.NonPointer(util.NativeType(submemb.Type)))
|
||||
if directComparable {
|
||||
// It must be a pointer, since other nilable types are not directly
|
||||
// comparable.
|
||||
equivArg = Identifier(validateDirectEqualPtr)
|
||||
} else {
|
||||
equivArg = Identifier(validateSemanticDeepEqual)
|
||||
}
|
||||
|
||||
for _, vfn := range validations.Functions {
|
||||
f := Function(subfieldTagName, vfn.Flags, validateSubfield, subname, getFn, equivArg, WrapperFunction{vfn, submemb.Type})
|
||||
result.AddFunction(f)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
|
||||
Reference in New Issue
Block a user