Reworked Required and OmitEmpty #8
67
binding.go
67
binding.go
|
@ -388,32 +388,41 @@ func validateField(errors Errors, zero interface{}, field reflect.StructField, f
|
|||
}
|
||||
}
|
||||
|
||||
rules := strings.Split(field.Tag.Get("binding"), ";")
|
||||
|
||||
if reflect.DeepEqual(zero, fieldValue) {
|
||||
for _, rule := range rules {
|
||||
if rule == "Required" {
|
||||
errors.Add([]string{field.Name}, ERR_REQUIRED, "Required")
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(rule, "Default(") {
|
||||
if fieldVal.CanSet() {
|
||||
errors = setWithProperType(field.Type.Kind(), rule[8:len(rule)-1], fieldVal, field.Tag.Get("form"), errors)
|
||||
} else {
|
||||
errors.Add([]string{field.Name}, ERR_EXCLUDE, "Default")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
VALIDATE_RULES:
|
||||
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
|
||||
for _, rule := range rules {
|
||||
if len(rule) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case rule == "OmitEmpty":
|
||||
if reflect.DeepEqual(zero, fieldValue) {
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
case rule == "Required":
|
||||
v := reflect.ValueOf(fieldValue)
|
||||
if v.Kind() == reflect.Slice {
|
||||
if v.Len() == 0 {
|
||||
errors.Add([]string{field.Name}, ERR_REQUIRED, "Required")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
continue
|
||||
case strings.HasPrefix(rule, "Default("):
|
||||
continue
|
||||
case rule == "OmitEmpty": // legacy
|
||||
continue
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(zero, fieldValue) {
|
||||
errors.Add([]string{field.Name}, ERR_REQUIRED, "Required")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
case rule == "AlphaDash":
|
||||
if AlphaDashPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
|
||||
errors.Add([]string{field.Name}, ERR_ALPHA_DASH, "AlphaDash")
|
||||
|
@ -430,8 +439,7 @@ VALIDATE_RULES:
|
|||
errors.Add([]string{field.Name}, ERR_SIZE, "Size")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
v := reflect.ValueOf(fieldValue)
|
||||
if v.Kind() == reflect.Slice && v.Len() != size {
|
||||
if fieldVal.Kind() == reflect.Slice && fieldVal.Len() != size {
|
||||
errors.Add([]string{field.Name}, ERR_SIZE, "Size")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
|
@ -441,8 +449,7 @@ VALIDATE_RULES:
|
|||
errors.Add([]string{field.Name}, ERR_MIN_SIZE, "MinSize")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
v := reflect.ValueOf(fieldValue)
|
||||
if v.Kind() == reflect.Slice && v.Len() < min {
|
||||
if fieldVal.Kind() == reflect.Slice && fieldVal.Len() < min {
|
||||
errors.Add([]string{field.Name}, ERR_MIN_SIZE, "MinSize")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
|
@ -452,8 +459,7 @@ VALIDATE_RULES:
|
|||
errors.Add([]string{field.Name}, ERR_MAX_SIZE, "MaxSize")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
v := reflect.ValueOf(fieldValue)
|
||||
if v.Kind() == reflect.Slice && v.Len() > max {
|
||||
if fieldVal.Kind() == reflect.Slice && fieldVal.Len() > max {
|
||||
errors.Add([]string{field.Name}, ERR_MAX_SIZE, "MaxSize")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
|
@ -474,9 +480,7 @@ VALIDATE_RULES:
|
|||
}
|
||||
case rule == "Url":
|
||||
str := fmt.Sprintf("%v", fieldValue)
|
||||
if len(str) == 0 {
|
||||
continue
|
||||
} else if !isURL(str) {
|
||||
if !isURL(str) {
|
||||
errors.Add([]string{field.Name}, ERR_URL, "Url")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
|
@ -500,15 +504,6 @@ VALIDATE_RULES:
|
|||
errors.Add([]string{field.Name}, ERR_EXCLUDE, "Exclude")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
case strings.HasPrefix(rule, "Default("):
|
||||
if reflect.DeepEqual(zero, fieldValue) {
|
||||
if fieldVal.CanAddr() {
|
||||
errors = setWithProperType(field.Type.Kind(), rule[8:len(rule)-1], fieldVal, field.Tag.Get("form"), errors)
|
||||
} else {
|
||||
errors.Add([]string{field.Name}, ERR_EXCLUDE, "Default")
|
||||
break VALIDATE_RULES
|
||||
}
|
||||
}
|
||||
default:
|
||||
// Apply custom validation rules
|
||||
var isValid bool
|
||||
|
|
|
@ -74,7 +74,7 @@ type (
|
|||
NotIn string `form:"NotIn" binding:"NotIn(1,2,3)"`
|
||||
Include string `form:"Include" binding:"Include(a)"`
|
||||
Exclude string `form:"Exclude" binding:"Exclude(a)"`
|
||||
Empty string `binding:"OmitEmpty"`
|
||||
Empty string
|
||||
}
|
||||
|
||||
Group struct {
|
||||
|
|
110
validate_test.go
110
validate_test.go
|
@ -401,6 +401,114 @@ var validationTestCases = []validationTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "no errors with not required fields",
|
||||
data: []*struct {
|
||||
AlphaDash string `binding:"AlphaDash"`
|
||||
AlphaDashDot string `binding:"AlphaDashDot"`
|
||||
Size string `binding:"Size(1)"`
|
||||
SizeSlice []string `binding:"Size(1)"`
|
||||
MinSize string `binding:"MinSize(5)"`
|
||||
MinSizeSlice []string `binding:"MinSize(5)"`
|
||||
MaxSize string `binding:"MaxSize(1)"`
|
||||
MaxSizeSlice []string `binding:"MaxSize(1)"`
|
||||
Range int `binding:"Range(1,2)"`
|
||||
Email string `binding:"Email"`
|
||||
Url string `binding:"Url"`
|
||||
In string `binding:"Default(0);In(1,2,3)"`
|
||||
NotIn string `binding:"NotIn(1,2,3)"`
|
||||
} {
|
||||
{},
|
||||
},
|
||||
expectedErrors: Errors{},
|
||||
},
|
||||
{
|
||||
description: "errors with required fields",
|
||||
data: []*struct {
|
||||
AlphaDash string `binding:"Required;AlphaDash"`
|
||||
AlphaDashDot string `binding:"Required;AlphaDashDot"`
|
||||
Size string `binding:"Required;Size(1)"`
|
||||
SizeSlice []string `binding:"Required;Size(1)"`
|
||||
MinSize string `binding:"Required;MinSize(5)"`
|
||||
MinSizeSlice []string `binding:"Required;MinSize(5)"`
|
||||
MaxSize string `binding:"Required;MaxSize(1)"`
|
||||
MaxSizeSlice []string `binding:"Required;MaxSize(1)"`
|
||||
Range int `binding:"Required;Range(1,2)"`
|
||||
Email string `binding:"Required;Email"`
|
||||
Url string `binding:"Required;Url"`
|
||||
In string `binding:"Required;Default(0);In(1,2,3)"`
|
||||
NotIn string `binding:"Required;NotIn(1,2,3)"`
|
||||
} {
|
||||
{},
|
||||
},
|
||||
expectedErrors: Errors{
|
||||
Error{
|
||||
FieldNames: []string{"AlphaDash"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"AlphaDashDot"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"Size"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"SizeSlice"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"MinSize"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"MinSizeSlice"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"MaxSize"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"MaxSizeSlice"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"Range"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"Email"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"Url"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"In"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
Error{
|
||||
FieldNames: []string{"NotIn"},
|
||||
Classification: "Required",
|
||||
Message: "Required",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func Test_Validation(t *testing.T) {
|
||||
|
@ -415,7 +523,7 @@ func performValidationTest(t *testing.T, testCase validationTestCase) {
|
|||
|
||||
m.Post(testRoute, func(resp http.ResponseWriter, req *http.Request) {
|
||||
actual := Validate(req, testCase.data)
|
||||
assert.EqualValues(t, fmt.Sprintf("%+v", testCase.expectedErrors), fmt.Sprintf("%+v", actual))
|
||||
assert.EqualValues(t, fmt.Sprintf("%+v", testCase.expectedErrors), fmt.Sprintf("%+v", actual), testCase.description)
|
||||
})
|
||||
|
||||
req, err := http.NewRequest("POST", testRoute, nil)
|
||||
|
|
Loading…
Reference in New Issue
Block a user