5849898283
Unit tests functional and coverage back to 100% Add more routes to dictionary, add more credentials, add default port 5554, rename cameradar logs ENV variable, improve unit test readability, remove tmp file
176 lines
5.3 KiB
Go
176 lines
5.3 KiB
Go
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)
|
|
}
|
|
}
|