You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.7 KiB
128 lines
3.7 KiB
10 years ago
|
package validator
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"reflect"
|
||
|
)
|
||
|
|
||
|
// FieldValidationError contains a single fields validation error
|
||
|
type FieldValidationError struct {
|
||
|
Field string
|
||
|
ErrorTag string
|
||
|
}
|
||
|
|
||
|
// StructValidationErrors is a slice of errors for struct fields ( Excluding struct fields)
|
||
|
// NOTE: if a field within a struct is a struct it's errors will not be contained within the current
|
||
|
// StructValidationErrors but rather a new ArrayValidationErrors is created for each struct
|
||
|
type StructValidationErrors struct {
|
||
|
Errors []FieldValidationError
|
||
|
}
|
||
|
|
||
|
// ArrayStructValidationErrors is a struct that contains a 2D flattened list of struct specific StructValidationErrors
|
||
|
type ArrayStructValidationErrors struct {
|
||
|
// Key = Struct Name
|
||
|
Errors map[string][]StructValidationErrors
|
||
|
}
|
||
|
|
||
|
// ValidationFunc that accepts the value of a field and parameter for use in validation (parameter not always used or needed)
|
||
|
type ValidationFunc func(v interface{}, param string) error
|
||
|
|
||
|
// Validator implements the Validator Struct
|
||
|
// NOTE: Fields within are not thread safe and that is on purpose
|
||
|
// Functions Tags etc. should all be predifined before use, so subscribe to the philosiphy
|
||
|
// or make it thread safe on your end
|
||
|
type Validator struct {
|
||
|
// TagName being used.
|
||
|
tagName string
|
||
|
// validationFuncs is a map of validation functions and the tag keys
|
||
|
validationFuncs map[string]ValidationFunc
|
||
|
}
|
||
|
|
||
|
var bakedInValidators = map[string]ValidationFunc{}
|
||
|
|
||
|
var internalValidator = NewValidator("validate", bakedInValidators)
|
||
|
|
||
|
// NewValidator creates a new Validator instance
|
||
|
// NOTE: it is not necessary to create a new validator as the internal one will do in 99.9% of cases, but the option is there.
|
||
|
func NewValidator(tagName string, funcs map[string]ValidationFunc) *Validator {
|
||
|
return &Validator{
|
||
|
tagName: tagName,
|
||
|
validationFuncs: funcs,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// SetTag sets the baked in Validator's tagName to one of your choosing
|
||
|
func SetTag(tagName string) {
|
||
|
internalValidator.SetTag(tagName)
|
||
|
}
|
||
|
|
||
|
// SetTag sets tagName of the Validator to one of your choosing
|
||
|
func (v *Validator) SetTag(tagName string) {
|
||
|
v.tagName = tagName
|
||
|
}
|
||
|
|
||
|
// AddFunction adds a ValidationFunc to the baked in Validator's map of validators denoted by the key
|
||
|
func AddFunction(key string, f ValidationFunc) error {
|
||
|
return internalValidator.AddFunction(key, f)
|
||
|
}
|
||
|
|
||
|
// AddFunction adds a ValidationFunc to a Validator's map of validators denoted by the key
|
||
|
func (v *Validator) AddFunction(key string, f ValidationFunc) error {
|
||
|
|
||
|
if len(key) == 0 {
|
||
|
return errors.New("Function Key cannot be empty")
|
||
|
}
|
||
|
|
||
|
if f == nil {
|
||
|
return errors.New("Function Key cannot be empty")
|
||
|
}
|
||
|
|
||
|
// Commented out to allow overwritting of Baked In Function if so desired.
|
||
|
// if v.ValidationFuncs[key] != nil {
|
||
|
// return errors.New(fmt.Sprintf("Validation Function with key: %s already exists.", key))
|
||
|
// }
|
||
|
|
||
|
v.validationFuncs[key] = f
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func ValidateStruct(s interface{}) ArrayStructValidationErrors {
|
||
|
|
||
|
return internalValidator.ValidateStruct(s)
|
||
|
}
|
||
|
|
||
|
func (v *Validator) ValidateStruct(s interface{}) ArrayStructValidationErrors {
|
||
|
|
||
|
var errorStruct = ArrayStructValidationErrors{}
|
||
|
|
||
|
structValue := reflect.ValueOf(s)
|
||
|
structType := reflect.TypeOf(s)
|
||
|
|
||
|
if structValue.Kind() == reflect.Ptr && !structValue.IsNil() {
|
||
|
return v.ValidateStruct(structValue.Elem().Interface())
|
||
|
}
|
||
|
|
||
|
if structValue.Kind() != reflect.Struct {
|
||
|
log.Fatal("interface passed for validation is not a struct")
|
||
|
}
|
||
|
|
||
|
var numFields = structValue.NumField()
|
||
|
|
||
|
for i := 0; i < numFields; i++ {
|
||
|
|
||
|
valueField := structValue.Field(i)
|
||
|
typeField := structType.Field(i)
|
||
|
|
||
|
if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
|
||
|
valueField = valueField.Elem()
|
||
|
}
|
||
|
|
||
|
fmt.Println(typeField.Name)
|
||
|
}
|
||
|
|
||
|
return errorStruct
|
||
|
}
|