Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 63 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package validator
================
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-9.8.0-green.svg)
![Project status](https://img.shields.io/badge/version-9.9.0-green.svg)
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
Expand All @@ -13,7 +13,8 @@ Package validator implements value validations for structs and individual fields
It has the following **unique** features:

- Cross Field and Cross Struct validations by using validation tags or custom validators.
- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
- Ability to dive into both map keys and values for validation
- Handles type interface by determining it's underlying type prior to validation.
- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29)
- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs
Expand Down Expand Up @@ -65,61 +66,69 @@ Please see http://godoc.org/gopkg.in/go-playground/validator.v9 for detailed usa

Benchmarks
------
###### Run on MacBook Pro (15-inch, 2017) Go version go1.9.1 linux/amd64
###### Run on MacBook Pro (15-inch, 2017) Go version go1.9.2 darwin/amd64
```go
go test -bench=. -benchmem=true
BenchmarkFieldSuccess-8 20000000 87.2 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 50000000 26.1 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 5000000 299 ns/op 208 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 20000000 100 ns/op 208 B/op 4 allocs/op
BenchmarkFieldDiveSuccess-8 2000000 645 ns/op 201 B/op 11 allocs/op
BenchmarkFieldDiveSuccessParallel-8 10000000 198 ns/op 201 B/op 11 allocs/op
BenchmarkFieldDiveFailure-8 2000000 876 ns/op 412 B/op 16 allocs/op
BenchmarkFieldDiveFailureParallel-8 5000000 268 ns/op 413 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-8 10000000 228 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 20000000 70.0 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 5000000 286 ns/op 208 B/op 4 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 20000000 95.6 ns/op 208 B/op 4 allocs/op
BenchmarkFieldOrTagSuccess-8 2000000 857 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 3000000 397 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 3000000 495 ns/op 224 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 5000000 376 ns/op 224 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 10000000 226 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 20000000 68.4 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationFailure-8 3000000 497 ns/op 304 B/op 8 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 10000000 170 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 3000000 420 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 20000000 124 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 2000000 681 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 10000000 244 ns/op 440 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 2000000 659 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredSuccessParallel-8 10000000 211 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredFailure-8 3000000 482 ns/op 256 B/op 7 allocs/op
BenchmarkStructFilteredFailureParallel-8 10000000 162 ns/op 256 B/op 7 allocs/op
BenchmarkStructPartialSuccess-8 3000000 564 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialSuccessParallel-8 10000000 180 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialFailure-8 2000000 779 ns/op 480 B/op 11 allocs/op
BenchmarkStructPartialFailureParallel-8 5000000 268 ns/op 480 B/op 11 allocs/op
BenchmarkStructExceptSuccess-8 2000000 879 ns/op 496 B/op 12 allocs/op
BenchmarkFieldSuccess-8 20000000 79.9 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 50000000 25.0 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 5000000 281 ns/op 208 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 20000000 97.0 ns/op 208 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-8 3000000 591 ns/op 201 B/op 11 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8 10000000 195 ns/op 201 B/op 11 allocs/op
BenchmarkFieldArrayDiveFailure-8 2000000 878 ns/op 412 B/op 16 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8 5000000 274 ns/op 413 B/op 16 allocs/op
BenchmarkFieldMapDiveSuccess-8 1000000 1279 ns/op 432 B/op 18 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8 5000000 401 ns/op 432 B/op 18 allocs/op
BenchmarkFieldMapDiveFailure-8 1000000 1060 ns/op 512 B/op 16 allocs/op
BenchmarkFieldMapDiveFailureParallel-8 5000000 334 ns/op 512 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1462 ns/op 480 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 463 ns/op 480 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1414 ns/op 721 B/op 21 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 446 ns/op 721 B/op 21 allocs/op
BenchmarkFieldCustomTypeSuccess-8 10000000 211 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 20000000 65.9 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 5000000 270 ns/op 208 B/op 4 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 20000000 93.3 ns/op 208 B/op 4 allocs/op
BenchmarkFieldOrTagSuccess-8 2000000 729 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 5000000 367 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 3000000 472 ns/op 224 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 5000000 373 ns/op 224 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 10000000 201 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 20000000 66.3 ns/op 32 B/op 2 allocs/op
BenchmarkStructLevelValidationFailure-8 3000000 468 ns/op 304 B/op 8 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 10000000 172 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 5000000 376 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 20000000 126 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 2000000 646 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 10000000 240 ns/op 440 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 3000000 582 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredSuccessParallel-8 10000000 198 ns/op 288 B/op 9 allocs/op
BenchmarkStructFilteredFailure-8 3000000 447 ns/op 256 B/op 7 allocs/op
BenchmarkStructFilteredFailureParallel-8 10000000 156 ns/op 256 B/op 7 allocs/op
BenchmarkStructPartialSuccess-8 3000000 536 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialSuccessParallel-8 10000000 175 ns/op 256 B/op 6 allocs/op
BenchmarkStructPartialFailure-8 2000000 738 ns/op 480 B/op 11 allocs/op
BenchmarkStructPartialFailureParallel-8 5000000 256 ns/op 480 B/op 11 allocs/op
BenchmarkStructExceptSuccess-8 2000000 835 ns/op 496 B/op 12 allocs/op
BenchmarkStructExceptSuccessParallel-8 10000000 163 ns/op 240 B/op 5 allocs/op
BenchmarkStructExceptFailure-8 2000000 734 ns/op 464 B/op 10 allocs/op
BenchmarkStructExceptFailureParallel-8 5000000 259 ns/op 464 B/op 10 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 3000000 432 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 129 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 2000000 671 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 229 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 2000000 628 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 182 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 872 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 267 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 5000000 274 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 20000000 79.0 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 2000000 647 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 10000000 224 ns/op 424 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1000000 1557 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexSuccessParallel-8 3000000 473 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexFailure-8 300000 4373 ns/op 3041 B/op 53 allocs/op
BenchmarkStructComplexFailureParallel-8 1000000 1554 ns/op 3041 B/op 53 allocs/op
BenchmarkStructExceptFailure-8 2000000 682 ns/op 464 B/op 10 allocs/op
BenchmarkStructExceptFailureParallel-8 10000000 244 ns/op 464 B/op 10 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 5000000 392 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 20000000 126 ns/op 72 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 2000000 611 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 214 ns/op 304 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 567 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 177 ns/op 80 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 807 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 268 ns/op 320 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 5000000 256 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 20000000 76.3 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 2000000 625 ns/op 424 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 10000000 219 ns/op 424 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1000000 1431 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexSuccessParallel-8 3000000 427 ns/op 128 B/op 8 allocs/op
BenchmarkStructComplexFailure-8 300000 4065 ns/op 3041 B/op 53 allocs/op
BenchmarkStructComplexFailureParallel-8 1000000 1478 ns/op 3041 B/op 53 allocs/op
```

