|
|
|
@ -1,3 +1,12 @@ |
|
|
|
|
/** |
|
|
|
|
* Package validator |
|
|
|
|
* |
|
|
|
|
* NOTES: |
|
|
|
|
* |
|
|
|
|
* anonymous structs - they don't have names so expect the Struct name within StructValidationErrors to be blank |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
package validator |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
@ -11,8 +20,9 @@ import ( |
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
defaultTagName = "validate" |
|
|
|
|
omitempty string = "omitempty" |
|
|
|
|
validationErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag\n" |
|
|
|
|
omitempty = "omitempty" |
|
|
|
|
validationFieldErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag\n" |
|
|
|
|
validationStructErrMsg = "Struct:%s\n" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// FieldValidationError contains a single fields validation error
|
|
|
|
@ -24,29 +34,35 @@ type FieldValidationError struct { |
|
|
|
|
// This is intended for use in development + debugging and not intended to be a production error message.
|
|
|
|
|
// it also allows FieldValidationError to be used as an Error interface
|
|
|
|
|
func (e FieldValidationError) Error() string { |
|
|
|
|
return fmt.Sprintf(validationErrMsg, e.Field, e.ErrorTag) |
|
|
|
|
return fmt.Sprintf(validationFieldErrMsg, e.Field, e.ErrorTag) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// StructValidationErrors is a struct of errors for struct fields ( Excluding fields of type 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 StructValidationErrors is created for each struct resulting in
|
|
|
|
|
// a neat & tidy 2D flattened list of structs validation errors
|
|
|
|
|
// StructValidationErrors is hierarchical list of field and struct errors
|
|
|
|
|
type StructValidationErrors struct { |
|
|
|
|
// Name of the Struct
|
|
|
|
|
Struct string |
|
|
|
|
// Struct Field Errors
|
|
|
|
|
Errors map[string]*FieldValidationError |
|
|
|
|
// Struct Fields of type struct and their errors
|
|
|
|
|
// key = Field Name of current struct, but internally Struct will be the actual struct name unless anonymous struct, it will be blank
|
|
|
|
|
StructErrors map[string]*StructValidationErrors |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// This is intended for use in development + debugging and not intended to be a production error message.
|
|
|
|
|
// it also allows StructValidationErrors to be used as an Error interface
|
|
|
|
|
func (e StructValidationErrors) Error() string { |
|
|
|
|
|
|
|
|
|
s := "" |
|
|
|
|
s := fmt.Sprintf(validationStructErrMsg, e.Struct) |
|
|
|
|
|
|
|
|
|
for _, err := range e.Errors { |
|
|
|
|
s += fmt.Sprintf(validationErrMsg, err.Field, err.ErrorTag) |
|
|
|
|
s += err.Error() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, sErr := range e.StructErrors { |
|
|
|
|
s += sErr.Error() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return s |
|
|
|
|
return fmt.Sprintf("%s\n\n", s) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ValidationFunc that accepts the value of a field and parameter for use in validation (parameter not always used or needed)
|
|
|
|
@ -113,22 +129,22 @@ func (v *Validator) AddFunction(key string, f ValidationFunc) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ValidateStruct validates a struct and returns a struct containing the errors
|
|
|
|
|
func ValidateStruct(s interface{}) map[string]*StructValidationErrors { |
|
|
|
|
func ValidateStruct(s interface{}) *StructValidationErrors { |
|
|
|
|
|
|
|
|
|
return internalValidator.ValidateStruct(s) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ValidateStruct validates a struct and returns a struct containing the errors
|
|
|
|
|
func (v *Validator) ValidateStruct(s interface{}) map[string]*StructValidationErrors { |
|
|
|
|
func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors { |
|
|
|
|
|
|
|
|
|
errorArray := map[string]*StructValidationErrors{} |
|
|
|
|
structValue := reflect.ValueOf(s) |
|
|
|
|
structType := reflect.TypeOf(s) |
|
|
|
|
structName := structType.Name() |
|
|
|
|
|
|
|
|
|
var currentStructError = &StructValidationErrors{ |
|
|
|
|
validationErrors := &StructValidationErrors{ |
|
|
|
|
Struct: structName, |
|
|
|
|
Errors: map[string]*FieldValidationError{}, |
|
|
|
|
StructErrors: map[string]*StructValidationErrors{}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if structValue.Kind() == reflect.Ptr && !structValue.IsNil() { |
|
|
|
@ -170,9 +186,7 @@ func (v *Validator) ValidateStruct(s interface{}) map[string]*StructValidationEr |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if structErrors := v.ValidateStruct(valueField.Interface()); structErrors != nil { |
|
|
|
|
for key, val := range structErrors { |
|
|
|
|
errorArray[key] = val |
|
|
|
|
} |
|
|
|
|
validationErrors.StructErrors[typeField.Name] = structErrors |
|
|
|
|
// free up memory map no longer needed
|
|
|
|
|
structErrors = nil |
|
|
|
|
} |
|
|
|
@ -180,24 +194,18 @@ func (v *Validator) ValidateStruct(s interface{}) map[string]*StructValidationEr |
|
|
|
|
default: |
|
|
|
|
|
|
|
|
|
if fieldError := v.validateStructFieldByTag(valueField.Interface(), typeField.Name, tag); fieldError != nil { |
|
|
|
|
currentStructError.Errors[fieldError.Field] = fieldError |
|
|
|
|
validationErrors.Errors[fieldError.Field] = fieldError |
|
|
|
|
// free up memory reference
|
|
|
|
|
fieldError = nil |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(currentStructError.Errors) > 0 { |
|
|
|
|
errorArray[currentStructError.Struct] = currentStructError |
|
|
|
|
// free up memory
|
|
|
|
|
currentStructError = nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(errorArray) == 0 { |
|
|
|
|
if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return errorArray |
|
|
|
|
return validationErrors |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ValidateFieldWithTag validates the given field by the given tag arguments
|
|
|
|
|