Skip to content

Commit 4fc4748

Browse files
committed
update readme. some bug fixed
1 parent cbf4d2d commit 4fc4748

8 files changed

+127
-103
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The package is a generic Go data validate library.
99

1010
> **[中文说明](README_cn.md)**
1111
12-
- Support validate Map, Struct, Request(Form, JSON, url.Values) data
12+
- Support validate Map, Struct, Request(Form, JSON, url.Values, UploadedFile) data
1313
- Support filter/sanitize data before validate
1414
- Support add custom filter/validator func
1515
- Support scene settings, verify different fields in different scenes
@@ -285,15 +285,15 @@ validator/aliases | description
285285
`dnsName/DNSName/isDNSName` | Check value is DNSName string.
286286
`dataURI/isDataURI` | Check value is DataURI string.
287287
`empty/isEmpty` | Check value is Empty string.
288-
`hexColor/isHexColor` | Check value is HexColor string.
288+
`hexColor/isHexColor` | Check value is Hex color string.
289289
`hexadecimal/isHexadecimal` | Check value is Hexadecimal string.
290290
`json/JSON/isJSON` | Check value is JSON string.
291291
`lat/latitude/isLatitude` | Check value is Latitude string.
292292
`lon/longitude/isLongitude` | Check value is Longitude string.
293293
`mac/isMAC` | Check value is MAC string.
294294
`num/number/isNumber` | Check value is number string. `>= 0`
295295
`printableASCII/isPrintableASCII` | Check value is PrintableASCII string.
296-
`rgbColor/RGBColor/isRGBColor` | Check value is RGBColor string.
296+
`rgbColor/RGBColor/isRGBColor` | Check value is RGB color string.
297297
`url/isURL` | Check value is URL string.
298298
`ip/isIP` | Check value is IP(v4 or v6) string.
299299
`ipv4/isIPv4` | Check value is IPv4 string.

README_cn.md

+44-43
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77

88
Go通用的数据验证与过滤库,使用简单,内置大部分常用验证器、过滤器,支持自定义消息、字段翻译。
99

