aba1728b by miraclesu

add some util funcs

1 parent ddb9ed39
1 package validation
2
3 import (
4 "fmt"
5 "reflect"
6 "strings"
7 )
8
9 const (
10 VALIDTAG = "valid"
11 )
12
13 var (
14 // key: function name
15 // value: the number of parameters
16 funcs = make(map[string]int)
17
18 // doesn't belong to validation functions
19 unFuncs = map[string]bool{
20 "Clear": true,
21 "HasErrors": true,
22 "ErrorMap": true,
23 "Error": true,
24 "apply": true,
25 "Check": true,
26 "Valid": true,
27 }
28 )
29
30 func init() {
31 v := &Validation{}
32 t := reflect.TypeOf(v)
33 for i := 0; i < t.NumMethod(); i++ {
34 m := t.Method(i)
35 if !unFuncs[m.Name] {
36 funcs[m.Name] = m.Type.NumIn() - 3
37 }
38 }
39 }
40
41 type ValidFunc struct {
42 Name string
43 Params []interface{}
44 }
45
46 func isStruct(t reflect.Type) bool {
47 return t.Kind() == reflect.Struct
48 }
49
50 func isStructPtr(t reflect.Type) bool {
51 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
52 }
53
54 func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
55 tag := f.Tag.Get(VALIDTAG)
56 if len(tag) == 0 {
57 return
58 }
59 fs := strings.Split(tag, ";")
60 for _, vfunc := range fs {
61 var vf ValidFunc
62 vf, err = parseFunc(vfunc)
63 if err != nil {
64 return
65 }
66 vfs = append(vfs, vf)
67 }
68 return
69 }
70
71 func parseFunc(vfunc string) (v ValidFunc, err error) {
72 defer func() {
73 if r := recover(); r != nil {
74 err = r.(error)
75 }
76 }()
77
78 vfunc = strings.TrimSpace(vfunc)
79 start := strings.Index(vfunc, "(")
80 var num int
81
82 // doesn't need parameter valid function
83 if start == -1 {
84 if num, err = numIn(vfunc); err != nil {
85 return
86 }
87 if num != 0 {
88 err = fmt.Errorf("%s require %d parameters", vfunc, num)
89 return
90 }
91 v = ValidFunc{Name: vfunc}
92 return
93 }
94
95 end := strings.Index(vfunc, ")")
96 if end == -1 {
97 err = fmt.Errorf("invalid valid function")
98 return
99 }
100
101 name := strings.TrimSpace(vfunc[:start])
102 if num, err = numIn(name); err != nil {
103 return
104 }
105
106 params := strings.Split(vfunc[start+1:end], ",")
107 // the num of param must be equal
108 if num != len(params) {
109 err = fmt.Errorf("%s require %d parameters", name, num)
110 return
111 }
112
113 v = ValidFunc{name, trim(params)}
114 return
115 }
116
117 func numIn(name string) (num int, err error) {
118 num, ok := funcs[name]
119 if !ok {
120 err = fmt.Errorf("doesn't exsits %s valid function", name)
121 }
122 return
123 }
124
125 func trim(s []string) []interface{} {
126 ts := make([]interface{}, len(s))
127 for i := 0; i < len(s); i++ {
128 ts[i] = strings.TrimSpace(s[i])
129 }
130 return ts
131 }
1 package validation
2
3 import (
4 "reflect"
5 "testing"
6 )
7
8 type user struct {
9 Id int
10 Tag string `valid:"Maxx(aa)"`
11 Name string `valid:"Required"`
12 Age int `valid:"Required;Range(1, 140)"`
13 }
14
15 func TestGetValidFuncs(t *testing.T) {
16 u := user{Name: "test", Age: 1}
17 tf := reflect.TypeOf(u)
18 var vfs []ValidFunc
19 var err error
20
21 f, _ := tf.FieldByName("Id")
22 if vfs, err = getValidFuncs(f); err != nil {
23 t.Fatal(err)
24 }
25 if len(vfs) != 0 {
26 t.Fatal("should get none ValidFunc")
27 }
28
29 f, _ = tf.FieldByName("Tag")
30 if vfs, err = getValidFuncs(f); err.Error() != "doesn't exsits Maxx valid function" {
31 t.Fatal(err)
32 }
33
34 f, _ = tf.FieldByName("Name")
35 if vfs, err = getValidFuncs(f); err != nil {
36 t.Fatal(err)
37 }
38 if len(vfs) != 1 {
39 t.Fatal("should get 1 ValidFunc")
40 }
41 if vfs[0].Name != "Required" && len(vfs[0].Params) != 0 {
42 t.Error("Required funcs should be got")
43 }
44
45 f, _ = tf.FieldByName("Age")
46 if vfs, err = getValidFuncs(f); err != nil {
47 t.Fatal(err)
48 }
49 if len(vfs) != 2 {
50 t.Fatal("should get 2 ValidFunc")
51 }
52 if vfs[0].Name != "Required" && len(vfs[0].Params) != 0 {
53 t.Error("Required funcs should be got")
54 }
55 if vfs[1].Name != "Range" && len(vfs[1].Params) != 2 {
56 t.Error("Range funcs should be got")
57 }
58 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!