Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
df354acf
Commit
df354acf
authored
Jul 28, 2013
by
astaxie
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #113 from miraclesu/valid
Support Match validate function for tag
parents
ae7e3171
6662eef2
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
96 additions
and
45 deletions
+96
-45
README.md
validation/README.md
+3
-3
util.go
validation/util.go
+39
-8
util_test.go
validation/util_test.go
+10
-1
validation.go
validation/validation.go
+29
-26
validation_test.go
validation/validation_test.go
+14
-5
validators.go
validation/validators.go
+1
-2
No files found.
validation/README.md
View file @
df354acf
...
...
@@ -55,9 +55,10 @@ Struct Tag Use:
// validation function follow with "valid" tag
// functions divide with ";"
// parameters in parentheses "()" and divide with ","
// Match function's pattern string must in "//"
type user struct {
Id int
Name string `valid:"Required"`
Name string `valid:"Required
;Match(/^(test)?\\w*@;com$/)
"`
Age int `valid:"Required;Range(1, 140)"`
}
...
...
@@ -86,8 +87,7 @@ Struct Tag Functions:
Alpha
Numeric
AlphaNumeric
Match(regexp string) // does not support yet
NoMatch(regexp string) // does not support yet
Match(pattern string)
AlphaDash
Email
IP
...
...
validation/util.go
View file @
df354acf
...
...
@@ -26,6 +26,7 @@ var (
"apply"
:
true
,
"Check"
:
true
,
"Valid"
:
true
,
"NoMatch"
:
true
,
}
)
...
...
@@ -50,7 +51,7 @@ type Funcs map[string]reflect.Value
func
(
f
Funcs
)
Call
(
name
string
,
params
...
interface
{})
(
result
[]
reflect
.
Value
,
err
error
)
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
err
=
r
.
(
erro
r
)
err
=
fmt
.
Errorf
(
"%v"
,
r
)
}
}()
if
_
,
ok
:=
f
[
name
];
!
ok
{
...
...
@@ -82,10 +83,17 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
if
len
(
tag
)
==
0
{
return
}
if
vfs
,
tag
,
err
=
getRegFuncs
(
tag
,
f
.
Name
);
err
!=
nil
{
fmt
.
Printf
(
"%+v
\n
"
,
err
)
return
}
fs
:=
strings
.
Split
(
tag
,
";"
)
for
_
,
vfunc
:=
range
fs
{
var
vf
ValidFunc
vf
,
err
=
parseFunc
(
vfunc
)
if
len
(
vfunc
)
==
0
{
continue
}
vf
,
err
=
parseFunc
(
vfunc
,
f
.
Name
)
if
err
!=
nil
{
return
}
...
...
@@ -94,10 +102,33 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
return
}
func
parseFunc
(
vfunc
string
)
(
v
ValidFunc
,
err
error
)
{
// Get Match function
// May be get NoMatch function in the future
func
getRegFuncs
(
tag
,
key
string
)
(
vfs
[]
ValidFunc
,
str
string
,
err
error
)
{
tag
=
strings
.
TrimSpace
(
tag
)
index
:=
strings
.
Index
(
tag
,
"Match(/"
)
if
index
==
-
1
{
str
=
tag
return
}
end
:=
strings
.
LastIndex
(
tag
,
"/)"
)
if
end
<
index
{
err
=
fmt
.
Errorf
(
"invalid Match function"
)
return
}
reg
,
err
:=
regexp
.
Compile
(
tag
[
index
+
len
(
"Match(/"
)
:
end
])
if
err
!=
nil
{
return
}
vfs
=
[]
ValidFunc
{
ValidFunc
{
"Match"
,
[]
interface
{}{
reg
,
key
}}}
str
=
strings
.
TrimSpace
(
tag
[
:
index
])
+
strings
.
TrimSpace
(
tag
[
end
+
len
(
"/)"
)
:
])
return
}
func
parseFunc
(
vfunc
,
key
string
)
(
v
ValidFunc
,
err
error
)
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
err
=
r
.
(
erro
r
)
err
=
fmt
.
Errorf
(
"%v"
,
r
)
}
}()
...
...
@@ -114,7 +145,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) {
err
=
fmt
.
Errorf
(
"%s require %d parameters"
,
vfunc
,
num
)
return
}
v
=
ValidFunc
{
vfunc
,
[]
interface
{}{
vfunc
}}
v
=
ValidFunc
{
vfunc
,
[]
interface
{}{
key
}}
return
}
...
...
@@ -136,7 +167,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) {
return
}
tParams
,
err
:=
trim
(
name
,
params
)
tParams
,
err
:=
trim
(
name
,
key
,
params
)
if
err
!=
nil
{
return
}
...
...
@@ -155,7 +186,7 @@ func numIn(name string) (num int, err error) {
return
}
func
trim
(
name
string
,
s
[]
string
)
(
ts
[]
interface
{},
err
error
)
{
func
trim
(
name
,
key
string
,
s
[]
string
)
(
ts
[]
interface
{},
err
error
)
{
ts
=
make
([]
interface
{},
len
(
s
),
len
(
s
)
+
1
)
fn
,
ok
:=
funcs
[
name
]
if
!
ok
{
...
...
@@ -170,7 +201,7 @@ func trim(name string, s []string) (ts []interface{}, err error) {
}
ts
[
i
]
=
param
}
ts
=
append
(
ts
,
name
)
ts
=
append
(
ts
,
key
)
return
}
...
...
validation/util_test.go
View file @
df354acf
...
...
@@ -8,8 +8,9 @@ import (
type
user
struct
{
Id
int
Tag
string
`valid:"Maxx(aa)"`
Name
string
`valid:"Required
"`
Name
string
`valid:"Required;
"`
Age
int
`valid:"Required;Range(1, 140)"`
match
string
`valid:"Required; Match(/^(test)?\\w*@(/test/);com$/);Max(2)"`
}
func
TestGetValidFuncs
(
t
*
testing
.
T
)
{
...
...
@@ -55,6 +56,14 @@ func TestGetValidFuncs(t *testing.T) {
if
vfs
[
1
]
.
Name
!=
"Range"
&&
len
(
vfs
[
1
]
.
Params
)
!=
2
{
t
.
Error
(
"Range funcs should be got"
)
}
f
,
_
=
tf
.
FieldByName
(
"match"
)
if
vfs
,
err
=
getValidFuncs
(
f
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
vfs
)
!=
3
{
t
.
Fatal
(
"should get 3 ValidFunc but now is"
,
len
(
vfs
))
}
}
func
TestCall
(
t
*
testing
.
T
)
{
...
...
validation/validation.go
View file @
df354acf
...
...
@@ -84,16 +84,19 @@ func (v *Validation) Required(obj interface{}, key string) *ValidationResult {
return
v
.
apply
(
Required
{
key
},
obj
)
}
func
(
v
*
Validation
)
Min
(
n
int
,
min
int
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Min
{
min
,
key
},
n
)
// Test that the obj is greater than min if obj's type is int
func
(
v
*
Validation
)
Min
(
obj
interface
{},
min
int
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Min
{
min
,
key
},
obj
)
}
func
(
v
*
Validation
)
Max
(
n
int
,
max
int
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Max
{
max
,
key
},
n
)
// Test that the obj is less than max if obj's type is int
func
(
v
*
Validation
)
Max
(
obj
interface
{},
max
int
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Max
{
max
,
key
},
obj
)
}
func
(
v
*
Validation
)
Range
(
n
,
min
,
max
int
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Range
{
Min
{
Min
:
min
},
Max
{
Max
:
max
},
key
},
n
)
// Test that the obj is between mni and max if obj's type is int
func
(
v
*
Validation
)
Range
(
obj
interface
{},
min
,
max
int
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Range
{
Min
{
Min
:
min
},
Max
{
Max
:
max
},
key
},
obj
)
}
func
(
v
*
Validation
)
MinSize
(
obj
interface
{},
min
int
,
key
string
)
*
ValidationResult
{
...
...
@@ -120,45 +123,45 @@ func (v *Validation) AlphaNumeric(obj interface{}, key string) *ValidationResult
return
v
.
apply
(
AlphaNumeric
{
key
},
obj
)
}
func
(
v
*
Validation
)
Match
(
str
string
,
regex
*
regexp
.
Regexp
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Match
{
regex
,
key
},
str
)
func
(
v
*
Validation
)
Match
(
obj
interface
{}
,
regex
*
regexp
.
Regexp
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Match
{
regex
,
key
},
obj
)
}
func
(
v
*
Validation
)
NoMatch
(
str
string
,
regex
*
regexp
.
Regexp
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
NoMatch
{
Match
{
Regexp
:
regex
},
key
},
str
)
func
(
v
*
Validation
)
NoMatch
(
obj
interface
{}
,
regex
*
regexp
.
Regexp
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
NoMatch
{
Match
{
Regexp
:
regex
},
key
},
obj
)
}
func
(
v
*
Validation
)
AlphaDash
(
str
string
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
AlphaDash
{
NoMatch
{
Match
:
Match
{
Regexp
:
alphaDashPattern
}},
key
},
str
)
func
(
v
*
Validation
)
AlphaDash
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
AlphaDash
{
NoMatch
{
Match
:
Match
{
Regexp
:
alphaDashPattern
}},
key
},
obj
)
}
func
(
v
*
Validation
)
Email
(
str
string
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Email
{
Match
{
Regexp
:
emailPattern
},
key
},
str
)
func
(
v
*
Validation
)
Email
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Email
{
Match
{
Regexp
:
emailPattern
},
key
},
obj
)
}
func
(
v
*
Validation
)
IP
(
str
string
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
IP
{
Match
{
Regexp
:
ipPattern
},
key
},
str
)
func
(
v
*
Validation
)
IP
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
IP
{
Match
{
Regexp
:
ipPattern
},
key
},
obj
)
}
func
(
v
*
Validation
)
Base64
(
str
string
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Base64
{
Match
{
Regexp
:
base64Pattern
},
key
},
str
)
func
(
v
*
Validation
)
Base64
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Base64
{
Match
{
Regexp
:
base64Pattern
},
key
},
obj
)
}
func
(
v
*
Validation
)
Mobile
(
str
string
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Mobile
{
Match
{
Regexp
:
mobilePattern
},
key
},
str
)
func
(
v
*
Validation
)
Mobile
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Mobile
{
Match
{
Regexp
:
mobilePattern
},
key
},
obj
)
}
func
(
v
*
Validation
)
Tel
(
str
string
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Tel
{
Match
{
Regexp
:
telPattern
},
key
},
str
)
func
(
v
*
Validation
)
Tel
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Tel
{
Match
{
Regexp
:
telPattern
},
key
},
obj
)
}
func
(
v
*
Validation
)
Phone
(
str
string
,
key
string
)
*
ValidationResult
{
func
(
v
*
Validation
)
Phone
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
Phone
{
Mobile
{
Match
:
Match
{
Regexp
:
mobilePattern
}},
Tel
{
Match
:
Match
{
Regexp
:
telPattern
}},
key
},
str
)
Tel
{
Match
:
Match
{
Regexp
:
telPattern
}},
key
},
obj
)
}
func
(
v
*
Validation
)
ZipCode
(
str
string
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
ZipCode
{
Match
{
Regexp
:
zipCodePattern
},
key
},
str
)
func
(
v
*
Validation
)
ZipCode
(
obj
interface
{}
,
key
string
)
*
ValidationResult
{
return
v
.
apply
(
ZipCode
{
Match
{
Regexp
:
zipCodePattern
},
key
},
obj
)
}
func
(
v
*
Validation
)
apply
(
chk
Validator
,
obj
interface
{})
*
ValidationResult
{
...
...
validation/validation_test.go
View file @
df354acf
...
...
@@ -61,10 +61,10 @@ func TestRange(t *testing.T) {
valid
:=
Validation
{}
if
valid
.
Range
(
-
1
,
0
,
1
,
"range0_1"
)
.
Ok
{
t
.
Error
(
"-1 is bet
t
ween 0 and 1 should be false"
)
t
.
Error
(
"-1 is between 0 and 1 should be false"
)
}
if
!
valid
.
Range
(
1
,
0
,
1
,
"range0_1"
)
.
Ok
{
t
.
Error
(
"1 is bet
t
ween 0 and 1 should be true"
)
t
.
Error
(
"1 is between 0 and 1 should be true"
)
}
}
...
...
@@ -283,12 +283,12 @@ func TestZipCode(t *testing.T) {
func
TestValid
(
t
*
testing
.
T
)
{
type
user
struct
{
Id
int
Name
string
`valid:"Required"`
Name
string
`valid:"Required
;Match(/^(test)?\\w*@(/test/);com$/)
"`
Age
int
`valid:"Required;Range(1, 140)"`
}
valid
:=
Validation
{}
u
:=
user
{
Name
:
"test"
,
Age
:
40
}
u
:=
user
{
Name
:
"test
@/test/;com
"
,
Age
:
40
}
b
,
err
:=
valid
.
Valid
(
u
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -297,7 +297,7 @@ func TestValid(t *testing.T) {
t
.
Error
(
"validation should be passed"
)
}
uptr
:=
&
user
{
Name
:
"test"
,
Age
:
18
0
}
uptr
:=
&
user
{
Name
:
"test"
,
Age
:
4
0
}
b
,
err
=
valid
.
Valid
(
uptr
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -305,4 +305,13 @@ func TestValid(t *testing.T) {
if
b
{
t
.
Error
(
"validation should not be passed"
)
}
u
=
user
{
Name
:
"test@/test/;com"
,
Age
:
180
}
b
,
err
=
valid
.
Valid
(
u
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
b
{
t
.
Error
(
"validation should not be passed"
)
}
}
validation/validators.go
View file @
df354acf
...
...
@@ -264,8 +264,7 @@ type Match struct {
}
func
(
m
Match
)
IsSatisfied
(
obj
interface
{})
bool
{
str
:=
obj
.
(
string
)
return
m
.
Regexp
.
MatchString
(
str
)
return
m
.
Regexp
.
MatchString
(
fmt
.
Sprintf
(
"%v"
,
obj
))
}
func
(
m
Match
)
DefaultMessage
()
string
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment