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