1+ /**
2+ * Package validator
3+ *
4+ * MISC:
5+ * - anonymous structs - they don't have names so expect the Struct name within StructValidationErrors to be blank
6+ *
7+ */
8+
19package validator
210
311import (
412 "errors"
513 "fmt"
6- "log"
714 "reflect"
815 "strings"
916 "unicode"
1017)
1118
1219const (
13- defaultTagName = "validate"
14- omitempty string = "omitempty"
15- validationErrMsg = "Field validation for \" %s\" failed on the \" %s\" tag\n "
20+ defaultTagName = "validate"
21+ omitempty = "omitempty"
22+ validationFieldErrMsg = "Field validation for \" %s\" failed on the \" %s\" tag\n "
23+ validationStructErrMsg = "Struct:%s\n "
1624)
1725
1826// FieldValidationError contains a single fields validation error
@@ -24,29 +32,35 @@ type FieldValidationError struct {
2432// This is intended for use in development + debugging and not intended to be a production error message.
2533// it also allows FieldValidationError to be used as an Error interface
2634func (e FieldValidationError ) Error () string {
27- return fmt .Sprintf (validationErrMsg , e .Field , e .ErrorTag )
35+ return fmt .Sprintf (validationFieldErrMsg , e .Field , e .ErrorTag )
2836}
2937
30- // StructValidationErrors is a struct of errors for struct fields ( Excluding fields of type struct )
31- // NOTE: if a field within a struct is a struct it's errors will not be contained within the current
32- // StructValidationErrors but rather a new StructValidationErrors is created for each struct resulting in
33- // a neat & tidy 2D flattened list of structs validation errors
38+ // StructValidationErrors is hierarchical list of field and struct errors
3439type StructValidationErrors struct {
40+ // Name of the Struct
3541 Struct string
42+ // Struct Field Errors
3643 Errors map [string ]* FieldValidationError
44+ // Struct Fields of type struct and their errors
45+ // key = Field Name of current struct, but internally Struct will be the actual struct name unless anonymous struct, it will be blank
46+ StructErrors map [string ]* StructValidationErrors
3747}
3848
3949// This is intended for use in development + debugging and not intended to be a production error message.
4050// it also allows StructValidationErrors to be used as an Error interface
4151func (e StructValidationErrors ) Error () string {
4252
43- s := ""
53+ s := fmt . Sprintf ( validationStructErrMsg , e . Struct )
4454
4555 for _ , err := range e .Errors {
46- s += fmt .Sprintf (validationErrMsg , err .Field , err .ErrorTag )
56+ s += err .Error ()
57+ }
58+
59+ for _ , sErr := range e .StructErrors {
60+ s += sErr .Error ()
4761 }
4862
49- return s
63+ return fmt . Sprintf ( "%s \n \n " , s )
5064}
5165
5266// ValidationFunc that accepts the value of a field and parameter for use in validation (parameter not always used or needed)
@@ -113,30 +127,30 @@ func (v *Validator) AddFunction(key string, f ValidationFunc) error {
113127}
114128
115129// ValidateStruct validates a struct and returns a struct containing the errors
116- func ValidateStruct (s interface {}) map [ string ] * StructValidationErrors {
130+ func ValidateStruct (s interface {}) * StructValidationErrors {
117131
118132 return internalValidator .ValidateStruct (s )
119133}
120134
121135// ValidateStruct validates a struct and returns a struct containing the errors
122- func (v * Validator ) ValidateStruct (s interface {}) map [ string ] * StructValidationErrors {
136+ func (v * Validator ) ValidateStruct (s interface {}) * StructValidationErrors {
123137
124- errorArray := map [string ]* StructValidationErrors {}
125138 structValue := reflect .ValueOf (s )
126139 structType := reflect .TypeOf (s )
127140 structName := structType .Name ()
128141
129- var currentStructError = & StructValidationErrors {
130- Struct : structName ,
131- Errors : map [string ]* FieldValidationError {},
142+ validationErrors := & StructValidationErrors {
143+ Struct : structName ,
144+ Errors : map [string ]* FieldValidationError {},
145+ StructErrors : map [string ]* StructValidationErrors {},
132146 }
133147
134148 if structValue .Kind () == reflect .Ptr && ! structValue .IsNil () {
135149 return v .ValidateStruct (structValue .Elem ().Interface ())
136150 }
137151
138152 if structValue .Kind () != reflect .Struct {
139- log . Fatal ("interface passed for validation is not a struct" )
153+ panic ("interface passed for validation is not a struct" )
140154 }
141155
142156 var numFields = structValue .NumField ()
@@ -170,34 +184,26 @@ func (v *Validator) ValidateStruct(s interface{}) map[string]*StructValidationEr
170184 }
171185
172186 if structErrors := v .ValidateStruct (valueField .Interface ()); structErrors != nil {
173- for key , val := range structErrors {
174- errorArray [key ] = val
175- }
187+ validationErrors .StructErrors [typeField .Name ] = structErrors
176188 // free up memory map no longer needed
177189 structErrors = nil
178190 }
179191
180192 default :
181193
182194 if fieldError := v .validateStructFieldByTag (valueField .Interface (), typeField .Name , tag ); fieldError != nil {
183- currentStructError .Errors [fieldError .Field ] = fieldError
195+ validationErrors .Errors [fieldError .Field ] = fieldError
184196 // free up memory reference
185197 fieldError = nil
186198 }
187199 }
188200 }
189201
190- if len (currentStructError .Errors ) > 0 {
191- errorArray [currentStructError .Struct ] = currentStructError
192- // free up memory
193- currentStructError = nil
194- }
195-
196- if len (errorArray ) == 0 {
202+ if len (validationErrors .Errors ) == 0 && len (validationErrors .StructErrors ) == 0 {
197203 return nil
198204 }
199205
200- return errorArray
206+ return validationErrors
201207}
202208
203209// ValidateFieldWithTag validates the given field by the given tag arguments
@@ -245,7 +251,7 @@ func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag st
245251 switch valueField .Kind () {
246252
247253 case reflect .Struct , reflect .Invalid :
248- log . Fatal ("Invalid field passed to ValidateFieldWithTag" )
254+ panic ("Invalid field passed to ValidateFieldWithTag" )
249255 }
250256
251257 valTags := strings .Split (tag , "," )
@@ -256,7 +262,7 @@ func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag st
256262 key := strings .Trim (vals [0 ], " " )
257263
258264 if len (key ) == 0 {
259- log . Fatalf ("Invalid validation tag on field %s" , name )
265+ panic ( fmt . Sprintf ("Invalid validation tag on field %s" , name ) )
260266 }
261267
262268 // OK to continue because we checked it's existance before getting into this loop
@@ -266,7 +272,7 @@ func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag st
266272
267273 valFunc := v .validationFuncs [key ]
268274 if valFunc == nil {
269- log . Fatalf ("Undefined validation function on field %s" , name )
275+ panic ( fmt . Sprintf ("Undefined validation function on field %s" , name ) )
270276 }
271277
272278 param := ""
0 commit comments