92db56c0 by miraclesu

add struct tag support

1 parent 4c6163ba
...@@ -48,6 +48,11 @@ type ValidFunc struct { ...@@ -48,6 +48,11 @@ type ValidFunc struct {
48 type Funcs map[string]reflect.Value 48 type Funcs map[string]reflect.Value
49 49
50 func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { 50 func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) {
51 defer func() {
52 if r := recover(); r != nil {
53 err = r.(error)
54 }
55 }()
51 if _, ok := f[name]; !ok { 56 if _, ok := f[name]; !ok {
52 err = fmt.Errorf("%s does not exist", name) 57 err = fmt.Errorf("%s does not exist", name)
53 return 58 return
...@@ -109,7 +114,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { ...@@ -109,7 +114,7 @@ func parseFunc(vfunc string) (v ValidFunc, err error) {
109 err = fmt.Errorf("%s require %d parameters", vfunc, num) 114 err = fmt.Errorf("%s require %d parameters", vfunc, num)
110 return 115 return
111 } 116 }
112 v = ValidFunc{Name: vfunc} 117 v = ValidFunc{vfunc, []interface{}{vfunc}}
113 return 118 return
114 } 119 }
115 120
...@@ -145,12 +150,13 @@ func numIn(name string) (num int, err error) { ...@@ -145,12 +150,13 @@ func numIn(name string) (num int, err error) {
145 err = fmt.Errorf("doesn't exsits %s valid function", name) 150 err = fmt.Errorf("doesn't exsits %s valid function", name)
146 return 151 return
147 } 152 }
153 // sub *Validation obj and key
148 num = fn.Type().NumIn() - 3 154 num = fn.Type().NumIn() - 3
149 return 155 return
150 } 156 }
151 157
152 func trim(name string, s []string) (ts []interface{}, err error) { 158 func trim(name string, s []string) (ts []interface{}, err error) {
153 ts = make([]interface{}, len(s)) 159 ts = make([]interface{}, len(s), len(s)+1)
154 fn, ok := funcs[name] 160 fn, ok := funcs[name]
155 if !ok { 161 if !ok {
156 err = fmt.Errorf("doesn't exsits %s valid function", name) 162 err = fmt.Errorf("doesn't exsits %s valid function", name)
...@@ -158,14 +164,17 @@ func trim(name string, s []string) (ts []interface{}, err error) { ...@@ -158,14 +164,17 @@ func trim(name string, s []string) (ts []interface{}, err error) {
158 } 164 }
159 for i := 0; i < len(s); i++ { 165 for i := 0; i < len(s); i++ {
160 var param interface{} 166 var param interface{}
167 // skip *Validation and obj params
161 if param, err = magic(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil { 168 if param, err = magic(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil {
162 return 169 return
163 } 170 }
164 ts[i] = param 171 ts[i] = param
165 } 172 }
173 ts = append(ts, name)
166 return 174 return
167 } 175 }
168 176
177 // modify the parameters's type to adapt the function input parameters' type
169 func magic(t reflect.Type, s string) (i interface{}, err error) { 178 func magic(t reflect.Type, s string) (i interface{}, err error) {
170 switch t.Kind() { 179 switch t.Kind() {
171 case reflect.Int: 180 case reflect.Int:
...@@ -174,10 +183,16 @@ func magic(t reflect.Type, s string) (i interface{}, err error) { ...@@ -174,10 +183,16 @@ func magic(t reflect.Type, s string) (i interface{}, err error) {
174 i = s 183 i = s
175 case reflect.Ptr: 184 case reflect.Ptr:
176 if t.Elem().String() != "regexp.Regexp" { 185 if t.Elem().String() != "regexp.Regexp" {
177 err = fmt.Errorf("%s does not support", t.Elem().String()) 186 err = fmt.Errorf("does not support %s", t.Elem().String())
178 return 187 return
179 } 188 }
180 i, err = regexp.Compile(s) 189 i, err = regexp.Compile(s)
190 default:
191 err = fmt.Errorf("does not support %s", t.Kind().String())
181 } 192 }
182 return 193 return
183 } 194 }
195
196 func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} {
197 return append([]interface{}{v, obj}, params...)
198 }
......
...@@ -67,7 +67,10 @@ func TestCall(t *testing.T) { ...@@ -67,7 +67,10 @@ func TestCall(t *testing.T) {
67 t.Fatal(err) 67 t.Fatal(err)
68 } 68 }
69 valid := &Validation{} 69 valid := &Validation{}
70 funcs.Call(vfs[1].Name, valid, u.Age, vfs[1].Params[0], vfs[1].Params[1], vfs[1].Name) 70 vfs[1].Params = append([]interface{}{valid, u.Age}, vfs[1].Params...)
71 if _, err = funcs.Call(vfs[1].Name, vfs[1].Params...); err != nil {
72 t.Fatal(err)
73 }
71 if len(valid.Errors) != 1 { 74 if len(valid.Errors) != 1 {
72 t.Error("age out of range should be has an error") 75 t.Error("age out of range should be has an error")
73 } 76 }
......
...@@ -179,26 +179,29 @@ func (v *Validation) Check(obj interface{}, checks ...Validator) *ValidationResu ...@@ -179,26 +179,29 @@ func (v *Validation) Check(obj interface{}, checks ...Validator) *ValidationResu
179 179
180 // the obj parameter must be a struct or a struct pointer 180 // the obj parameter must be a struct or a struct pointer
181 func (v *Validation) Valid(obj interface{}) (b bool, err error) { 181 func (v *Validation) Valid(obj interface{}) (b bool, err error) {
182 t := reflect.TypeOf(obj) 182 objT := reflect.TypeOf(obj)
183 objV := reflect.ValueOf(obj)
183 switch { 184 switch {
184 case isStruct(t): 185 case isStruct(objT):
185 case isStructPtr(t): 186 case isStructPtr(objT):
186 t = t.Elem() 187 objT = objT.Elem()
188 objV = objV.Elem()
187 default: 189 default:
188 err = fmt.Errorf("%v must be a struct or a struct pointer", obj) 190 err = fmt.Errorf("%v must be a struct or a struct pointer", obj)
189 return 191 return
190 } 192 }
191 // tv := reflect.TypeOf(v) 193
192 // for i := 0; i < t.NumField(); i++ { 194 for i := 0; i < objT.NumField(); i++ {
193 // f := t.Field(i) 195 var vfs []ValidFunc
194 // var vfs []ValidFunc 196 if vfs, err = getValidFuncs(objT.Field(i)); err != nil {
195 // if vfs, err = getValidFuncs(f); err != nil { 197 return
196 // return 198 }
197 // } 199 for _, vf := range vfs {
198 // for _, vf := range vfs { 200 if _, err = funcs.Call(vf.Name,
199 // m, _ := tv.MethodByName(vf.Name) 201 mergeParam(v, objV.Field(i).Interface(), vf.Params)...); err != nil {
200 // m.Func
201 // }
202 // }
203 return 202 return
203 }
204 }
205 }
206 return !v.HasErrors(), nil
204 } 207 }
......
...@@ -57,16 +57,16 @@ func TestMax(t *testing.T) { ...@@ -57,16 +57,16 @@ func TestMax(t *testing.T) {
57 } 57 }
58 } 58 }
59 59
60 // func TestRange(t *testing.T) { 60 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 bettween 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 bettween 0 and 1 should be true")
68 // } 68 }
69 // } 69 }
70 70
71 func TestMinSize(t *testing.T) { 71 func TestMinSize(t *testing.T) {
72 valid := Validation{} 72 valid := Validation{}
...@@ -217,3 +217,30 @@ func TestBase64(t *testing.T) { ...@@ -217,3 +217,30 @@ func TestBase64(t *testing.T) {
217 t.Error("\"c3VjaHVhbmdqaUBnbWFpbC5jb20=\" are a valid base64 characters should be true") 217 t.Error("\"c3VjaHVhbmdqaUBnbWFpbC5jb20=\" are a valid base64 characters should be true")
218 } 218 }
219 } 219 }
220
221 func TestValid(t *testing.T) {
222 type user struct {
223 Id int
224 Name string `valid:"Required"`
225 Age int `valid:"Required;Range(1, 140)"`
226 }
227 valid := Validation{}
228
229 u := user{Name: "test", Age: 40}
230 b, err := valid.Valid(u)
231 if err != nil {
232 t.Fatal(err)
233 }
234 if !b {
235 t.Error("validation should be passed")
236 }
237
238 uptr := &user{Name: "test", Age: 180}
239 b, err = valid.Valid(uptr)
240 if err != nil {
241 t.Fatal(err)
242 }
243 if b {
244 t.Error("validation should not be passed")
245 }
246 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!