123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- package validator
- import (
- "context"
- "reflect"
- )
- // StructLevelFunc accepts all values needed for struct level validation
- type StructLevelFunc func(sl StructLevel)
- // StructLevelFuncCtx accepts all values needed for struct level validation
- // but also allows passing of contextual validation information vi context.Context.
- type StructLevelFuncCtx func(ctx context.Context, sl StructLevel)
- // wrapStructLevelFunc wraps noramal StructLevelFunc makes it compatible with StructLevelFuncCtx
- func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {
- return func(ctx context.Context, sl StructLevel) {
- fn(sl)
- }
- }
- // StructLevel contains all the information and helper functions
- // to validate a struct
- type StructLevel interface {
- // returns the main validation object, in case one want to call validations internally.
- // this is so you don;t have to use anonymous functoins to get access to the validate
- // instance.
- Validator() *Validate
- // returns the top level struct, if any
- Top() reflect.Value
- // returns the current fields parent struct, if any
- Parent() reflect.Value
- // returns the current struct.
- Current() reflect.Value
- // ExtractType gets the actual underlying type of field value.
- // It will dive into pointers, customTypes and return you the
- // underlying value and it's kind.
- ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool)
- // reports an error just by passing the field and tag information
- //
- // NOTES:
- //
- // fieldName and altName get appended to the existing namespace that
- // validator is on. eg. pass 'FirstName' or 'Names[0]' depending
- // on the nesting
- //
- // tag can be an existing validation tag or just something you make up
- // and process on the flip side it's up to you.
- ReportError(field interface{}, fieldName, structFieldName string, tag, param string)
- // reports an error just by passing ValidationErrors
- //
- // NOTES:
- //
- // relativeNamespace and relativeActualNamespace get appended to the
- // existing namespace that validator is on.
- // eg. pass 'User.FirstName' or 'Users[0].FirstName' depending
- // on the nesting. most of the time they will be blank, unless you validate
- // at a level lower the the current field depth
- ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors)
- }
- var _ StructLevel = new(validate)
- // Top returns the top level struct
- //
- // NOTE: this can be the same as the current struct being validated
- // if not is a nested struct.
- //
- // this is only called when within Struct and Field Level validation and
- // should not be relied upon for an acurate value otherwise.
- func (v *validate) Top() reflect.Value {
- return v.top
- }
- // Parent returns the current structs parent
- //
- // NOTE: this can be the same as the current struct being validated
- // if not is a nested struct.
- //
- // this is only called when within Struct and Field Level validation and
- // should not be relied upon for an acurate value otherwise.
- func (v *validate) Parent() reflect.Value {
- return v.slflParent
- }
- // Current returns the current struct.
- func (v *validate) Current() reflect.Value {
- return v.slCurrent
- }
- // Validator returns the main validation object, in case one want to call validations internally.
- func (v *validate) Validator() *Validate {
- return v.v
- }
- // ExtractType gets the actual underlying type of field value.
- func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) {
- return v.extractTypeInternal(field, false)
- }
- // ReportError reports an error just by passing the field and tag information
- func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) {
- fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false)
- if len(structFieldName) == 0 {
- structFieldName = fieldName
- }
- v.str1 = string(append(v.ns, fieldName...))
- if v.v.hasTagNameFunc || fieldName != structFieldName {
- v.str2 = string(append(v.actualNs, structFieldName...))
- } else {
- v.str2 = v.str1
- }
- if kind == reflect.Invalid {
- v.errs = append(v.errs,
- &fieldError{
- v: v.v,
- tag: tag,
- actualTag: tag,
- ns: v.str1,
- structNs: v.str2,
- fieldLen: uint8(len(fieldName)),
- structfieldLen: uint8(len(structFieldName)),
- param: param,
- kind: kind,
- },
- )
- return
- }
- v.errs = append(v.errs,
- &fieldError{
- v: v.v,
- tag: tag,
- actualTag: tag,
- ns: v.str1,
- structNs: v.str2,
- fieldLen: uint8(len(fieldName)),
- structfieldLen: uint8(len(structFieldName)),
- value: fv.Interface(),
- param: param,
- kind: kind,
- typ: fv.Type(),
- },
- )
- }
- // ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation.
- //
- // NOTE: this function prepends the current namespace to the relative ones.
- func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) {
- var err *fieldError
- for i := 0; i < len(errs); i++ {
- err = errs[i].(*fieldError)
- err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...))
- err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...))
- v.errs = append(v.errs, err)
- }
- }
|