Complementary Software
Expand Down
39 changes: 39 additions & 0 deletions _examples/dive/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"fmt"

"gopkg.in/go-playground/validator.v9"
)

// Test ...
type Test struct {
Array []string `validate:"required,gt=0,dive,required"`
Map map[string]string `validate:"required,gt=0,dive,keys,keymax,endkeys,required,max=1000"`
}

// use a single instance of Validate, it caches struct info
var validate *validator.Validate

func main() {

validate = validator.New()

// registering alias so we can see the differences between
// map key, value validation errors
validate.RegisterAlias("keymax", "max=10")

var test Test

val(test)

test.Array = []string{""}
test.Map = map[string]string{"test > than 10": ""}
val(test)
}

func val(test Test) {
fmt.Println("testing")
err := validate.Struct(test)
fmt.Println(err)
}
2 changes: 2 additions & 0 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ func wrapFunc(fn Func) FuncCtx {
var (
restrictedTags = map[string]struct{}{
diveTag: {},
keysTag: {},
endKeysTag: {},
structOnlyTag: {},
omitempty: {},
skipValidationTag: {},
Expand Down
114 changes: 110 additions & 4 deletions benchmarks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func BenchmarkFieldFailureParallel(b *testing.B) {
})
}

func BenchmarkFieldDiveSuccess(b *testing.B) {
func BenchmarkFieldArrayDiveSuccess(b *testing.B) {

validate := New()

Expand All @@ -72,7 +72,7 @@ func BenchmarkFieldDiveSuccess(b *testing.B) {
}
}

func BenchmarkFieldDiveSuccessParallel(b *testing.B) {
func BenchmarkFieldArrayDiveSuccessParallel(b *testing.B) {

validate := New()

Expand All @@ -86,7 +86,7 @@ func BenchmarkFieldDiveSuccessParallel(b *testing.B) {
})
}

func BenchmarkFieldDiveFailure(b *testing.B) {
func BenchmarkFieldArrayDiveFailure(b *testing.B) {

validate := New()

Expand All @@ -98,7 +98,7 @@ func BenchmarkFieldDiveFailure(b *testing.B) {
}
}

func BenchmarkFieldDiveFailureParallel(b *testing.B) {
func BenchmarkFieldArrayDiveFailureParallel(b *testing.B) {

validate := New()

Expand All @@ -112,6 +112,112 @@ func BenchmarkFieldDiveFailureParallel(b *testing.B) {
})
}

func BenchmarkFieldMapDiveSuccess(b *testing.B) {

validate := New()

m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}

b.ResetTimer()

for n := 0; n < b.N; n++ {
validate.Var(m, "required,dive,required")
}
}

func BenchmarkFieldMapDiveSuccessParallel(b *testing.B) {

validate := New()

m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}

b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
validate.Var(m, "required,dive,required")
}
})
}

func BenchmarkFieldMapDiveFailure(b *testing.B) {

validate := New()

m := map[string]string{"": "", "val3": "val3"}

b.ResetTimer()
for n := 0; n < b.N; n++ {
validate.Var(m, "required,dive,required")
}
}

func BenchmarkFieldMapDiveFailureParallel(b *testing.B) {

validate := New()

m := map[string]string{"": "", "val3": "val3"}

b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
validate.Var(m, "required,dive,required")
}
})
}

func BenchmarkFieldMapDiveWithKeysSuccess(b *testing.B) {

validate := New()

m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}

b.ResetTimer()

for n := 0; n < b.N; n++ {
validate.Var(m, "required,dive,keys,required,endkeys,required")
}
}

func BenchmarkFieldMapDiveWithKeysSuccessParallel(b *testing.B) {

validate := New()

m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}

b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
validate.Var(m, "required,dive,keys,required,endkeys,required")
}
})
}

func BenchmarkFieldMapDiveWithKeysFailure(b *testing.B) {

validate := New()

m := map[string]string{"": "", "val3": "val3"}

b.ResetTimer()
for n := 0; n < b.N; n++ {
validate.Var(m, "required,dive,keys,required,endkeys,required")
}
}

func BenchmarkFieldMapDiveWithKeysFailureParallel(b *testing.B) {

validate := New()

m := map[string]string{"": "", "val3": "val3"}

b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
validate.Var(m, "required,dive,keys,required,endkeys,required")
}
})
}

func BenchmarkFieldCustomTypeSuccess(b *testing.B) {

validate := New()
Expand Down
Loading