From c0ff4f7f6086822d063316460febb912a5e5bc19 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Thu, 12 Feb 2015 14:40:37 -0500 Subject: [PATCH] initial code checkin so that can integrate with http://gopkg.in/ --- validator.go | 127 ++++++++++++++++++++++++++++++++++++++++++++++ validator_test.go | 31 +++++++++++ 2 files changed, 158 insertions(+) create mode 100644 validator.go create mode 100644 validator_test.go diff --git a/validator.go b/validator.go new file mode 100644 index 0000000..1b1d13f --- /dev/null +++ b/validator.go @@ -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 +} diff --git a/validator_test.go b/validator_test.go new file mode 100644 index 0000000..9180a03 --- /dev/null +++ b/validator_test.go @@ -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) +}