Add unique validation

pull/317/head
Dean Karn 7 years ago
parent 946d444376
commit 11a1fab51d
  1. 108
      README.md
  2. 20
      baked_in.go
  3. 6
      doc.go
  4. 41
      validator_test.go

@ -65,61 +65,61 @@ Please see http://godoc.org/gopkg.in/go-playground/validator.v9 for detailed usa
Benchmarks Benchmarks
------ ------
###### Run on Dell XPS 15 i7-7700HQ 32GB Go version go1.8.3 linux/amd64 ###### Run on MacBook Pro (15-inch, 2017) Go version go1.9.1 linux/amd64
```go ```go
go test -run=XXX -bench=. -benchmem=true go test -bench=. -benchmem=true
BenchmarkFieldSuccess-8 20000000 88.3 ns/op 0 B/op 0 allocs/op BenchmarkFieldSuccess-8 20000000 87.2 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 50000000 30.4 ns/op 0 B/op 0 allocs/op BenchmarkFieldSuccessParallel-8 50000000 26.1 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 3000000 428 ns/op 208 B/op 4 allocs/op BenchmarkFieldFailure-8 5000000 299 ns/op 208 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 20000000 96.0 ns/op 208 B/op 4 allocs/op BenchmarkFieldFailureParallel-8 20000000 100 ns/op 208 B/op 4 allocs/op
BenchmarkFieldDiveSuccess-8 2000000 695 ns/op 201 B/op 11 allocs/op BenchmarkFieldDiveSuccess-8 2000000 645 ns/op 201 B/op 11 allocs/op
BenchmarkFieldDiveSuccessParallel-8 10000000 205 ns/op 201 B/op 11 allocs/op BenchmarkFieldDiveSuccessParallel-8 10000000 198 ns/op 201 B/op 11 allocs/op
BenchmarkFieldDiveFailure-8 1000000 1083 ns/op 412 B/op 16 allocs/op BenchmarkFieldDiveFailure-8 2000000 876 ns/op 412 B/op 16 allocs/op
BenchmarkFieldDiveFailureParallel-8 5000000 278 ns/op 413 B/op 16 allocs/op BenchmarkFieldDiveFailureParallel-8 5000000 268 ns/op 413 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-8 10000000 229 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccess-8 10000000 228 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 20000000 72.4 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccessParallel-8 20000000 70.0 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 5000000 377 ns/op 208 B/op 4 allocs/op BenchmarkFieldCustomTypeFailure-8 5000000 286 ns/op 208 B/op 4 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 20000000 93.0 ns/op 208 B/op 4 allocs/op BenchmarkFieldCustomTypeFailureParallel-8 20000000 95.6 ns/op 208 B/op 4 allocs/op
BenchmarkFieldOrTagSuccess-8 2000000 767 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagSuccess-8 2000000 857 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 3000000 425 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagSuccessParallel-8 3000000 397 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 2000000 548 ns/op 224 B/op 5 allocs/op BenchmarkFieldOrTagFailure-8 3000000 495 ns/op 224 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 3000000 411 ns/op 224 B/op 5 allocs/op BenchmarkFieldOrTagFailureParallel-8 5000000 376 ns/op 224 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 10000000 219 ns/op 32 B/op 2 allocs/op BenchmarkStructLevelValidationSuccess-8 10000000 226 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 20000000 69.2 ns/op 32 B/op 2 allocs/op BenchmarkStructLevelValidationSuccessParallel-8 20000000 68.4 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationFailure-8 2000000 628 ns/op 304 B/op 8 allocs/op BenchmarkStructLevelValidationFailure-8 3000000 497 ns/op 304 B/op 8 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 10000000 165 ns/op 304 B/op 8 allocs/op BenchmarkStructLevelValidationFailureParallel-8 10000000 170 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 3000000 411 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeSuccess-8 3000000 420 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 122 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeSuccessParallel-8 20000000 124 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 1000000 1022 ns/op 424 B/op 9 allocs/op BenchmarkStructSimpleCustomTypeFailure-8 2000000 681 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 10000000 228 ns/op 440 B/op 10 allocs/op BenchmarkStructSimpleCustomTypeFailureParallel-8 10000000 244 ns/op 440 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 2000000 737 ns/op 288 B/op 9 allocs/op BenchmarkStructFilteredSuccess-8 2000000 659 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredSuccessParallel-8 10000000 192 ns/op 288 B/op 9 allocs/op BenchmarkStructFilteredSuccessParallel-8 10000000 211 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredFailure-8 3000000 583 ns/op 256 B/op 7 allocs/op BenchmarkStructFilteredFailure-8 3000000 482 ns/op 256 B/op 7 allocs/op
BenchmarkStructFilteredFailureParallel-8 10000000 152 ns/op 256 B/op 7 allocs/op BenchmarkStructFilteredFailureParallel-8 10000000 162 ns/op 256 B/op 7 allocs/op
BenchmarkStructPartialSuccess-8 2000000 731 ns/op 256 B/op 6 allocs/op BenchmarkStructPartialSuccess-8 3000000 564 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialSuccessParallel-8 10000000 173 ns/op 256 B/op 6 allocs/op BenchmarkStructPartialSuccessParallel-8 10000000 180 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialFailure-8 1000000 1164 ns/op 480 B/op 11 allocs/op BenchmarkStructPartialFailure-8 2000000 779 ns/op 480 B/op 11 allocs/op
BenchmarkStructPartialFailureParallel-8 5000000 253 ns/op 480 B/op 11 allocs/op BenchmarkStructPartialFailureParallel-8 5000000 268 ns/op 480 B/op 11 allocs/op
BenchmarkStructExceptSuccess-8 1000000 1337 ns/op 496 B/op 12 allocs/op BenchmarkStructExceptSuccess-8 2000000 879 ns/op 496 B/op 12 allocs/op
BenchmarkStructExceptSuccessParallel-8 10000000 153 ns/op 240 B/op 5 allocs/op BenchmarkStructExceptSuccessParallel-8 10000000 163 ns/op 240 B/op 5 allocs/op
BenchmarkStructExceptFailure-8 2000000 954 ns/op 464 B/op 10 allocs/op BenchmarkStructExceptFailure-8 2000000 734 ns/op 464 B/op 10 allocs/op
BenchmarkStructExceptFailureParallel-8 5000000 234 ns/op 464 B/op 10 allocs/op BenchmarkStructExceptFailureParallel-8 5000000 259 ns/op 464 B/op 10 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 3000000 420 ns/op 72 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldSuccess-8 3000000 432 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 125 ns/op 72 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 129 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 2000000 790 ns/op 304 B/op 8 allocs/op BenchmarkStructSimpleCrossFieldFailure-8 2000000 671 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 205 ns/op 304 B/op 8 allocs/op BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 229 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 2000000 611 ns/op 80 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 2000000 628 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 172 ns/op 80 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 182 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 1000000 1112 ns/op 320 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 872 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 258 ns/op 320 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 267 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 5000000 263 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleSuccess-8 5000000 274 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 20000000 83.1 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleSuccessParallel-8 20000000 79.0 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 2000000 964 ns/op 424 B/op 9 allocs/op BenchmarkStructSimpleFailure-8 2000000 647 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 10000000 212 ns/op 424 B/op 9 allocs/op BenchmarkStructSimpleFailureParallel-8 10000000 224 ns/op 424 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1000000 1504 ns/op 128 B/op 8 allocs/op BenchmarkStructComplexSuccess-8 1000000 1557 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexSuccessParallel-8 3000000 427 ns/op 128 B/op 8 allocs/op BenchmarkStructComplexSuccessParallel-8 3000000 473 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexFailure-8 300000 7585 ns/op 3041 B/op 53 allocs/op BenchmarkStructComplexFailure-8 300000 4373 ns/op 3041 B/op 53 allocs/op
BenchmarkStructComplexFailureParallel-8 1000000 1387 ns/op 3041 B/op 53 allocs/op BenchmarkStructComplexFailureParallel-8 1000000 1554 ns/op 3041 B/op 53 allocs/op
``` ```
Complementary Software Complementary Software

