Skip to content

Commit 40bd6a0

Browse files
Dean KarnDean Karn
authored andcommitted
Merge pull request #169 from joeybloggs/v8-development
New v8 Changes
2 parents f6ff3d4 + aa72515 commit 40bd6a0

File tree

9 files changed

+579
-351
lines changed

9 files changed

+579
-351
lines changed

README.md

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,46 @@ It has the following **unique** features:
1414
- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
1515
- Handles type interface by determining it's underlying type prior to validation.
1616
- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29)
17+
- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs
1718

1819
Installation
1920
------------
2021

2122
Use go get.
2223

23-
go get gopkg.in/bluesuncorp/validator.v7
24+
go get gopkg.in/bluesuncorp/validator.v8
2425

2526
or to update
2627

27-
go get -u gopkg.in/bluesuncorp/validator.v7
28+
go get -u gopkg.in/bluesuncorp/validator.v8
2829

2930
Then import the validator package into your own code.
3031

31-
import "gopkg.in/bluesuncorp/validator.v7"
32+
import "gopkg.in/bluesuncorp/validator.v8"
33+
34+
Error Return Value
35+
-------
36+
37+
Validation functions return type error
38+
39+
They return type error to avoid the issue discussed in the following, where err is always != nil:
40+
41+
* http://stackoverflow.com/a/29138676/3158232
42+
* https://github.com/bluesuncorp/validator/issues/134
43+
44+
validator only returns nil or ValidationErrors as type error; so in you code all you need to do
45+
is check if the error returned is not nil, and if it's not type cast it to type ValidationErrors
46+
like so:
47+
48+
```go
49+
err := validate.Struct(mystruct)
50+
validationErrors := err.(validator.ValidationErrors)
51+
```
3252

3353
Usage and documentation
3454
------
3555

36-
Please see http://godoc.org/gopkg.in/bluesuncorp/validator.v7 for detailed usage docs.
56+
Please see http://godoc.org/gopkg.in/bluesuncorp/validator.v8 for detailed usage docs.
3757

3858
##### Examples:
3959

@@ -44,7 +64,7 @@ package main
4464
import (
4565
"fmt"
4666

47-
"gopkg.in/bluesuncorp/validator.v7"
67+
"gopkg.in/bluesuncorp/validator.v8"
4868
)
4969

5070
// User contains user information
@@ -69,10 +89,7 @@ var validate *validator.Validate
6989

