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 }
176