util.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package validation
  2. import (
  3. "fmt"
  4. "reflect"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. "github.com/coscms/tagfast"
  9. )
  10. const (
  11. VALIDTAG = "valid"
  12. )
  13. var (
  14. // key: function name
  15. // value: the number of parameters
  16. funcs = make(Funcs)
  17. // doesn't belong to validation functions
  18. unFuncs = map[string]bool{
  19. "Clear": true,
  20. "HasErrors": true,
  21. "ErrorMap": true,
  22. "Error": true,
  23. "apply": true,
  24. "Check": true,
  25. "Valid": true,
  26. "NoMatch": true,
  27. }
  28. )
  29. func init() {
  30. v := &Validation{}
  31. t := reflect.TypeOf(v)
  32. for i := 0; i < t.NumMethod(); i++ {
  33. m := t.Method(i)
  34. if !unFuncs[m.Name] {
  35. funcs[m.Name] = m.Func
  36. }
  37. }
  38. }
  39. type ValidFunc struct {
  40. Name string
  41. Params []interface{}
  42. }
  43. type Funcs map[string]reflect.Value
  44. func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) {
  45. defer func() {
  46. if r := recover(); r != nil {
  47. err = fmt.Errorf("%v", r)
  48. }
  49. }()
  50. if _, ok := f[name]; !ok {
  51. err = fmt.Errorf("%s does not exist", name)
  52. return
  53. }
  54. if len(params) != f[name].Type().NumIn() {
  55. err = fmt.Errorf("The number of params is not adapted")
  56. return
  57. }
  58. in := make([]reflect.Value, len(params))
  59. for k, param := range params {
  60. in[k] = reflect.ValueOf(param)
  61. }
  62. result = f[name].Call(in)
  63. return
  64. }
  65. func isStruct(t reflect.Type) bool {
  66. return t.Kind() == reflect.Struct
  67. }
  68. func isStructPtr(t reflect.Type) bool {
  69. return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
  70. }
  71. func getValidFuncs(f reflect.StructField, t reflect.Type, fName string) (vfs []ValidFunc, err error) {
  72. tag, tagf := tagfast.Tago(t, f, VALIDTAG)
  73. if len(tag) == 0 {
  74. return
  75. }
  76. cached := tagf.GetParsed(VALIDTAG)
  77. if cached == nil {
  78. //fmt.Printf("%s :[Tag]: %s\n\n", fName, tag)
  79. if vfs, tag, err = getRegFuncs(tag, fName); err != nil {
  80. fmt.Printf("%+v\n", err)
  81. return
  82. }
  83. fs := strings.Split(tag, ";")
  84. for _, vfunc := range fs {
  85. var vf ValidFunc
  86. if len(vfunc) == 0 {
  87. continue
  88. }
  89. vf, err = parseFunc(vfunc, fName)
  90. if err != nil {
  91. return
  92. }
  93. vfs = append(vfs, vf)
  94. }
  95. tagf.SetParsed(VALIDTAG, vfs)
  96. } else {
  97. vfs = cached.([]ValidFunc)
  98. } // */_ = tagf
  99. return
  100. }
  101. // Get Match function
  102. // May be get NoMatch function in the future
  103. func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) {
  104. tag = strings.TrimSpace(tag)
  105. index := strings.Index(tag, "Match(/")
  106. if index == -1 {
  107. str = tag
  108. return
  109. }
  110. end := strings.LastIndex(tag, "/)")
  111. if end < index {
  112. err = fmt.Errorf("invalid Match function")
  113. return
  114. }
  115. reg, err := regexp.Compile(tag[index+len("Match(/") : end])
  116. if err != nil {
  117. return
  118. }
  119. vfs = []ValidFunc{ValidFunc{"Match", []interface{}{reg, key + "|Match"}}}
  120. str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):])
  121. return
  122. }
  123. func parseFunc(vfunc, key string) (v ValidFunc, err error) {
  124. defer func() {
  125. if r := recover(); r != nil {
  126. err = fmt.Errorf("%v", r)
  127. }
  128. }()
  129. vfunc = strings.TrimSpace(vfunc)
  130. start := strings.Index(vfunc, "(")
  131. var num int
  132. // doesn't need parameter valid function
  133. if start == -1 {
  134. if num, err = numIn(vfunc); err != nil {
  135. return
  136. }
  137. if num != 0 {
  138. err = fmt.Errorf("%s require %d parameters", vfunc, num)
  139. return
  140. }
  141. v = ValidFunc{vfunc, []interface{}{key + "|" + vfunc}}
  142. return
  143. }
  144. end := strings.Index(vfunc, ")")
  145. if end == -1 {
  146. err = fmt.Errorf("invalid valid function")
  147. return
  148. }
  149. name := strings.TrimSpace(vfunc[:start])
  150. if num, err = numIn(name); err != nil {
  151. return
  152. }
  153. params := strings.Split(vfunc[start+1:end], ",")
  154. // the num of param must be equal
  155. if num != len(params) {
  156. err = fmt.Errorf("%s require %d parameters", name, num)
  157. return
  158. }
  159. tParams, err := trim(name, key+"|"+name, params)
  160. if err != nil {
  161. return
  162. }
  163. v = ValidFunc{name, tParams}
  164. return
  165. }
  166. func numIn(name string) (num int, err error) {
  167. fn, ok := funcs[name]
  168. if !ok {
  169. err = fmt.Errorf("doesn't exsits %s valid function", name)
  170. return
  171. }
  172. // sub *Validation obj and key
  173. num = fn.Type().NumIn() - 3
  174. return
  175. }
  176. func trim(name, key string, s []string) (ts []interface{}, err error) {
  177. ts = make([]interface{}, len(s), len(s)+1)
  178. fn, ok := funcs[name]
  179. if !ok {
  180. err = fmt.Errorf("doesn't exsits %s valid function", name)
  181. return
  182. }
  183. for i := 0; i < len(s); i++ {
  184. var param interface{}
  185. // skip *Validation and obj params
  186. if param, err = magic(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil {
  187. return
  188. }
  189. ts[i] = param
  190. }
  191. ts = append(ts, key)
  192. return
  193. }
  194. // modify the parameters's type to adapt the function input parameters' type
  195. func magic(t reflect.Type, s string) (i interface{}, err error) {
  196. switch t.Kind() {
  197. case reflect.Int:
  198. i, err = strconv.Atoi(s)
  199. case reflect.String:
  200. i = s
  201. case reflect.Ptr:
  202. if t.Elem().String() != "regexp.Regexp" {
  203. err = fmt.Errorf("does not support %s", t.Elem().String())
  204. return
  205. }
  206. i, err = regexp.Compile(s)
  207. default:
  208. err = fmt.Errorf("does not support %s", t.Kind().String())
  209. }
  210. return
  211. }
  212. func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} {
  213. return append([]interface{}{v, obj}, params...)
  214. }