struct_level.go raw

   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