df354acf by astaxie

Merge pull request #113 from miraclesu/valid

Support Match validate function for tag
2 parents ae7e3171 6662eef2
...@@ -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 Email 92 Email
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
......
...@@ -8,8 +8,9 @@ import ( ...@@ -8,8 +8,9 @@ import (
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) {
......
...@@ -84,16 +84,19 @@ func (v *Validation) Required(obj interface{}, key string) *ValidationResult { ...@@ -84,16 +84,19 @@ func (v *Validation) Required(obj interface{}, key string) *ValidationResult {
84 return v.apply(Required{key}, obj) 84 return v.apply(Required{key}, obj)
85 } 85 }
86 86
87 func (v *Validation) Min(n int, min int, key string) *ValidationResult { 87 // Test that the obj is greater than min if obj's type is int
88 return v.apply(Min{min, key}, n) 88 func (v *Validation) Min(obj interface{}, min int, key string) *ValidationResult {
89 return v.apply(Min{min, key}, obj)
89 } 90 }
90 91
91 func (v *Validation) Max(n int, max int, key string) *ValidationResult { 92 // Test that the obj is less than max if obj's type is int
92 return v.apply(Max{max, key}, n) 93 func (v *Validation) Max(obj interface{}, max int, key string) *ValidationResult {
94 return v.apply(Max{max, key}, obj)
93 } 95 }
94 96
95 func (v *Validation) Range(n, min, max int, key string) *ValidationResult { 97 // Test that the obj is between mni and max if obj's type is int
96 return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, n) 98 func (v *Validation) Range(obj interface{}, min, max int, key string) *ValidationResult {
99 return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, obj)
97 } 100 }
98 101
99 func (v *Validation) MinSize(obj interface{}, min int, key string) *ValidationResult { 102 func (v *Validation) MinSize(obj interface{}, min int, key string) *ValidationResult {
...@@ -120,45 +123,45 @@ func (v *Validation) AlphaNumeric(obj interface{}, key string) *ValidationResult ...@@ -120,45 +123,45 @@ func (v *Validation) AlphaNumeric(obj interface{}, key string) *ValidationResult
120 return v.apply(AlphaNumeric{key}, obj) 123 return v.apply(AlphaNumeric{key}, obj)
121 } 124 }
122 125
123 func (v *Validation) Match(str string, regex *regexp.Regexp, key string) *ValidationResult { 126 func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *ValidationResult {
124 return v.apply(Match{regex, key}, str) 127 return v.apply(Match{regex, key}, obj)
125 } 128 }
126 129
127 func (v *Validation) NoMatch(str string, regex *regexp.Regexp, key string) *ValidationResult { 130 func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *ValidationResult {
128 return v.apply(NoMatch{Match{Regexp: regex}, key}, str) 131 return v.apply(NoMatch{Match{Regexp: regex}, key}, obj)
129 } 132 }
130 133
131 func (v *Validation) AlphaDash(str string, key string) *ValidationResult { 134 func (v *Validation) AlphaDash(obj interface{}, key string) *ValidationResult {
132 return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, str) 135 return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, obj)
133 } 136 }
134 137
135 func (v *Validation) Email(str string, key string) *ValidationResult { 138 func (v *Validation) Email(obj interface{}, key string) *ValidationResult {
136 return v.apply(Email{Match{Regexp: emailPattern}, key}, str) 139 return v.apply(Email{Match{Regexp: emailPattern}, key}, obj)
137 } 140 }
138 141
139 func (v *Validation) IP(str string, key string) *ValidationResult { 142 func (v *Validation) IP(obj interface{}, key string) *ValidationResult {
140 return v.apply(IP{Match{Regexp: ipPattern}, key}, str) 143 return v.apply(IP{Match{Regexp: ipPattern}, key}, obj)
141 } 144 }
142 145
143 func (v *Validation) Base64(str string, key string) *ValidationResult { 146 func (v *Validation) Base64(obj interface{}, key string) *ValidationResult {
144 return v.apply(Base64{Match{Regexp: base64Pattern}, key}, str) 147 return v.apply(Base64{Match{Regexp: base64Pattern}, key}, obj)
145 } 148 }
146 149
147 func (v *Validation) Mobile(str string, key string) *ValidationResult { 150 func (v *Validation) Mobile(obj interface{}, key string) *ValidationResult {
148 return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, str) 151 return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, obj)
149 } 152 }
150 153
151 func (v *Validation) Tel(str string, key string) *ValidationResult { 154 func (v *Validation) Tel(obj interface{}, key string) *ValidationResult {
152 return v.apply(Tel{Match{Regexp: telPattern}, key}, str) 155 return v.apply(Tel{Match{Regexp: telPattern}, key}, obj)
153 } 156 }
154 157
155 func (v *Validation) Phone(str string, key string) *ValidationResult { 158 func (v *Validation) Phone(obj interface{}, key string) *ValidationResult {
156 return v.apply(Phone{Mobile{Match: Match{Regexp: mobilePattern}}, 159 return v.apply(Phone{Mobile{Match: Match{Regexp: mobilePattern}},
157 Tel{Match: Match{Regexp: telPattern}}, key}, str) 160 Tel{Match: Match{Regexp: telPattern}}, key}, obj)
158 } 161 }
159 162
160 func (v *Validation) ZipCode(str string, key string) *ValidationResult { 163 func (v *Validation) ZipCode(obj interface{}, key string) *ValidationResult {
161 return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, str) 164 return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, obj)
162 } 165 }
163 166
164 func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult { 167 func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult {
......
...@@ -61,10 +61,10 @@ func TestRange(t *testing.T) { ...@@ -61,10 +61,10 @@ func TestRange(t *testing.T) {
61 valid := Validation{} 61 valid := Validation{}
62 62
63 if valid.Range(-1, 0, 1, "range0_1").Ok { 63 if valid.Range(-1, 0, 1, "range0_1").Ok {
64 t.Error("-1 is bettween 0 and 1 should be false") 64 t.Error("-1 is between 0 and 1 should be false")
65 } 65 }
66 if !valid.Range(1, 0, 1, "range0_1").Ok { 66 if !valid.Range(1, 0, 1, "range0_1").Ok {
67 t.Error("1 is bettween 0 and 1 should be true") 67 t.Error("1 is between 0 and 1 should be true")
68 } 68 }
69 } 69 }
70 70
...@@ -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 }
......
...@@ -264,8 +264,7 @@ type Match struct { ...@@ -264,8 +264,7 @@ type Match struct {
264 } 264 }
265 265
266 func (m Match) IsSatisfied(obj interface{}) bool { 266 func (m Match) IsSatisfied(obj interface{}) bool {
267 str := obj.(string) 267 return m.Regexp.MatchString(fmt.Sprintf("%v", obj))
268 return m.Regexp.MatchString(str)
269 } 268 }
270 269
271 func (m Match) DefaultMessage() string { 270 func (m Match) DefaultMessage() string {
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!