add struct tag support
Showing
4 changed files
with
78 additions
and
30 deletions
| ... | @@ -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 | 202 | return |
| 201 | // } | 203 | } |
| 202 | // } | 204 | } |
| 203 | return | 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 | } | ... | ... |
-
Please register or sign in to post a comment