Merge pull request #97 from bluesuncorp/v5

merge latest changes from v5
pull/115/head
Dean Karn 10 years ago
commit 31fb6bb006
  1. 4
      .gitignore
  2. 117
      README.md
  3. 85
      examples/simple.go
  4. 25
      validator_test.go

4
.gitignore vendored

@ -23,4 +23,6 @@ _testmain.go
*.test *.test
*.prof *.prof
*.test *.test
*.out *.out
cover.html
README.html

@ -5,10 +5,15 @@ Package validator
[![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v5?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v5) [![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v5?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v5)
Package validator implements value validations for structs and individual fields based on tags. Package validator implements value validations for structs and individual fields based on tags.
It is also capable of Cross Field and Cross Struct validations.
It has the following **unique** features:
- Cross Field and Cross Struct validations.
- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
- Handles type interface by determining it's underlying type prior to validation.
Installation Installation
============ ------------
Use go get. Use go get.
@ -23,12 +28,114 @@ Then import the validator package into your own code.
import "gopkg.in/bluesuncorp/validator.v5" import "gopkg.in/bluesuncorp/validator.v5"
Usage and documentation Usage and documentation
======================= ------
Please see http://godoc.org/gopkg.in/bluesuncorp/validator.v5 for detailed usage docs. Please see http://godoc.org/gopkg.in/bluesuncorp/validator.v5 for detailed usage docs.
##### Example:
```go
package main
import (
"fmt"
"gopkg.in/bluesuncorp/validator.v5"
)
// User contains user information
type User struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
FavouriteColor string `validate:"hexcolor|rgb|rgba"`
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}
// Address houses a users address information
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
var validate *validator.Validate
func main() {
validate = validator.New("validate", validator.BakedInValidators)
address := &Address{
Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
}
user := &User{
FirstName: "Badger",
LastName: "Smith",
Age: 135,
Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000",
Addresses: []*Address{address},
}
// returns nil or *StructErrors
errs := validate.Struct(user)
if errs != nil {
// err will be of type *FieldError
err := errs.Errors["Age"]
fmt.Println(err.Error()) // output: Field validation for "Age" failed on the "lte" tag
fmt.Println(err.Field) // output: Age
fmt.Println(err.Tag) // output: lte
fmt.Println(err.Kind) // output: uint8
fmt.Println(err.Type) // output: uint8
fmt.Println(err.Param) // output: 130
fmt.Println(err.Value) // output: 135
// or if you prefer you can use the Flatten function
// NOTE: I find this usefull when using a more hard static approach of checking field errors.
// The above, is best for passing to some generic code to say parse the errors. i.e. I pass errs
// to a routine which loops through the errors, creates and translates the error message into the
// users locale and returns a map of map[string]string // field and error which I then use
// within the HTML rendering.
flat := errs.Flatten()
fmt.Println(flat) // output: map[Age:Field validation for "Age" failed on the "lte" tag Addresses[0].Address.City:Field validation for "City" failed on the "required" tag]
err = flat["Addresses[0].Address.City"]
fmt.Println(err.Field) // output: City
fmt.Println(err.Tag) // output: required
fmt.Println(err.Kind) // output: string
fmt.Println(err.Type) // output: string
fmt.Println(err.Param) // output:
fmt.Println(err.Value) // output:
// from here you can create your own error messages in whatever language you wish
return
}
// save user to database
}
```
Benchmarks
------
###### Run on MacBook Pro (Retina, 15-inch, Late 2013) 2.6 GHz Intel Core i7 16 GB 1600 MHz DDR3
```go
$ go test -cpu=4 -bench=. -benchmem=true
PASS
BenchmarkValidateField-4 3000000 436 ns/op 192 B/op 2 allocs/op
BenchmarkValidateStructSimple-4 500000 2863 ns/op 784 B/op 13 allocs/op
BenchmarkTemplateParallelSimple-4 500000 3044 ns/op 784 B/op 13 allocs/op
BenchmarkValidateStructLarge-4 100000 15226 ns/op 4853 B/op 74 allocs/op
BenchmarkTemplateParallelLarge-4 100000 14637 ns/op 4856 B/op 74 allocs/op
```
How to Contribute How to Contribute
================= ------
There will always be a development branch for each version i.e. `v1-development`. In order to contribute, There will always be a development branch for each version i.e. `v1-development`. In order to contribute,
please make your pull requests against those branches. please make your pull requests against those branches.
@ -41,5 +148,5 @@ I strongly encourage everyone whom creates a custom validation function to contr
help make this package even better. help make this package even better.
License License
======= ------
Distributed under MIT License, please see license file in code for more details. Distributed under MIT License, please see license file in code for more details.

@ -0,0 +1,85 @@
package main
import (
"fmt"
"gopkg.in/bluesuncorp/validator.v5"
)
// User contains user information
type User struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
FavouriteColor string `validate:"hexcolor|rgb|rgba"`
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}
// Address houses a users address information
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
var validate *validator.Validate
func main() {
validate = validator.New("validate", validator.BakedInValidators)
address := &Address{
Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
}
user := &User{
FirstName: "Badger",
LastName: "Smith",
Age: 135,
Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000",
Addresses: []*Address{address},
}
// returns nil or *StructErrors
errs := validate.Struct(user)
if errs != nil {
// err will be of type *FieldError
err := errs.Errors["Age"]
fmt.Println(err.Error()) // output: Field validation for "Age" failed on the "lte" tag
fmt.Println(err.Field) // output: Age
fmt.Println(err.Tag) // output: lte
fmt.Println(err.Kind) // output: uint8
fmt.Println(err.Type) // output: uint8
fmt.Println(err.Param) // output: 130
fmt.Println(err.Value) // output: 135
// or if you prefer you can use the Flatten function
// NOTE: I find this usefull when using a more hard static approach of checking field errors.
// The above, is best for passing to some generic code to say parse the errors. i.e. I pass errs
// to a routine which loops through the errors, creates and translates the error message into the
// users locale and returns a map of map[string]string // field and error which I then use
// within the HTML rendering.
flat := errs.Flatten()
fmt.Println(flat) // output: map[Age:Field validation for "Age" failed on the "lte" tag Addresses[0].Address.City:Field validation for "City" failed on the "required" tag]
err = flat["Addresses[0].Address.City"]
fmt.Println(err.Field) // output: City
fmt.Println(err.Tag) // output: required
fmt.Println(err.Kind) // output: string
fmt.Println(err.Type) // output: string
fmt.Println(err.Param) // output:
fmt.Println(err.Value) // output:
// from here you can create your own error messages in whatever language you wish
return
}
// save user to database
}

@ -14,6 +14,11 @@ import (
// - Run "gocov test | gocov report" to report on test converage by file // - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called // - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
// //
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
// //
// go test -cpuprofile cpu.out // go test -cpuprofile cpu.out
// ./validator.test -test.bench=. -test.cpuprofile=cpu.prof // ./validator.test -test.bench=. -test.cpuprofile=cpu.prof
@ -3765,3 +3770,23 @@ func TestInvalidValidatorFunction(t *testing.T) {
PanicMatches(t, func() { validate.Field(s.Test, "zzxxBadFunction") }, fmt.Sprintf("Undefined validation function on field %s", "")) PanicMatches(t, func() { validate.Field(s.Test, "zzxxBadFunction") }, fmt.Sprintf("Undefined validation function on field %s", ""))
} }
func TestPoolObjectMaxSizeValidation(t *testing.T) {
// this will ensure that the pool objects are let go
// when the pool is saturated
validate.SetMaxStructPoolSize(0)
tSuccess := &TestSlice{
Required: []int{1},
Len: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
Min: []int{1, 2},
Max: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
MinMax: []int{1, 2, 3, 4, 5},
OmitEmpty: []int{},
}
for i := 0; i < 2; i++ {
err := validate.Struct(tSuccess)
Equal(t, err, nil)
}
}

Loading…
Cancel
Save