Support Match validate function for tag
Showing
4 changed files
with
67 additions
and
18 deletions
| ... | @@ -55,9 +55,10 @@ Struct Tag Use: | ... | @@ -55,9 +55,10 @@ Struct Tag Use: |
| 55 | // validation function follow with "valid" tag | 55 | // validation function follow with "valid" tag |
| 56 | // functions divide with ";" | 56 | // functions divide with ";" |
| 57 | // parameters in parentheses "()" and divide with "," | 57 | // parameters in parentheses "()" and divide with "," |
| 58 | // Match function's pattern string must in "//" | ||
| 58 | type user struct { | 59 | type user struct { |
| 59 | Id int | 60 | Id int |
| 60 | Name string `valid:"Required"` | 61 | Name string `valid:"Required;Match(/^(test)?\\w*@;com$/)"` |
| 61 | Age int `valid:"Required;Range(1, 140)"` | 62 | Age int `valid:"Required;Range(1, 140)"` |
| 62 | } | 63 | } |
| 63 | 64 | ||
| ... | @@ -86,8 +87,7 @@ Struct Tag Functions: | ... | @@ -86,8 +87,7 @@ Struct Tag Functions: |
| 86 | Alpha | 87 | Alpha |
| 87 | Numeric | 88 | Numeric |
| 88 | AlphaNumeric | 89 | AlphaNumeric |
| 89 | Match(regexp string) // does not support yet | 90 | Match(pattern string) |
| 90 | NoMatch(regexp string) // does not support yet | ||
| 91 | AlphaDash | 91 | AlphaDash |
| 92 | 92 | ||
| 93 | IP | 93 | IP | ... | ... |
| ... | @@ -26,6 +26,7 @@ var ( | ... | @@ -26,6 +26,7 @@ var ( |
| 26 | "apply": true, | 26 | "apply": true, |
| 27 | "Check": true, | 27 | "Check": true, |
| 28 | "Valid": true, | 28 | "Valid": true, |
| 29 | "NoMatch": true, | ||
| 29 | } | 30 | } |
| 30 | ) | 31 | ) |
| 31 | 32 | ||
| ... | @@ -50,7 +51,7 @@ type Funcs map[string]reflect.Value | ... | @@ -50,7 +51,7 @@ type Funcs map[string]reflect.Value |
| 50 | func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { | 51 | func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { |
| 51 | defer func() { | 52 | defer func() { |
| 52 | if r := recover(); r != nil { | 53 | if r := recover(); r != nil { |
| 53 | err = r.(error) | 54 | err = fmt.Errorf("%v", r) |
| 54 | } | 55 | } |
| 55 | }() | 56 | }() |
| 56 | if _, ok := f[name]; !ok { | 57 | if _, ok := f[name]; !ok { |
| ... | @@ -82,10 +83,17 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { | ... | @@ -82,10 +83,17 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { |
| 82 | if len(tag) == 0 { | 83 | if len(tag) == 0 { |
| 83 | return | 84 | return |
| 84 | } | 85 | } |
| 86 | if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil { | ||
| 87 | fmt.Printf("%+v\n", err) | ||
| 88 | return | ||
| 89 | } | ||
| 85 | fs := strings.Split(tag, ";") | 90 | fs := strings.Split(tag, ";") |
| 86 | for _, vfunc := range fs { | 91 | for _, vfunc := range fs { |
| 87 | var vf ValidFunc | 92 | var vf ValidFunc |
| 88 | vf, err = parseFunc(vfunc) | 93 | if len(vfunc) == 0 { |
| 94 | continue | ||
| 95 | } | ||
| 96 | vf, err = parseFunc(vfunc, f.Name) | ||
| 89 | if err != nil { | 97 | if err != nil { |
| 90 | return | 98 | return |
| 91 | } | 99 | } |
| ... | @@ -94,10 +102,33 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { | ... | @@ -94,10 +102,33 @@ func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { |
| 94 | return | 102 | return |
| 95 | } | 103 | } |
| 96 | 104 | ||
| 97 | func parseFunc(vfunc string) (v ValidFunc, err error) { | 105 | // Get Match function |
| 106 | // May be get NoMatch function in the future | ||
| 107 | func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) { | ||
| 108 | tag = strings.TrimSpace(tag) | ||
| 109 | index := strings.Index(tag, "Match(/") | ||
| 110 | if index == -1 { | ||
| 111 | str = tag | ||
| 112 | return | ||
| 113 | } | ||
| 114 | end := strings.LastIndex(tag, "/)") | ||
| 115 | if end < index { | ||
| 116 | err = fmt.Errorf("invalid Match function") | ||
| 117 | return | ||
| 118 | } | ||
| 119 | reg, err := regexp.Compile(tag[index+len("Match(/") : end]) | ||
| 120 | if err != nil { | ||
| 121 | return | ||
| 122 | } | ||
| 123 | vfs = []ValidFunc{ValidFunc{"Match", []interface{}{reg, key}}} | ||
| 124 | str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):]) | ||
| 125 | return | ||
| 126 | } | ||
| 127 | |||
| 128 | func parseFunc(vfunc, key string) (v ValidFunc, err error) { | ||
| 98 | defer func() { | 129 | defer func() { |
| 99 | if r := recover(); r != nil { | 130 | if r := recover(); r != nil { |
| 100 | err = r.(error) | 131 | err = fmt.Errorf("%v", r) |
| 101 | } | 132 | } |
| 102 | }() | 133 | }() |
| 103 | 134 | ||
| ... | @@ -114,7 +145,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { | ... | @@ -114,7 +145,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { |
| 114 | err = fmt.Errorf("%s require %d parameters", vfunc, num) | 145 | err = fmt.Errorf("%s require %d parameters", vfunc, num) |
| 115 | return | 146 | return |
| 116 | } | 147 | } |
| 117 | v = ValidFunc{vfunc, []interface{}{vfunc}} | 148 | v = ValidFunc{vfunc, []interface{}{key}} |
| 118 | return | 149 | return |
| 119 | } | 150 | } |
| 120 | 151 | ||
| ... | @@ -136,7 +167,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { | ... | @@ -136,7 +167,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { |
| 136 | return | 167 | return |
| 137 | } | 168 | } |
| 138 | 169 | ||
| 139 | tParams, err := trim(name, params) | 170 | tParams, err := trim(name, key, params) |
| 140 | if err != nil { | 171 | if err != nil { |
| 141 | return | 172 | return |
| 142 | } | 173 | } |
| ... | @@ -155,7 +186,7 @@ func numIn(name string) (num int, err error) { | ... | @@ -155,7 +186,7 @@ func numIn(name string) (num int, err error) { |
| 155 | return | 186 | return |
| 156 | } | 187 | } |
| 157 | 188 | ||
| 158 | func trim(name string, s []string) (ts []interface{}, err error) { | 189 | func trim(name, key string, s []string) (ts []interface{}, err error) { |
| 159 | ts = make([]interface{}, len(s), len(s)+1) | 190 | ts = make([]interface{}, len(s), len(s)+1) |
| 160 | fn, ok := funcs[name] | 191 | fn, ok := funcs[name] |
| 161 | if !ok { | 192 | if !ok { |
| ... | @@ -170,7 +201,7 @@ func trim(name string, s []string) (ts []interface{}, err error) { | ... | @@ -170,7 +201,7 @@ func trim(name string, s []string) (ts []interface{}, err error) { |
| 170 | } | 201 | } |
| 171 | ts[i] = param | 202 | ts[i] = param |
| 172 | } | 203 | } |
| 173 | ts = append(ts, name) | 204 | ts = append(ts, key) |
| 174 | return | 205 | return |
| 175 | } | 206 | } |
| 176 | 207 | ... | ... |
| ... | @@ -6,10 +6,11 @@ import ( | ... | @@ -6,10 +6,11 @@ import ( |
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | type user struct { | 8 | type user struct { |
| 9 | Id int | 9 | Id int |
| 10 | Tag string `valid:"Maxx(aa)"` | 10 | Tag string `valid:"Maxx(aa)"` |
| 11 | Name string `valid:"Required"` | 11 | Name string `valid:"Required;"` |
| 12 | Age int `valid:"Required;Range(1, 140)"` | 12 | Age int `valid:"Required;Range(1, 140)"` |
| 13 | match string `valid:"Required; Match(/^(test)?\\w*@(/test/);com$/);Max(2)"` | ||
| 13 | } | 14 | } |
| 14 | 15 | ||
| 15 | func TestGetValidFuncs(t *testing.T) { | 16 | func TestGetValidFuncs(t *testing.T) { |
| ... | @@ -55,6 +56,14 @@ func TestGetValidFuncs(t *testing.T) { | ... | @@ -55,6 +56,14 @@ func TestGetValidFuncs(t *testing.T) { |
| 55 | if vfs[1].Name != "Range" && len(vfs[1].Params) != 2 { | 56 | if vfs[1].Name != "Range" && len(vfs[1].Params) != 2 { |
| 56 | t.Error("Range funcs should be got") | 57 | t.Error("Range funcs should be got") |
| 57 | } | 58 | } |
| 59 | |||
| 60 | f, _ = tf.FieldByName("match") | ||
| 61 | if vfs, err = getValidFuncs(f); err != nil { | ||
| 62 | t.Fatal(err) | ||
| 63 | } | ||
| 64 | if len(vfs) != 3 { | ||
| 65 | t.Fatal("should get 3 ValidFunc but now is", len(vfs)) | ||
| 66 | } | ||
| 58 | } | 67 | } |
| 59 | 68 | ||
| 60 | func TestCall(t *testing.T) { | 69 | func TestCall(t *testing.T) { | ... | ... |
| ... | @@ -283,12 +283,12 @@ func TestZipCode(t *testing.T) { | ... | @@ -283,12 +283,12 @@ func TestZipCode(t *testing.T) { |
| 283 | func TestValid(t *testing.T) { | 283 | func TestValid(t *testing.T) { |
| 284 | type user struct { | 284 | type user struct { |
| 285 | Id int | 285 | Id int |
| 286 | Name string `valid:"Required"` | 286 | Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` |
| 287 | Age int `valid:"Required;Range(1, 140)"` | 287 | Age int `valid:"Required;Range(1, 140)"` |
| 288 | } | 288 | } |
| 289 | valid := Validation{} | 289 | valid := Validation{} |
| 290 | 290 | ||
| 291 | u := user{Name: "test", Age: 40} | 291 | u := user{Name: "test@/test/;com", Age: 40} |
| 292 | b, err := valid.Valid(u) | 292 | b, err := valid.Valid(u) |
| 293 | if err != nil { | 293 | if err != nil { |
| 294 | t.Fatal(err) | 294 | t.Fatal(err) |
| ... | @@ -297,7 +297,7 @@ func TestValid(t *testing.T) { | ... | @@ -297,7 +297,7 @@ func TestValid(t *testing.T) { |
| 297 | t.Error("validation should be passed") | 297 | t.Error("validation should be passed") |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | uptr := &user{Name: "test", Age: 180} | 300 | uptr := &user{Name: "test", Age: 40} |
| 301 | b, err = valid.Valid(uptr) | 301 | b, err = valid.Valid(uptr) |
| 302 | if err != nil { | 302 | if err != nil { |
| 303 | t.Fatal(err) | 303 | t.Fatal(err) |
| ... | @@ -305,4 +305,13 @@ func TestValid(t *testing.T) { | ... | @@ -305,4 +305,13 @@ func TestValid(t *testing.T) { |
| 305 | if b { | 305 | if b { |
| 306 | t.Error("validation should not be passed") | 306 | t.Error("validation should not be passed") |
| 307 | } | 307 | } |
| 308 | |||
| 309 | u = user{Name: "test@/test/;com", Age: 180} | ||
| 310 | b, err = valid.Valid(u) | ||
| 311 | if err != nil { | ||
| 312 | t.Fatal(err) | ||
| 313 | } | ||
| 314 | if b { | ||
| 315 | t.Error("validation should not be passed") | ||
| 316 | } | ||
| 308 | } | 317 | } | ... | ... |
-
Please register or sign in to post a comment