Merge pull request #361 from jservice-rvbd/unique-for-maps

Extend the unique tag to also cover map values.
pull/362/head
Dean Karn 7 years ago committed by GitHub
commit b297167b88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      baked_in.go
  2. 1
      doc.go
  3. 23
      validator_test.go

@ -1,7 +1,9 @@
package validator package validator
import ( import (
"bytes"
"context" "context"
"crypto/sha256"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
@ -11,8 +13,6 @@ import (
"sync" "sync"
"time" "time"
"unicode/utf8" "unicode/utf8"
"crypto/sha256"
"bytes"
) )
// Func accepts a FieldLevel interface for all validation needs. The return // Func accepts a FieldLevel interface for all validation needs. The return
@ -187,7 +187,7 @@ func isOneOf(fl FieldLevel) bool {
return false return false
} }
// isUnique is the validation function for validating if each array|slice element is unique // isUnique is the validation function for validating if each array|slice|map value is unique
func isUnique(fl FieldLevel) bool { func isUnique(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -195,12 +195,19 @@ func isUnique(fl FieldLevel) bool {
switch field.Kind() { switch field.Kind() {
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
m := reflect.MakeMap(reflect.MapOf(fl.Field().Type().Elem(), v.Type())) m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type()))
for i := 0; i < field.Len(); i++ { for i := 0; i < field.Len(); i++ {
m.SetMapIndex(field.Index(i), v) m.SetMapIndex(field.Index(i), v)
} }
return field.Len() == m.Len() return field.Len() == m.Len()
case reflect.Map:
m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type()))
for _, k := range field.MapKeys() {
m.SetMapIndex(field.MapIndex(k), v)
}
return field.Len() == m.Len()
default: default:
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }

@ -506,6 +506,7 @@ to the top level struct.
Unique Unique
For arrays & slices, unique will ensure that there are no duplicates. For arrays & slices, unique will ensure that there are no duplicates.
For maps, unique will ensure that there are no duplicate values.
Usage: unique Usage: unique

@ -7696,6 +7696,18 @@ func TestUniqueValidation(t *testing.T) {
param interface{} param interface{}
expected bool expected bool
}{ }{
// Arrays
{[2]string{"a", "b"}, true},
{[2]int{1, 2}, true},
{[2]float64{1, 2}, true},
{[2]interface{}{"a", "b"}, true},
{[2]interface{}{"a", 1}, true},
{[2]float64{1, 1}, false},
{[2]int{1, 1}, false},
{[2]string{"a", "a"}, false},
{[2]interface{}{"a", "a"}, false},
{[4]interface{}{"a", 1, "b", 1}, false},
// Slices
{[]string{"a", "b"}, true}, {[]string{"a", "b"}, true},
{[]int{1, 2}, true}, {[]int{1, 2}, true},
{[]float64{1, 2}, true}, {[]float64{1, 2}, true},
@ -7706,6 +7718,17 @@ func TestUniqueValidation(t *testing.T) {
{[]string{"a", "a"}, false}, {[]string{"a", "a"}, false},
{[]interface{}{"a", "a"}, false}, {[]interface{}{"a", "a"}, false},
{[]interface{}{"a", 1, "b", 1}, false}, {[]interface{}{"a", 1, "b", 1}, false},
// Maps
{map[string]string{"one": "a", "two": "b"}, true},
{map[string]int{"one": 1, "two": 2}, true},
{map[string]float64{"one": 1, "two": 2}, true},
{map[string]interface{}{"one": "a", "two": "b"}, true},
{map[string]interface{}{"one": "a", "two": 1}, true},
{map[string]float64{"one": 1, "two": 1}, false},
{map[string]int{"one": 1, "two": 1}, false},
{map[string]string{"one": "a", "two": "a"}, false},
{map[string]interface{}{"one": "a", "two": "a"}, false},
{map[string]interface{}{"one": "a", "two": 1, "three": "b", "four": 1}, false},
} }
validate := New() validate := New()

Loading…
Cancel
Save