mirror of
https://github.com/astaxie/beego.git
synced 2024-11-29 19:01:29 +00:00
Merge pull request #113 from miraclesu/valid
Support Match validate function for tag
This commit is contained in:
commit
df354acf97
@ -55,9 +55,10 @@ Struct Tag Use:
|
|||||||
// validation function follow with "valid" tag
|
// validation function follow with "valid" tag
|
||||||
// functions divide with ";"
|
// functions divide with ";"
|
||||||
// parameters in parentheses "()" and divide with ","
|
// parameters in parentheses "()" and divide with ","
|
||||||
|
// Match function's pattern string must in "//"
|
||||||
type user struct {
|
type user struct {
|
||||||
Id int
|
Id int
|
||||||
Name string `valid:"Required"`
|
Name string `valid:"Required;Match(/^(test)?\\w*@;com$/)"`
|
||||||
Age int `valid:"Required;Range(1, 140)"`
|
Age int `valid:"Required;Range(1, 140)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +87,7 @@ Struct Tag Functions:
|
|||||||
Alpha
|
Alpha
|
||||||
Numeric
|
Numeric
|
||||||
AlphaNumeric
|
AlphaNumeric
|
||||||
Match(regexp string) // does not support yet
|
Match(pattern string)
|
||||||
NoMatch(regexp string) // does not support yet
|
|
||||||
AlphaDash
|
AlphaDash
|
||||||
Email
|
Email
|
||||||
IP
|
IP
|
||||||
|
@ -26,6 +26,7 @@ var (
|
|||||||
"apply": true,
|
"apply": true,
|
||||||
"Check": true,
|
"Check": true,
|
||||||
"Valid": 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) {
|
func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
err = r.(error)
|
err = fmt.Errorf("%v", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if _, ok := f[name]; !ok {
|
if _, ok := f[name]; !ok {
|
||||||
@ -82,10 +83,17 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
|
|||||||
if len(tag) == 0 {
|
if len(tag) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil {
|
||||||
|
fmt.Printf("%+v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
fs := strings.Split(tag, ";")
|
fs := strings.Split(tag, ";")
|
||||||
for _, vfunc := range fs {
|
for _, vfunc := range fs {
|
||||||
var vf ValidFunc
|
var vf ValidFunc
|
||||||
vf, err = parseFunc(vfunc)
|
if len(vfunc) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vf, err = parseFunc(vfunc, f.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -94,10 +102,33 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
|
|||||||
return
|
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() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
err = r.(error)
|
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)
|
err = fmt.Errorf("%s require %d parameters", vfunc, num)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v = ValidFunc{vfunc, []interface{}{vfunc}}
|
v = ValidFunc{vfunc, []interface{}{key}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +167,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tParams, err := trim(name, params)
|
tParams, err := trim(name, key, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -155,7 +186,7 @@ func numIn(name string) (num int, err error) {
|
|||||||
return
|
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)
|
ts = make([]interface{}, len(s), len(s)+1)
|
||||||
fn, ok := funcs[name]
|
fn, ok := funcs[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -170,7 +201,7 @@ func trim(name string, s []string) (ts []interface{}, err error) {
|
|||||||
}
|
}
|
||||||
ts[i] = param
|
ts[i] = param
|
||||||
}
|
}
|
||||||
ts = append(ts, name)
|
ts = append(ts, key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,8 +8,9 @@ import (
|
|||||||
type user struct {
|
type user struct {
|
||||||
Id int
|
Id int
|
||||||
Tag string `valid:"Maxx(aa)"`
|
Tag string `valid:"Maxx(aa)"`
|
||||||
Name string `valid:"Required"`
|
Name string `valid:"Required;"`
|
||||||
Age int `valid:"Required;Range(1, 140)"`
|
Age int `valid:"Required;Range(1, 140)"`
|
||||||
|
match string `valid:"Required; Match(/^(test)?\\w*@(/test/);com$/);Max(2)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetValidFuncs(t *testing.T) {
|
func TestGetValidFuncs(t *testing.T) {
|
||||||
@ -55,6 +56,14 @@ func TestGetValidFuncs(t *testing.T) {
|
|||||||
if vfs[1].Name != "Range" && len(vfs[1].Params) != 2 {
|
if vfs[1].Name != "Range" && len(vfs[1].Params) != 2 {
|
||||||
t.Error("Range funcs should be got")
|
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) {
|
func TestCall(t *testing.T) {
|
||||||
|
@ -84,16 +84,19 @@ func (v *Validation) Required(obj interface{}, key string) *ValidationResult {
|
|||||||
return v.apply(Required{key}, obj)
|
return v.apply(Required{key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) Min(n int, min int, key string) *ValidationResult {
|
// Test that the obj is greater than min if obj's type is int
|
||||||
return v.apply(Min{min, key}, n)
|
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 {
|
// Test that the obj is less than max if obj's type is int
|
||||||
return v.apply(Max{max, key}, n)
|
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 {
|
// Test that the obj is between mni and max if obj's type is int
|
||||||
return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, n)
|
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 {
|
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)
|
return v.apply(AlphaNumeric{key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) Match(str string, regex *regexp.Regexp, key string) *ValidationResult {
|
func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *ValidationResult {
|
||||||
return v.apply(Match{regex, key}, str)
|
return v.apply(Match{regex, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) NoMatch(str string, regex *regexp.Regexp, key string) *ValidationResult {
|
func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *ValidationResult {
|
||||||
return v.apply(NoMatch{Match{Regexp: regex}, key}, str)
|
return v.apply(NoMatch{Match{Regexp: regex}, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) AlphaDash(str string, key string) *ValidationResult {
|
func (v *Validation) AlphaDash(obj interface{}, key string) *ValidationResult {
|
||||||
return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, str)
|
return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) Email(str string, key string) *ValidationResult {
|
func (v *Validation) Email(obj interface{}, key string) *ValidationResult {
|
||||||
return v.apply(Email{Match{Regexp: emailPattern}, key}, str)
|
return v.apply(Email{Match{Regexp: emailPattern}, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) IP(str string, key string) *ValidationResult {
|
func (v *Validation) IP(obj interface{}, key string) *ValidationResult {
|
||||||
return v.apply(IP{Match{Regexp: ipPattern}, key}, str)
|
return v.apply(IP{Match{Regexp: ipPattern}, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) Base64(str string, key string) *ValidationResult {
|
func (v *Validation) Base64(obj interface{}, key string) *ValidationResult {
|
||||||
return v.apply(Base64{Match{Regexp: base64Pattern}, key}, str)
|
return v.apply(Base64{Match{Regexp: base64Pattern}, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) Mobile(str string, key string) *ValidationResult {
|
func (v *Validation) Mobile(obj interface{}, key string) *ValidationResult {
|
||||||
return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, str)
|
return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) Tel(str string, key string) *ValidationResult {
|
func (v *Validation) Tel(obj interface{}, key string) *ValidationResult {
|
||||||
return v.apply(Tel{Match{Regexp: telPattern}, key}, str)
|
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}},
|
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 {
|
func (v *Validation) ZipCode(obj interface{}, key string) *ValidationResult {
|
||||||
return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, str)
|
return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult {
|
func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult {
|
||||||
|
@ -61,10 +61,10 @@ func TestRange(t *testing.T) {
|
|||||||
valid := Validation{}
|
valid := Validation{}
|
||||||
|
|
||||||
if valid.Range(-1, 0, 1, "range0_1").Ok {
|
if valid.Range(-1, 0, 1, "range0_1").Ok {
|
||||||
t.Error("-1 is bettween 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 {
|
if !valid.Range(1, 0, 1, "range0_1").Ok {
|
||||||
t.Error("1 is bettween 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) {
|
func TestValid(t *testing.T) {
|
||||||
type user struct {
|
type user struct {
|
||||||
Id int
|
Id int
|
||||||
Name string `valid:"Required"`
|
Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"`
|
||||||
Age int `valid:"Required;Range(1, 140)"`
|
Age int `valid:"Required;Range(1, 140)"`
|
||||||
}
|
}
|
||||||
valid := Validation{}
|
valid := Validation{}
|
||||||
|
|
||||||
u := user{Name: "test", Age: 40}
|
u := user{Name: "test@/test/;com", Age: 40}
|
||||||
b, err := valid.Valid(u)
|
b, err := valid.Valid(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -297,7 +297,7 @@ func TestValid(t *testing.T) {
|
|||||||
t.Error("validation should be passed")
|
t.Error("validation should be passed")
|
||||||
}
|
}
|
||||||
|
|
||||||
uptr := &user{Name: "test", Age: 180}
|
uptr := &user{Name: "test", Age: 40}
|
||||||
b, err = valid.Valid(uptr)
|
b, err = valid.Valid(uptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -305,4 +305,13 @@ func TestValid(t *testing.T) {
|
|||||||
if b {
|
if b {
|
||||||
t.Error("validation should not be passed")
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,8 +264,7 @@ type Match struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m Match) IsSatisfied(obj interface{}) bool {
|
func (m Match) IsSatisfied(obj interface{}) bool {
|
||||||
str := obj.(string)
|
return m.Regexp.MatchString(fmt.Sprintf("%v", obj))
|
||||||
return m.Regexp.MatchString(str)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Match) DefaultMessage() string {
|
func (m Match) DefaultMessage() string {
|
||||||
|
Loading…
Reference in New Issue
Block a user