7090
func main() {
7191

72-
config := validator.Config{
73-
TagName: "validate",
74-
ValidationFuncs: validator.BakedInValidators,
75-
}
92+
config := &validator.Config{TagName: "validate"}
7693

7794
validate = validator.New(config)
7895

@@ -98,13 +115,13 @@ func validateStruct() {
98115
}
99116

100117
// returns nil or ValidationErrors ( map[string]*FieldError )
101-
errs := validate.Struct(user)
118+
err := validate.Struct(user)
102119

103120
if errs != nil {
104121

105122
fmt.Println(errs) // output: Key: "User.Age" Error:Field validation for "Age" failed on the "lte" tag
106123
// Key: "User.Addresses[0].City" Error:Field validation for "City" failed on the "required" tag
107-
err := errs["User.Addresses[0].City"]
124+
err := errs.(validator.ValidationErrors)["User.Addresses[0].City"]
108125
fmt.Println(err.Field) // output: City
109126
fmt.Println(err.Tag) // output: required
110127
fmt.Println(err.Kind) // output: string
@@ -143,7 +160,7 @@ import (
143160
"fmt"
144161
"reflect"
145162

146-
"gopkg.in/bluesuncorp/validator.v7"
163+
"gopkg.in/bluesuncorp/validator.v8"
147164
)
148165

149166
// DbBackedUser User struct
@@ -154,10 +171,7 @@ type DbBackedUser struct {
154171

155172
func main() {
156173

157-
config := validator.Config{
158-
TagName: "validate",
159-
ValidationFuncs: validator.BakedInValidators,
160-
}
174+
config := &validator.Config{TagName: "validate"}
161175

162176
validate := validator.New(config)
163177

@@ -167,7 +181,7 @@ func main() {
167181
x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}
168182
errs := validate.Struct(x)
169183

170-
if len(errs) > 0 {
184+
if len(errs.(validator.ValidationErrors)) > 0 {
171185
fmt.Printf("Errs:\n%+v\n", errs)
172186
}
173187
}
@@ -191,32 +205,32 @@ Benchmarks
191205
```go
192206
$ go test -cpu=4 -bench=. -benchmem=true
193207
PASS
194-
BenchmarkFieldSuccess-4 5000000 285 ns/op 16 B/op 1 allocs/op
195-
BenchmarkFieldFailure-4 5000000 284 ns/op 16 B/op 1 allocs/op
196-
BenchmarkFieldDiveSuccess-4 500000 2501 ns/op 384 B/op 19 allocs/op
197-
BenchmarkFieldDiveFailure-4 500000 3022 ns/op 752 B/op 23 allocs/op
198-
BenchmarkFieldCustomTypeSuccess-4 3000000 445 ns/op 32 B/op 2 allocs/op
199-
BenchmarkFieldCustomTypeFailure-4 2000000 788 ns/op 416 B/op 6 allocs/op
200-
BenchmarkFieldOrTagSuccess-4 1000000 1377 ns/op 32 B/op 2 allocs/op
201-
BenchmarkFieldOrTagFailure-4 1000000 1201 ns/op 400 B/op 6 allocs/op
202-
BenchmarkStructSimpleCustomTypeSuccess-4 1000000 1257 ns/op 80 B/op 5 allocs/op
203-
BenchmarkStructSimpleCustomTypeFailure-4 1000000 1776 ns/op 608 B/op 13 allocs/op
204-
BenchmarkStructPartialSuccess-4 1000000 1354 ns/op 400 B/op 11 allocs/op
205-
BenchmarkStructPartialFailure-4 1000000 1813 ns/op 784 B/op 16 allocs/op
206-
BenchmarkStructExceptSuccess-4 2000000 916 ns/op 368 B/op 9 allocs/op
207-
BenchmarkStructExceptFailure-4 1000000 1369 ns/op 400 B/op 11 allocs/op
208-
BenchmarkStructSimpleCrossFieldSuccess-4 1000000 1033 ns/op 128 B/op 6 allocs/op
209-
BenchmarkStructSimpleCrossFieldFailure-4 1000000 1569 ns/op 528 B/op 11 allocs/op
210-
BenchmarkStructSimpleCrossStructCrossFieldSuccess-4 1000000 1371 ns/op 160 B/op 8 allocs/op
211-
BenchmarkStructSimpleCrossStructCrossFieldFailure-4 1000000 1935 ns/op 560 B/op 13 allocs/op
208+
BenchmarkFieldSuccess-4 5000000 296 ns/op 16 B/op 1 allocs/op
209+
BenchmarkFieldFailure-4 5000000 294 ns/op 16 B/op 1 allocs/op
210+
BenchmarkFieldDiveSuccess-4 500000 2529 ns/op 384 B/op 19 allocs/op
211+
BenchmarkFieldDiveFailure-4 500000 3056 ns/op 768 B/op 23 allocs/op
212+
BenchmarkFieldCustomTypeSuccess-4 3000000 443 ns/op 32 B/op 2 allocs/op
213+
BenchmarkFieldCustomTypeFailure-4 2000000 753 ns/op 384 B/op 4 allocs/op
214+
BenchmarkFieldOrTagSuccess-4 1000000 1334 ns/op 32 B/op 2 allocs/op
215+
BenchmarkFieldOrTagFailure-4 1000000 1172 ns/op 416 B/op 6 allocs/op
216+
BenchmarkStructSimpleCustomTypeSuccess-4 1000000 1206 ns/op 80 B/op 5 allocs/op
217+
BenchmarkStructSimpleCustomTypeFailure-4 1000000 1737 ns/op 592 B/op 11 allocs/op
218+
BenchmarkStructPartialSuccess-4 1000000 1367 ns/op 400 B/op 11 allocs/op
219+
BenchmarkStructPartialFailure-4 1000000 1914 ns/op 800 B/op 16 allocs/op
220+
BenchmarkStructExceptSuccess-4 2000000 909 ns/op 368 B/op 9 allocs/op
221+
BenchmarkStructExceptFailure-4 1000000 1350 ns/op 400 B/op 11 allocs/op
222+
BenchmarkStructSimpleCrossFieldSuccess-4 1000000 1218 ns/op 128 B/op 6 allocs/op
223+
BenchmarkStructSimpleCrossFieldFailure-4 1000000 1783 ns/op 544 B/op 11 allocs/op
224+
BenchmarkStructSimpleCrossStructCrossFieldSuccess-4 1000000 1806 ns/op 160 B/op 8 allocs/op
225+
BenchmarkStructSimpleCrossStructCrossFieldFailure-4 1000000 2369 ns/op 576 B/op 13 allocs/op
212226
BenchmarkStructSimpleSuccess-4 1000000 1161 ns/op 48 B/op 3 allocs/op
213-
BenchmarkStructSimpleFailure-4 1000000 1720 ns/op 560 B/op 11 allocs/op
214-
BenchmarkStructSimpleSuccessParallel-4 5000000 329 ns/op 48 B/op 3 allocs/op
215-
BenchmarkStructSimpleFailureParallel-4 2000000 625 ns/op 560 B/op 11 allocs/op
216-
BenchmarkStructComplexSuccess-4 200000 6636 ns/op 432 B/op 27 allocs/op
217-
BenchmarkStructComplexFailure-4 200000 11327 ns/op 2919 B/op 69 allocs/op
218-
BenchmarkStructComplexSuccessParallel-4 1000000 1991 ns/op 432 B/op 27 allocs/op
219-
BenchmarkStructComplexFailureParallel-4 500000 3854 ns/op 2920 B/op 69 allocs/op
227+
BenchmarkStructSimpleFailure-4 1000000 1813 ns/op 592 B/op 11 allocs/op
228+
BenchmarkStructSimpleSuccessParallel-4 5000000 353 ns/op 48 B/op 3 allocs/op
229+
BenchmarkStructSimpleFailureParallel-4 2000000 656 ns/op 592 B/op 11 allocs/op
230+
BenchmarkStructComplexSuccess-4 200000 7637 ns/op 432 B/op 27 allocs/op
231+
BenchmarkStructComplexFailure-4 100000 12775 ns/op 3128 B/op 69 allocs/op
232+
BenchmarkStructComplexSuccessParallel-4 1000000 2270 ns/op 432 B/op 27 allocs/op
233+
BenchmarkStructComplexFailureParallel-4 300000 4328 ns/op 3128 B/op 69 allocs/op
220234
```
221235

222236
How to Contribute
@@ -225,9 +239,9 @@ How to Contribute
225239
There will always be a development branch for each version i.e. `v1-development`. In order to contribute,
226240
please make your pull requests against those branches.
227241

228-
If the changes being proposed or requested are breaking changes, please create an issue, for discussion
229-
or create a pull request against the highest development branch for example this package has a
230-
v1 and v1-development branch however, there will also be a v2-development brach even though v2 doesn't exist yet.
242+
If the changes being proposed or requested are breaking changes, please create an issue, for discussion
243+
or create a pull request against the highest development branch for example this package has a
244+
v1 and v1-development branch however, there will also be a v2-development branch even though v2 doesn't exist yet.
231245

232246
I strongly encourage everyone whom creates a custom validation function to contribute them and
233247
help make this package even better.

baked_in.go

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ import (
1010
"unicode/utf8"
1111
)
1212

13+
// BakedInAliasValidators is a default mapping of a single validationstag that
14+
// defines a common or complex set of validation(s) to simplify
15+
// adding validation to structs. i.e. set key "_ageok" and the tags
16+
// are "gt=0,lte=130" or key "_preferredname" and tags "omitempty,gt=0,lte=60"
17+
var bakedInAliasValidators = map[string]string{
18+
"iscolor": "hexcolor|rgb|rgba|hsl|hsla",
19+
}
20+
1321
// BakedInValidators is the default map of ValidationFunc
1422
// you can add, remove or even replace items to suite your needs,
1523
// or even disregard and use your own map if so desired.
16-
var BakedInValidators = map[string]Func{
24+
var bakedInValidators = map[string]Func{
1725
"required": hasValue,
1826
"len": hasLengthOf,
1927
"min": hasMinOf,
@@ -107,15 +115,15 @@ func isSSN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va
107115
return false
108116
}
109117

110-
return matchesRegex(sSNRegex, field.String())
118+
return sSNRegex.MatchString(field.String())
111119
}
112120

113121
func isLongitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
114-
return matchesRegex(longitudeRegex, field.String())
122+
return longitudeRegex.MatchString(field.String())
115123
}
116124

117125
func isLatitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
118-
return matchesRegex(latitudeRegex, field.String())
126+
return latitudeRegex.MatchString(field.String())
119127
}
120128

121129
func isDataURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
@@ -126,7 +134,7 @@ func isDataURI(v *Validate, topStruct reflect.Value, currentStructOrField reflec
126134
return false
127135
}
128136

129-
if !matchesRegex(dataURIRegex, uri[0]) {
137+
if !dataURIRegex.MatchString(uri[0]) {
130138
return false
131139
}
132140

@@ -141,31 +149,31 @@ func hasMultiByteCharacter(v *Validate, topStruct reflect.Value, currentStructOr
141149
return true
142150
}
143151

144-
return matchesRegex(multibyteRegex, field.String())
152+
return multibyteRegex.MatchString(field.String())
145153
}
146154

147155
func isPrintableASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
148-
return matchesRegex(printableASCIIRegex, field.String())
156+
return printableASCIIRegex.MatchString(field.String())
149157
}
150158

151159
func isASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
152-
return matchesRegex(aSCIIRegex, field.String())
160+
return aSCIIRegex.MatchString(field.String())
153161
}
154162

