gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }