struct_level.go (5464B)
1 package validator 2 3 import ( 4 "context" 5 "reflect" 6 ) 7 8 // StructLevelFunc accepts all values needed for struct level validation 9 type 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. 13 type StructLevelFuncCtx func(ctx context.Context, sl StructLevel) 14 15 // wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx 16 func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx { 17 return func(ctx context.Context, sl StructLevel) { 18 fn(sl) 19 } 20 } 21 22 // StructLevel contains all the information and helper functions 23 // to validate a struct 24 type 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 validate 28 // instance. 29 Validator() *Validate 30 31 // Top returns the top level struct, if any 32 Top() reflect.Value 33 34 // Parent returns the current fields parent struct, if any 35 Parent() reflect.Value 36 37 // Current returns the current struct. 38 Current() reflect.Value 39 40 // ExtractType gets the actual underlying type of field value. 41 // It will dive into pointers, customTypes and return you the 42 // underlying value and its kind. 43 ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) 44 45 // ReportError reports an error just by passing the field and tag information 46 // 47 // NOTES: 48 // 49 // fieldName and altName get appended to the existing namespace that 50 // validator is on. e.g. pass 'FirstName' or 'Names[0]' depending 51 // on the nesting 52 // 53 // tag can be an existing validation tag or just something you make up 54 // and process on the flip side it's up to you. 55 ReportError(field interface{}, fieldName, structFieldName string, tag, param string) 56 57 // ReportValidationErrors reports an error just by passing ValidationErrors 58 // 59 // NOTES: 60 // 61 // relativeNamespace and relativeActualNamespace get appended to the 62 // existing namespace that validator is on. 63 // e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending 64 // on the nesting. most of the time they will be blank, unless you validate 65 // at a level lower the current field depth 66 ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) 67 } 68 69 var _ 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. 78 func (v *validate) Top() reflect.Value { 79 return v.top 80 } 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. 89 func (v *validate) Parent() reflect.Value { 90 return v.slflParent 91 } 92 93 // Current returns the current struct. 94 func (v *validate) Current() reflect.Value { 95 return v.slCurrent 96 } 97 98 // Validator returns the main validation object, in case one want to call validations internally. 99 func (v *validate) Validator() *Validate { 100 return v.v 101 } 102 103 // ExtractType gets the actual underlying type of field value. 104 func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) { 105 return v.extractTypeInternal(field, false) 106 } 107 108 // ReportError reports an error just by passing the field and tag information 109 func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) { 110 111 fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) 112 113 if len(structFieldName) == 0 { 114 structFieldName = fieldName 115 } 116 117 v.str1 = string(append(v.ns, fieldName...)) 118 119 if v.v.hasTagNameFunc || fieldName != structFieldName { 120 v.str2 = string(append(v.actualNs, structFieldName...)) 121 } else { 122 v.str2 = v.str1 123 } 124 125 if kind == reflect.Invalid { 126 127 v.errs = append(v.errs, 128 &fieldError{ 129 v: v.v, 130 tag: tag, 131 actualTag: tag, 132 ns: v.str1, 133 structNs: v.str2, 134 fieldLen: uint8(len(fieldName)), 135 structfieldLen: uint8(len(structFieldName)), 136 param: param, 137 kind: kind, 138 }, 139 ) 140 return 141 } 142 143 v.errs = append(v.errs, 144 &fieldError{ 145 v: v.v, 146 tag: tag, 147 actualTag: tag, 148 ns: v.str1, 149 structNs: v.str2, 150 fieldLen: uint8(len(fieldName)), 151 structfieldLen: uint8(len(structFieldName)), 152 value: fv.Interface(), 153 param: param, 154 kind: kind, 155 typ: 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. 163 func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) { 164 165 var err *fieldError 166 167 for i := 0; i < len(errs); i++ { 168 169 err = errs[i].(*fieldError) 170 err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...)) 171 err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...)) 172 173 v.errs = append(v.errs, err) 174 } 175 }