10-
- 支持验证Map,Struct,Request(Form,JSON,url.Values)数据
10+
> **[EN README](README.md)**
11+
12+
- 支持验证Map,Struct,Request(Form,JSON,url.Values, UploadedFile)数据
1113
- 简单方便,支持前置验证检查, 支持添加自定义验证器
1214
- 支持将规则按场景进行分组设置。不同场景验证不同的字段
13-
- 支持自定义每个验证的错误消息,字段翻译,消息翻译(内置`en` `zh-CN`)
1415
- 支持在进行验证前对值使用过滤器进行净化过滤,查看 [内置过滤器](#built-in-filters)
15-
- 方便的获取错误信息,验证后的安全数据获取(只会收集有规则检查过的数据)
1616
- 已经内置了超多(> 60 个)常用的验证器,查看 [内置验证器](#built-in-validators)
17+
- 方便的获取错误信息,验证后的安全数据获取(只会收集有规则检查过的数据)
18+
- 支持自定义每个验证的错误消息,字段翻译,消息翻译(内置`en` `zh-CN`)
1719
- 完善的单元测试,覆盖率 > 85%
1820

1921
> 受到这些项目的启发 [albrow/forms](https://github.com/albrow/forms)[asaskevich/govalidator](https://github.com/asaskevich/govalidator). 非常感谢它们
@@ -270,58 +272,57 @@ v := d.Validation()
270272
`range/between` | 检查值是否为数字且在给定范围内
271273
`max/lte` | 检查输入值小于或等于给定值
272274
`min/gte` | 检查输入值大于或等于给定值(for `intX` `uintX` `floatX`)
273-
`intStr/intString/isIntString` | Check value is an int string.
274275
`eq/equal/isEqual` | 检查输入值是否等于给定值
275276
`ne/notEq/notEqual` | 检查输入值是否不等于给定值
276-
`lt/lessThan` | Check value is less than the given size(use for `intX` `uintX` `floatX`)
277-
`gt/greaterThan` | Check value is greater than the given size(use for `intX` `uintX` `floatX`)
278-
`email/isEmail` | Check value is email address string.
279-
`intEq/intEqual` | Check value is int and equals to the given value.
280-
`len/length` | Check value length is equals to the given size(use for `string` `array` `slice` `map`).
281-
`regex/regexp` | Check if the value can pass the regular verification
282-
`arr/array/isArray` | Check value is array type
283-
`map/isMap` | Check value is a MAP type
284-
`strings/isStrings` | Check value is string slice type(only allow `[]string`).
285-
`ints/isInts` | Check value is int slice type(only allow `[]int`).
286-
`minLen/minLength` | Check the minimum length of the value is the given size
287-
`maxLen/maxLength` | Check the maximum length of the value is the given size
288-
`eqField` | Check that the field value is equals to the value of another field
289-
`neField` | Check that the field value is not equals to the value of another field
290-
`gteField` | Check that the field value is greater than or equal to the value of another field
291-
`gtField` | Check that the field value is greater than the value of another field
292-
`lteField` | Check if the field value is less than or equal to the value of another field
293-
`ltField` | Check that the field value is less than the value of another field
277+
`lt/lessThan` | 检查值小于给定大小(use for `intX` `uintX` `floatX`)
278+
`gt/greaterThan` | 检查值大于给定大小(use for `intX` `uintX` `floatX`)
279+
`intEq/intEqual` | 检查值为int且等于给定值
280+
`len/length` | 检查值长度等于给定大小(use for `string` `array` `slice` `map`).
281+
`minLen/minLength` | 检查值的最小长度是给定大小
282+
`maxLen/maxLength` | 检查值的最大长度是给定大小
283+
`email/isEmail` | 检查值是Email地址字符串
284+
`regex/regexp` | 检查该值是否可以通过正则验证
285+
`arr/array/isArray` | 检查值是数组`array`类型
286+
`map/isMap` | 检查值是MAP类型
287+
`strings/isStrings` | 检查值是字符串切片类型(`[]string`).
288+
`ints/isInts` | 检查值是int slice类型(only allow `[]int`).
289+
`eqField` | 检查字段值是否等于另一个字段的值
290+
`neField` | 检查字段值是否不等于另一个字段的值
291+
`gtField` | 检查字段值是否大于另一个字段的值
292+
`gteField` | 检查字段值是否大于或等于另一个字段的值
293+
`ltField` | 检查字段值是否小于另一个字段的值
294+
`lteField` | 检查字段值是否小于或等于另一个字段的值
294295
`file/isFile` | 验证是否是上传的文件
295296
`image/isImage` | 验证是否是上传的图片文件,支持后缀检查
296297
`mime/mimeType/inMimeTypes` | 验证是否是上传的文件,并且在指定的MIME类型中
297-
`date/isDate` | Check the field value is date string. eg `2018-10-25`
298-
`gtDate/afterDate` | Check that the input value is greater than the given date string.
299-
`ltDate/beforeDate` | Check that the input value is less than the given date string
300-
`gteDate/afterOrEqualDate` | Check that the input value is greater than or equal to the given date string.
301-
`lteDate/beforeOrEqualDate` | Check that the input value is less than or equal to the given date string.
302-
`hasWhitespace` | Check value string has Whitespace.
303-
`ascii/ASCII/isASCII` | Check value is ASCII string.
298+
`date/isDate` | 检查字段值是否为日期字符串。(只支持几种常用的格式) eg `2018-10-25`
299+
`gtDate/afterDate` | 检查输入值是否大于给定的日期字符串
300+
`ltDate/beforeDate` | 检查输入值是否小于给定的日期字符串
301+
`gteDate/afterOrEqualDate` | 检查输入值是否大于或等于给定的日期字符串
302+
`lteDate/beforeOrEqualDate` | 检查输入值是否小于或等于给定的日期字符串
303+
`hasWhitespace` | 检查字符串值是否有空格
304+
`ascii/ASCII/isASCII` | 检查值是ASCII字符串
304305
`alpha/isAlpha` | 验证值是否仅包含字母字符
305306
`alphaNum/isAlphaNum` | 验证是否仅包含字母、数字
306307
`alphaDash/isAlphaDash` | 验证是否仅包含字母、数字、破折号( - )以及下划线( _ )
307308
`multiByte/isMultiByte` | Check value is MultiByte string.
308-
`base64/isBase64` | Check value is Base64 string.
309-
`dnsName/DNSName/isDNSName` | Check value is DNSName string.
309+
`base64/isBase64` | 检查值是Base64字符串
310+
`dnsName/DNSName/isDNSName` | 检查值是DNS名称字符串
310311
`dataURI/isDataURI` | Check value is DataURI string.
311312
`empty/isEmpty` | Check value is Empty string.
312-
`hexColor/isHexColor` | Check value is HexColor string.
313-
`hexadecimal/isHexadecimal` | Check value is Hexadecimal string.
314-
`json/JSON/isJSON` | Check value is JSON string.
315-
`lat/latitude/isLatitude` | Check value is Latitude string.
316-
`lon/longitude/isLongitude` | Check value is Longitude string.
317-
`mac/isMAC` | Check value is MAC string.
318-
`num/number/isNumber` | Check value is number string. `>= 0`
313+
`hexColor/isHexColor` | 检查值是16进制的颜色字符串
314+
`hexadecimal/isHexadecimal` | 检查值是十六进制字符串
315+
`json/JSON/isJSON` | 检查值是JSON字符串。
316+
`lat/latitude/isLatitude` | 检查值是纬度坐标
317+
`lon/longitude/isLongitude` | 检查值是经度坐标
318+
`mac/isMAC` | 检查值是MAC字符串
319+
`num/number/isNumber` | 检查值是数字字符串. `>= 0`
319320
`printableASCII/isPrintableASCII` | Check value is PrintableASCII string.
320-
`rgbColor/RGBColor/isRGBColor` | Check value is RGBColor string.
321-
`url/isURL` | Check value is URL string.
322-
`ip/isIP` | Check value is IP(v4 or v6) string.
323-
`ipv4/isIPv4` | Check value is IPv4 string.
324-
`ipv6/isIPv6` | Check value is IPv6 string.
321+
`rgbColor/RGBColor/isRGBColor` | 检查值是RGB颜色字符串
322+
`url/isURL` | 检查值是URL字符串
323+
`ip/isIP` | 检查值是IP(v4或v6)字符串
324+
`ipv4/isIPv4` | 检查值是IPv4字符串
325+
`ipv6/isIPv6` | 检查值是IPv6字符串
325326
`CIDR/isCIDR` | Check value is CIDR string.
326327
`CIDRv4/isCIDRv4` | Check value is CIDRv4 string.
327328
`CIDRv6/isCIDRv6` | Check value is CIDRv6 string.

data_source.go

+6
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,16 @@ func (d *FormData) Set(field string, val interface{}) error {
414414

415415
// Get value by key
416416
func (d FormData) Get(key string) (interface{}, bool) {
417+
// get form value
417418
if vs, ok := d.Form[key]; ok && len(vs) > 0 {
418419
return vs[0], true
419420
}
420421

422+
// get uploaded file
423+
if fh, ok := d.Files[key]; ok {
424+
return fh, true
425+
}
426+
421427
return nil, false
422428
}
423429

generic_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ func TestValueLen(t *testing.T) {
2525
for _, sample := range tests {
2626
is.Equal(3, ValueLen(reflect.ValueOf(sample)))
2727
}
28+
29+
is.Equal(-1, ValueLen(reflect.ValueOf(nil)))
2830
}
2931

3032
func TestCallByValue(t *testing.T) {
@@ -296,12 +298,13 @@ func TestRule(t *testing.T) {
296298
v.AddRule("key0", "inRule").SetCheckFunc(func(s string) bool {
297299
return s == "val0"
298300
})
301+
v.AddRule("name", "gtField", "key0")
299302

300303
// validate. will skip validate field "name"
301304
v.Validate()
302305
is.True(v.IsOK())
303306
is.Equal("val0", v.SafeVal("key0"))
304-
is.Equal(nil, v.SafeVal("name"))
307+
is.Equal(nil, v.SafeVal("not-exist"))
305308

306309
// validate on "test". will validate field "name"
307310
v.ResetResult()

helper.go

+9-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"github.com/gookit/filter"
77
"reflect"
8-
"runtime"
98
"strconv"
109
"strings"
1110
"unicode"
@@ -135,7 +134,7 @@ func CalcLength(val interface{}) int {
135134
}
136135

137136
// value compare. use for compare int, string.
138-
func valueCompare(srcVal, dstVal interface{}, op string) bool {
137+
func valueCompare(srcVal, dstVal interface{}, op string) (ok bool) {
139138
var err error
140139
var srcInt, dstInt int64
141140

@@ -162,21 +161,21 @@ func valueCompare(srcVal, dstVal interface{}, op string) bool {
162161

163162
switch op {
164163
case "lt":
165-
return srcInt < dstInt
164+
ok = srcInt < dstInt
166165
case "lte":
167-
return srcInt <= dstInt
166+
ok = srcInt <= dstInt
168167
case "gt":
169-
return srcInt > dstInt
168+
ok = srcInt > dstInt
170169
case "gte":
171-
return srcInt >= dstInt
170+
ok = srcInt >= dstInt
172171
}
173172

174-
return false
173+
return
175174
}
176175

177-
func nameOfFunc(fv reflect.Value) string {
178-
return runtime.FuncForPC(fv.Pointer()).Name()
179-
}
176+
// func nameOfFunc(fv reflect.Value) string {
177+
// return runtime.FuncForPC(fv.Pointer()).Name()
178+
// }
180179

181180
func parseArgString(argStr string) (ss []string) {
182181
if argStr == "" { // no arg

validate.go

+51-45
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ type Rule struct {
3737
fields []string
3838
// is optional, only validate on value is not empty. sometimes
3939
optional bool
40+
// skip validate not exist field/empty value
41+
skipEmpty bool
4042
// default value setting
4143
defValue interface{}
4244
// error message
@@ -76,6 +78,16 @@ func (r *Rule) SetScene(scene string) *Rule {
7678
return r
7779
}
7880

81+
// SetOptional only validate on value is not empty.
82+
func (r *Rule) SetOptional(optional bool) {
83+
r.optional = optional
84+
}
85+
86+
// SetSkipEmpty skip validate not exist field/empty value
87+
func (r *Rule) SetSkipEmpty(skipEmpty bool) {
88+
r.skipEmpty = skipEmpty
89+
}
90+
7991
// SetCheckFunc set custom validate func.
8092
func (r *Rule) SetCheckFunc(checkFunc interface{}) *Rule {
8193
var name string
@@ -101,11 +113,6 @@ func (r *Rule) SetBeforeFunc(fn func(field string, v *Validation) bool) {
101113
r.beforeFunc = fn
102114
}
103115

104-
// SetOptional only validate on value is not empty.
105-
func (r *Rule) SetOptional(optional bool) {
106-
r.optional = optional
107-
}
108-
109116
// SetMessage set error message.
110117
// Usage:
111118
// v.AddRule("name", "required").SetMessage("error message")
@@ -161,7 +168,6 @@ func (r *Rule) Apply(v *Validation) (stop bool) {
161168
continue
162169
}
163170

164-
// field value check:
165171
// get field value.
166172
val, exist := v.Get(field)
167173
if !exist && r.optional { // not exist AND r.optional=true. skip check.
@@ -194,6 +200,45 @@ func (r *Rule) Apply(v *Validation) (stop bool) {
194200
return false
195201
}
196202

203+
func (r *Rule) fileValidate(field, name string, v *Validation) (ok bool) {
204+
// beforeFunc return false, skip validate
205+
if r.beforeFunc != nil && !r.beforeFunc(field, v) {
206+
return false
207+
}
208+
209+
fd, ok := v.data.(*FormData)
210+
if !ok {
211+
return
212+
}
213+
214+
// skip on empty AND field not exist
215+
if v.SkipOnEmpty && !fd.HasFile(field) {
216+
return true
217+
}
218+
219+
var ss []string
220+
for _, item := range r.arguments {
221+
ss = append(ss, item.(string))
222+
}
223+
224+
switch name {
225+
case "isFile":
226+
ok = v.IsFile(fd, field)
227+
case "isImage":
228+
ok = v.IsImage(fd, field, ss...)
229+
case "inMimeTypes":
230+
if ln := len(ss); ln == 0 {
231+
return false
232+
} else if ln == 1 {
233+
ok = v.InMimeTypes(fd, field, ss[0])
234+
} else {
235+
ok = v.InMimeTypes(fd, field, ss[0], ss[1:]...)
236+
}
237+
}
238+
239+
return
240+
}
241+
197242
// validate the field value
198243
func (r *Rule) valueValidate(field, name string, val interface{}, v *Validation) (ok bool) {
199244
// "-" OR "safe" mark field value always is safe.
@@ -251,45 +296,6 @@ func (r *Rule) valueValidate(field, name string, val interface{}, v *Validation)
251296
return
252297
}
253298

254-
func (r *Rule) fileValidate(field, name string, v *Validation) (ok bool) {
255-
// beforeFunc return false, skip validate
256-
if r.beforeFunc != nil && !r.beforeFunc(field, v) {
257-
return false
258-
}
259-
260-
fd, ok := v.data.(*FormData)
261-
if !ok {
262-
return
263-
}
264-
265-
// skip on empty AND field not exist
266-
if v.SkipOnEmpty && !fd.HasFile(field) {
267-
return true
268-
}
269-
270-
var ss []string
271-
for _, item := range r.arguments {
272-
ss = append(ss, item.(string))
273-
}
274-
275-
switch name {
276-
case "isFile":
277-
ok = v.IsFile(fd, field)
278-
case "isImage":
279-
ok = v.IsImage(fd, field, ss...)
280-
case "inMimeTypes":
281-
if ln := len(ss); ln == 0 {
282-
return false
283-
} else if ln == 1 {
284-
ok = v.InMimeTypes(fd, field, ss[0])
285-
} else {
286-
ok = v.InMimeTypes(fd, field, ss[0], ss[1:]...)
287-
}
288-
}
289-
290-
return
291-
}
292-
293299
func (r *Rule) errorMessage(field, validator string, v *Validation) (msg string) {
294300
if r.messages != nil {
295301
var ok bool

validation_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var mpSample = M{
2929
"oldSt": 1,
3030
"newSt": 2,
3131
"email": "[email protected]",
32+
"items": []string{"a"},
3233
}
3334

3435
func TestMap(t *testing.T) {
@@ -114,6 +115,10 @@ func TestErrorMessages(t *testing.T) {
114115
is.False(v.Validate())
115116
is.Equal("oldSt's err msg", v.Errors.Get("oldSt"))
116117
is.Equal("newSt's err msg", v.Errors.Get("newSt"))
118+
119+
is.False(v.GtField([]int{2}, "age"))
120+
is.False(v.GtField(2, "items"))
121+
is.False(v.GtField("a", "items"))
117122
}
118123

119124
// UserForm struct
@@ -256,6 +261,9 @@ func TestFromQuery(t *testing.T) {
256261
"age": "required|int|min:10",
257262
})
258263

264+
val, ok := v.Raw("name")
265+
is.True(ok)
266+
is.Equal("inhere", val)
259267
is.False(v.Validate())
260268
is.Equal("name min length is 7", v.Errors.Field("name")[0])
261269
is.Empty(v.SafeData())

0 commit comments

Comments
 (0)