155163
func isUUID5(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
156-
return matchesRegex(uUID5Regex, field.String())
164+
return uUID5Regex.MatchString(field.String())
157165
}
158166

159167
func isUUID4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
160-
return matchesRegex(uUID4Regex, field.String())
168+
return uUID4Regex.MatchString(field.String())
161169
}
162170

163171
func isUUID3(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
164-
return matchesRegex(uUID3Regex, field.String())
172+
return uUID3Regex.MatchString(field.String())
165173
}
166174

167175
func isUUID(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
168-
return matchesRegex(uUIDRegex, field.String())
176+
return uUIDRegex.MatchString(field.String())
169177
}
170178

171179
func isISBN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
@@ -176,7 +184,7 @@ func isISBN13(v *Validate, topStruct reflect.Value, currentStructOrField reflect
176184

177185
s := strings.Replace(strings.Replace(field.String(), "-", "", 4), " ", "", 4)
178186

179-
if !matchesRegex(iSBN13Regex, s) {
187+
if !iSBN13Regex.MatchString(s) {
180188
return false
181189
}
182190

@@ -200,7 +208,7 @@ func isISBN10(v *Validate, topStruct reflect.Value, currentStructOrField reflect
200208

201209
s := strings.Replace(strings.Replace(field.String(), "-", "", 3), " ", "", 3)
202210

203-
if !matchesRegex(iSBN10Regex, s) {
211+
if !iSBN10Regex.MatchString(s) {
204212
return false
205213
}
206214

@@ -617,7 +625,7 @@ func isEq(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Val
617625
}
618626

619627
func isBase64(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
620-
return matchesRegex(base64Regex, field.String())
628+
return base64Regex.MatchString(field.String())
621629
}
622630

623631
func isURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
@@ -655,47 +663,47 @@ func isURL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Va
655663
}
656664

657665
func isEmail(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
658-
return matchesRegex(emailRegex, field.String())
666+
return emailRegex.MatchString(field.String())
659667
}
660668

661669
func isHsla(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
662-
return matchesRegex(hslaRegex, field.String())
670+
return hslaRegex.MatchString(field.String())
663671
}
664672

665673
func isHsl(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
666-
return matchesRegex(hslRegex, field.String())
674+
return hslRegex.MatchString(field.String())
667675
}
668676

669677
func isRgba(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
670-
return matchesRegex(rgbaRegex, field.String())
678+
return rgbaRegex.MatchString(field.String())
671679
}
672680

673681
func isRgb(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
674-
return matchesRegex(rgbRegex, field.String())
682+
return rgbRegex.MatchString(field.String())
675683
}
676684

677685
func isHexcolor(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
678-
return matchesRegex(hexcolorRegex, field.String())
686+
return hexcolorRegex.MatchString(field.String())
679687
}
680688

681689
func isHexadecimal(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
682-
return matchesRegex(hexadecimalRegex, field.String())
690+
return hexadecimalRegex.MatchString(field.String())
683691
}
684692

685693
func isNumber(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
686-
return matchesRegex(numberRegex, field.String())
694+
return numberRegex.MatchString(field.String())
687695
}
688696

689697
func isNumeric(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
690-
return matchesRegex(numericRegex, field.String())
698+
return numericRegex.MatchString(field.String())
691699
}
692700

693701
func isAlphanum(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
694-
return matchesRegex(alphaNumericRegex, field.String())
702+
return alphaNumericRegex.MatchString(field.String())
695703
}
696704

697705
func isAlpha(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
698-
return matchesRegex(alphaRegex, field.String())
706+
return alphaRegex.MatchString(field.String())
699707
}
700708

701709
func hasValue(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {

0 commit comments

Comments
 (0)