Extend the unique tag to also cover map values.

pull/361/head
James Service 7 years ago
parent 14984d9132
commit 8ae3903dd3
  1. 33
      baked_in.go
  2. 23
      validator_test.go

@ -1,7 +1,9 @@
package validator
import (
"bytes"
"context"
"crypto/sha256"
"fmt"
"net"
"net/url"
@ -11,8 +13,6 @@ import (
"sync"
"time"
"unicode/utf8"
"crypto/sha256"
"bytes"
)
// Func accepts a FieldLevel interface for all validation needs. The return
@ -187,7 +187,7 @@ func isOneOf(fl FieldLevel) bool {
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 {
field := fl.Field()
@ -195,12 +195,19 @@ func isUnique(fl FieldLevel) bool {
switch field.Kind() {
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++ {
m.SetMapIndex(field.Index(i), v)
}
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:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
@ -451,13 +458,13 @@ func isBitcoinAddress(fl FieldLevel) bool {
func isBitcoinBech32Address(fl FieldLevel) bool {
address := fl.Field().String()
if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address){
if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address) {
return false
}
am := len(address) % 8
if am == 0 || am == 3 || am == 5{
if am == 0 || am == 3 || am == 5 {
return false
}
@ -474,7 +481,7 @@ func isBitcoinBech32Address(fl FieldLevel) bool {
ver := dp[0]
if ver < 0 || ver > 16{
if ver < 0 || ver > 16 {
return false
}
@ -486,16 +493,16 @@ func isBitcoinBech32Address(fl FieldLevel) bool {
values := append(hr, dp...)
GEN := []int{ 0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3 }
GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
p := 1
for _, v := range values {
b := p >> 25
p = (p & 0x1ffffff) << 5 ^ v
p = (p&0x1ffffff)<<5 ^ v
for i := 0; i < 5; i++ {
if (b >> uint(i)) & 1 == 1 {
if (b>>uint(i))&1 == 1 {
p ^= GEN[i]
}
}
@ -510,16 +517,16 @@ func isBitcoinBech32Address(fl FieldLevel) bool {
mv := (1 << 5) - 1
sw := []int{}
for _, v := range dp[1:len(dp) - 6]{
for _, v := range dp[1 : len(dp)-6] {
acc = (acc << 5) | v
b += 5
for b >= 8{
for b >= 8 {
b -= 8
sw = append(sw, (acc>>b)&mv)
}
}
if len(sw) < 2 || len(sw) > 40{
if len(sw) < 2 || len(sw) > 40 {
return false
}

@ -7696,6 +7696,18 @@ func TestUniqueValidation(t *testing.T) {
param interface{}
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},
{[]int{1, 2}, true},
{[]float64{1, 2}, true},
@ -7706,6 +7718,17 @@ func TestUniqueValidation(t *testing.T) {
{[]string{"a", "a"}, false},
{[]interface{}{"a", "a"}, 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()

Loading…
Cancel
Save