initial working commit

pull/16/head
Dean Karn 10 years ago
parent 83c9883fe8
commit aad5727a16
  1. 18
      baked_in.go
  2. 209
      validator.go
  3. 33
      validator_test.go

@ -0,0 +1,18 @@
package validator
import (
"log"
"reflect"
)
var bakedInValidators = map[string]ValidationFunc{
"required": isRequired,
}
func isRequired(field interface{}, param string) bool {
log.Printf("Required:%s Valid:%t\n", field, field != nil && field != reflect.Zero(reflect.TypeOf(field)).Interface())
return field != nil && field != reflect.Zero(reflect.TypeOf(field)).Interface()
// return true
}

@ -2,9 +2,10 @@ package validator
import (
"errors"
"fmt"
"log"
"reflect"
"strings"
"unicode"
)
// FieldValidationError contains a single fields validation error
@ -17,17 +18,18 @@ type FieldValidationError struct {
// 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
Struct string
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
}
// // 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
type ValidationFunc func(v interface{}, param string) bool
// Validator implements the Validator Struct
// NOTE: Fields within are not thread safe and that is on purpose
@ -40,7 +42,7 @@ type Validator struct {
validationFuncs map[string]ValidationFunc
}
var bakedInValidators = map[string]ValidationFunc{}
// var bakedInValidators = map[string]ValidationFunc{}
var internalValidator = NewValidator("validate", bakedInValidators)
@ -89,17 +91,23 @@ func (v *Validator) AddFunction(key string, f ValidationFunc) error {
return nil
}
func ValidateStruct(s interface{}) ArrayStructValidationErrors {
// ValidateStruct validates a struct and returns a struct containing the errors
func ValidateStruct(s interface{}) []*StructValidationErrors {
return internalValidator.ValidateStruct(s)
}
func (v *Validator) ValidateStruct(s interface{}) ArrayStructValidationErrors {
var errorStruct = ArrayStructValidationErrors{}
// ValidateStruct validates a struct and returns a struct containing the errors
func (v *Validator) ValidateStruct(s interface{}) []*StructValidationErrors {
errorArray := []*StructValidationErrors{}
structValue := reflect.ValueOf(s)
structType := reflect.TypeOf(s)
structName := structType.Name()
var currentStructError = &StructValidationErrors{
Struct: structName,
}
if structValue.Kind() == reflect.Ptr && !structValue.IsNil() {
return v.ValidateStruct(structValue.Elem().Interface())
@ -120,8 +128,179 @@ func (v *Validator) ValidateStruct(s interface{}) ArrayStructValidationErrors {
valueField = valueField.Elem()
}
fmt.Println(typeField.Name)
tag := typeField.Tag.Get(v.tagName)
if tag == "-" {
continue
}
// if no validation and not a struct (which may containt fields for validation)
if tag == "" && valueField.Kind() != reflect.Struct {
continue
}
switch valueField.Kind() {
case reflect.Struct:
if !unicode.IsUpper(rune(typeField.Name[0])) {
continue
}
if structErrors := v.ValidateStruct(valueField.Interface()); structErrors != nil {
errorArray = append(errorArray, structErrors...)
}
default:
if fieldError := v.validateStructFieldByTag(valueField.Interface(), typeField.Name, tag); fieldError != nil {
currentStructError.Errors = append(currentStructError.Errors, fieldError)
}
}
}
if currentStructError.Errors != nil {
errorArray = append(errorArray, currentStructError)
}
if len(errorArray) == 0 {
return nil
}
return errorArray
}
// ValidateFieldWithTag validates the given field by the given tag arguments
func (v *Validator) validateStructFieldByTag(f interface{}, name string, tag string) *FieldValidationError {
// // This is a double check if coming from ValidateStruct but need to be here in case function is called directly
// if tag == "-" {
// return nil
// }
//
// valueField := reflect.ValueOf(f)
//
// if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
// return v.validateStructFieldByTag(valueField.Elem().Interface(), name, tag)
// }
//
// // fmt.Println(typeField.Name)
//
// switch valueField.Kind() {
//
// case reflect.Struct, reflect.Invalid:
// log.Fatal("Invalid field passed to ValidateFieldWithTag")
// }
//
// // typeField := reflect.TypeOf(f)
// // name := ""
// valTags := strings.Split(tag, ",")
//
// for _, valTag := range valTags {
//
// vals := strings.Split(valTag, "=")
// key := strings.Trim(vals[0], " ")
//
// if len(key) == 0 {
// log.Fatalf("Invalid validation tag on field %s", name)
// }
//
// valFunc := v.validationFuncs[key]
// if valFunc == nil {
// log.Fatalf("Undefined validation function on field %s", name)
// }
//
// param := ""
// if len(vals) > 1 {
// param = strings.Trim(vals[1], " ")
// }
//
// if err := valFunc(f, param); !err {
//
// return &FieldValidationError{
// Field: name,
// ErrorTag: key,
// }
// }
//
// }
//
// return nil
//
//
if err := v.validateFieldByNameAndTag(f, name, tag); err != nil {
return &FieldValidationError{
Field: name,
ErrorTag: err.Error(),
}
}
return nil
}
// ValidateFieldByTag allows validation of a single field with the internal validator, still using tag style validation to check multiple errors
func ValidateFieldByTag(f interface{}, tag string) error {
return internalValidator.validateFieldByNameAndTag(f, "", tag)
}
// ValidateFieldByTag allows validation of a single field, still using tag style validation to check multiple errors
func (v *Validator) ValidateFieldByTag(f interface{}, tag string) error {
return v.validateFieldByNameAndTag(f, "", tag)
}
func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag string) error {
// This is a double check if coming from ValidateStruct but need to be here in case function is called directly
if tag == "-" {
return nil
}
valueField := reflect.ValueOf(f)
if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
return v.ValidateFieldByTag(valueField.Elem().Interface(), tag)
}
// fmt.Println(typeField.Name)
switch valueField.Kind() {
case reflect.Struct, reflect.Invalid:
log.Fatal("Invalid field passed to ValidateFieldWithTag")
}
// typeField := reflect.TypeOf(f)
// name := ""
valTags := strings.Split(tag, ",")
for _, valTag := range valTags {
vals := strings.Split(valTag, "=")
key := strings.Trim(vals[0], " ")
if len(key) == 0 {
log.Fatalf("Invalid validation tag on field %s", name)
}
valFunc := v.validationFuncs[key]
if valFunc == nil {
log.Fatalf("Undefined validation function on field %s", name)
}
param := ""
if len(vals) > 1 {
param = strings.Trim(vals[1], " ")
}
if err := valFunc(f, param); !err {
return errors.New(key)
}
}
return errorStruct
return nil
}

@ -4,7 +4,7 @@ import (
"fmt"
"testing"
"gopkg.in/joeybloggs/go-validate-yourself.v0"
"github.com/joeybloggs/go-validate-yourself"
)
type UserDetails struct {
@ -19,13 +19,38 @@ type User struct {
func TestValidateStruct(t *testing.T) {
u := &User{
FirstName: "Dean Karn",
FirstName: "",
Details: &UserDetails{
"26 Here Blvd.",
"",
},
}
errors := validator.ValidateStruct(u)
fmt.Println(errors)
fmt.Println(errors == nil)
for _, i := range errors {
fmt.Printf("Error Struct:%s\n", i.Struct)
for _, j := range i.Errors {
fmt.Printf("Error Field:%s Error Tag:%s\n", j.Field, j.ErrorTag)
}
}
}
// func TestValidateField(t *testing.T) {
//
// u := &User{
// FirstName: "Dean Karn",
// Details: &UserDetails{
// "26 Here Blvd.",
// },
// }
//
// err := validator.ValidateFieldByTag(u.FirstName, "required")
//
// fmt.Println(err == nil)
// fmt.Println(err)
// }

Loading…
Cancel
Save