parent
2483ffe407
commit
c0ff4f7f60
@ -0,0 +1,127 @@ |
|||||||
|
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 |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
package validator_test |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/joeybloggs/go-validate-yourself" |
||||||
|
) |
||||||
|
|
||||||
|
type UserDetails struct { |
||||||
|
Address string `validate:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
type User struct { |
||||||
|
FirstName string `validate:"required"` |
||||||
|
Details *UserDetails |
||||||
|
} |
||||||
|
|
||||||
|
func TestValidateStruct(t *testing.T) { |
||||||
|
|
||||||
|
u := &User{ |
||||||
|
FirstName: "Dean Karn", |
||||||
|
Details: &UserDetails{ |
||||||
|
"26 Here Blvd.", |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
errors := validator.ValidateStruct(u) |
||||||
|
|
||||||
|
fmt.Println(errors) |
||||||
|
} |
Loading…
Reference in new issue