podman
175 строк · 5.3 Кб
1package validator2
3import (4"context"5"reflect"6)
7
8// StructLevelFunc accepts all values needed for struct level validation
9type StructLevelFunc func(sl StructLevel)10
11// StructLevelFuncCtx accepts all values needed for struct level validation
12// but also allows passing of contextual validation information via context.Context.
13type StructLevelFuncCtx func(ctx context.Context, sl StructLevel)14
15// wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx
16func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {17return func(ctx context.Context, sl StructLevel) {18fn(sl)19}20}
21
22// StructLevel contains all the information and helper functions
23// to validate a struct
24type StructLevel interface {25
26// Validator returns the main validation object, in case one wants to call validations internally.27// this is so you don't have to use anonymous functions to get access to the validate28// instance.29Validator() *Validate30
31// Top returns the top level struct, if any32Top() reflect.Value33
34// Parent returns the current fields parent struct, if any35Parent() reflect.Value36
37// Current returns the current struct.38Current() reflect.Value39
40// ExtractType gets the actual underlying type of field value.41// It will dive into pointers, customTypes and return you the42// underlying value and its kind.43ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool)44
45// ReportError reports an error just by passing the field and tag information46//47// NOTES:48//49// fieldName and altName get appended to the existing namespace that50// validator is on. e.g. pass 'FirstName' or 'Names[0]' depending51// on the nesting52//53// tag can be an existing validation tag or just something you make up54// and process on the flip side it's up to you.55ReportError(field interface{}, fieldName, structFieldName string, tag, param string)56
57// ReportValidationErrors reports an error just by passing ValidationErrors58//59// NOTES:60//61// relativeNamespace and relativeActualNamespace get appended to the62// existing namespace that validator is on.63// e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending64// on the nesting. most of the time they will be blank, unless you validate65// at a level lower the current field depth66ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors)67}
68
69var _ StructLevel = new(validate)70
71// Top returns the top level struct
72//
73// NOTE: this can be the same as the current struct being validated
74// if not is a nested struct.
75//
76// this is only called when within Struct and Field Level validation and
77// should not be relied upon for an accurate value otherwise.
78func (v *validate) Top() reflect.Value {79return v.top80}
81
82// Parent returns the current structs parent
83//
84// NOTE: this can be the same as the current struct being validated
85// if not is a nested struct.
86//
87// this is only called when within Struct and Field Level validation and
88// should not be relied upon for an accurate value otherwise.
89func (v *validate) Parent() reflect.Value {90return v.slflParent91}
92
93// Current returns the current struct.
94func (v *validate) Current() reflect.Value {95return v.slCurrent96}
97
98// Validator returns the main validation object, in case one want to call validations internally.
99func (v *validate) Validator() *Validate {100return v.v101}
102
103// ExtractType gets the actual underlying type of field value.
104func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) {105return v.extractTypeInternal(field, false)106}
107
108// ReportError reports an error just by passing the field and tag information
109func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) {110
111fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false)112
113if len(structFieldName) == 0 {114structFieldName = fieldName115}116
117v.str1 = string(append(v.ns, fieldName...))118
119if v.v.hasTagNameFunc || fieldName != structFieldName {120v.str2 = string(append(v.actualNs, structFieldName...))121} else {122v.str2 = v.str1123}124
125if kind == reflect.Invalid {126
127v.errs = append(v.errs,128&fieldError{129v: v.v,130tag: tag,131actualTag: tag,132ns: v.str1,133structNs: v.str2,134fieldLen: uint8(len(fieldName)),135structfieldLen: uint8(len(structFieldName)),136param: param,137kind: kind,138},139)140return141}142
143v.errs = append(v.errs,144&fieldError{145v: v.v,146tag: tag,147actualTag: tag,148ns: v.str1,149structNs: v.str2,150fieldLen: uint8(len(fieldName)),151structfieldLen: uint8(len(structFieldName)),152value: fv.Interface(),153param: param,154kind: kind,155typ: fv.Type(),156},157)158}
159
160// ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation.
161//
162// NOTE: this function prepends the current namespace to the relative ones.
163func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) {164
165var err *fieldError166
167for i := 0; i < len(errs); i++ {168
169err = errs[i].(*fieldError)170err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...))171err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...))172
173v.errs = append(v.errs, err)174}175}
176