Skip to content

Commit 677d681

Browse files
Dean KarnDean Karn
authored andcommitted
Merge branch 'v1-development' into v1
2 parents 2c6624d + 15d2131 commit 677d681

File tree

3 files changed

+370
-68
lines changed

3 files changed

+370
-68
lines changed

baked_in.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,24 @@ import (
99

1010
var bakedInValidators = map[string]ValidationFunc{
1111
"required": required,
12-
"length": length,
12+
"len": length,
1313
"min": min,
1414
"max": max,
1515
"regex": regex,
1616
}
1717

1818
func required(field interface{}, param string) bool {
1919

20-
return field != nil && field != reflect.Zero(reflect.TypeOf(field)).Interface()
20+
st := reflect.ValueOf(field)
21+
22+
switch st.Kind() {
23+
24+
case reflect.Slice, reflect.Map, reflect.Array:
25+
return field != nil && int64(st.Len()) > 0
26+
27+
default:
28+
return field != nil && field != reflect.Zero(reflect.TypeOf(field)).Interface()
29+
}
2130
}
2231

2332
// length tests whether a variable's length is equal to a given

validator.go

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
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+
19
package validator
210

311
import (
412
"errors"
513
"fmt"
6-
"log"
714
"reflect"
815
"strings"
916
"unicode"
1017
)
1118

1219
const (
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
2634
func (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
3439
type 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
4151
func (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

Comments
 (0)