@ -131,9 +131,29 @@ var (
"mac": isMAC, "mac": isMAC,
"hostname": isHostname, "hostname": isHostname,
"fqdn": isFQDN, "fqdn": isFQDN,
"unique": isUnique,
} }
) )
// isUnique is the validation function for validating if each array|slice element is unique
func isUnique(fl FieldLevel) bool {
field := fl.Field()
v := reflect.ValueOf(struct{}{})
switch field.Kind() {
case reflect.Slice, reflect.Array:
m := reflect.MakeMap(reflect.MapOf(fl.Field().Type().Elem(), v.Type()))
for i := 0; i < field.Len(); i++ {
m.SetMapIndex(field.Index(i), v)
}
return field.Len() == m.Len()
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
}
// IsMAC is the validation function for validating if the field's value is a valid MAC address. // IsMAC is the validation function for validating if the field's value is a valid MAC address.
func isMAC(fl FieldLevel) bool { func isMAC(fl FieldLevel) bool {

@ -468,6 +468,12 @@ to the top level struct.
Usage: ltecsfield=InnerStructField.Field Usage: ltecsfield=InnerStructField.Field
Unique
For arrays & slices, unique will ensure that there are no duplicates.
Usage: unique
Alpha Only Alpha Only
This validates that a string value contains ASCII alpha characters only This validates that a string value contains ASCII alpha characters only

@ -7272,3 +7272,44 @@ func TestIsDefault(t *testing.T) {
Equal(t, fe.Namespace(), "Test2.inner") Equal(t, fe.Namespace(), "Test2.inner")
Equal(t, fe.Tag(), "isdefault") Equal(t, fe.Tag(), "isdefault")
} }
func TestUniqueValidation(t *testing.T) {
tests := []struct {
param interface{}
expected bool
}{
{[]string{"a", "b"}, true},
{[]int{1, 2}, true},
{[]float64{1, 2}, true},
{[]interface{}{"a", "b"}, true},
{[]interface{}{"a", 1}, true},
{[]float64{1, 1}, false},
{[]int{1, 1}, false},
{[]string{"a", "a"}, false},
{[]interface{}{"a", "a"}, false},
{[]interface{}{"a", 1, "b", 1}, false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.param, "unique")
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "unique" {
t.Fatalf("Index: %d unique failed Error: %v", i, errs)
}
}
}
}
PanicMatches(t, func() { validate.Var(1.0, "unique") }, "Bad field type float64")
}

Loading…
Cancel
Save