1
0

util.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package validation
  15. import (
  16. "fmt"
  17. "reflect"
  18. "regexp"
  19. "strconv"
  20. "strings"
  21. )
  22. const (
  23. // ValidTag struct tag
  24. ValidTag = "valid"
  25. wordsize = 32 << (^uint(0) >> 32 & 1)
  26. )
  27. var (
  28. // key: function name
  29. // value: the number of parameters
  30. funcs = make(Funcs)
  31. // doesn't belong to validation functions
  32. unFuncs = map[string]bool{
  33. "Clear": true,
  34. "HasErrors": true,
  35. "ErrorMap": true,
  36. "Error": true,
  37. "apply": true,
  38. "Check": true,
  39. "Valid": true,
  40. "NoMatch": true,
  41. }
  42. // ErrInt64On32 show 32 bit platform not support int64
  43. ErrInt64On32 = fmt.Errorf("not support int64 on 32-bit platform")
  44. )
  45. func init() {
  46. v := &Validation{}
  47. t := reflect.TypeOf(v)
  48. for i := 0; i < t.NumMethod(); i++ {
  49. m := t.Method(i)
  50. if !unFuncs[m.Name] {
  51. funcs[m.Name] = m.Func
  52. }
  53. }
  54. }
  55. // CustomFunc is for custom validate function
  56. type CustomFunc func(v *Validation, obj interface{}, key string)
  57. // AddCustomFunc Add a custom function to validation
  58. // The name can not be:
  59. // Clear
  60. // HasErrors
  61. // ErrorMap
  62. // Error
  63. // Check
  64. // Valid
  65. // NoMatch
  66. // If the name is same with exists function, it will replace the origin valid function
  67. func AddCustomFunc(name string, f CustomFunc) error {
  68. if unFuncs[name] {
  69. return fmt.Errorf("invalid function name: %s", name)
  70. }
  71. funcs[name] = reflect.ValueOf(f)
  72. return nil
  73. }
  74. // ValidFunc Valid function type
  75. type ValidFunc struct {
  76. Name string
  77. Params []interface{}
  78. }
  79. // Funcs Validate function map
  80. type Funcs map[string]reflect.Value
  81. // Call validate values with named type string
  82. func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) {
  83. defer func() {
  84. if r := recover(); r != nil {
  85. err = fmt.Errorf("%v", r)
  86. }
  87. }()
  88. if _, ok := f[name]; !ok {
  89. err = fmt.Errorf("%s does not exist", name)
  90. return
  91. }
  92. if len(params) != f[name].Type().NumIn() {
  93. err = fmt.Errorf("The number of params is not adapted")
  94. return
  95. }
  96. in := make([]reflect.Value, len(params))
  97. for k, param := range params {
  98. in[k] = reflect.ValueOf(param)
  99. }
  100. result = f[name].Call(in)
  101. return
  102. }
  103. func isStruct(t reflect.Type) bool {
  104. return t.Kind() == reflect.Struct
  105. }
  106. func isStructPtr(t reflect.Type) bool {
  107. return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
  108. }
  109. func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
  110. tag := f.Tag.Get(ValidTag)
  111. if len(tag) == 0 {
  112. return
  113. }
  114. if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil {
  115. return
  116. }
  117. fs := strings.Split(tag, ";")
  118. for _, vfunc := range fs {
  119. var vf ValidFunc
  120. if len(vfunc) == 0 {
  121. continue
  122. }
  123. vf, err = parseFunc(vfunc, f.Name)
  124. if err != nil {
  125. return
  126. }
  127. vfs = append(vfs, vf)
  128. }
  129. return
  130. }
  131. // Get Match function
  132. // May be get NoMatch function in the future
  133. func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) {
  134. tag = strings.TrimSpace(tag)
  135. index := strings.Index(tag, "Match(/")
  136. if index == -1 {
  137. str = tag
  138. return
  139. }
  140. end := strings.LastIndex(tag, "/)")
  141. if end < index {
  142. err = fmt.Errorf("invalid Match function")
  143. return
  144. }
  145. reg, err := regexp.Compile(tag[index+len("Match(/") : end])
  146. if err != nil {
  147. return
  148. }
  149. vfs = []ValidFunc{{"Match", []interface{}{reg, key + ".Match"}}}
  150. str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):])
  151. return
  152. }
  153. func parseFunc(vfunc, key string) (v ValidFunc, err error) {
  154. defer func() {
  155. if r := recover(); r != nil {
  156. err = fmt.Errorf("%v", r)
  157. }
  158. }()
  159. vfunc = strings.TrimSpace(vfunc)
  160. start := strings.Index(vfunc, "(")
  161. var num int
  162. // doesn't need parameter valid function
  163. if start == -1 {
  164. if num, err = numIn(vfunc); err != nil {
  165. return
  166. }
  167. if num != 0 {
  168. err = fmt.Errorf("%s require %d parameters", vfunc, num)
  169. return
  170. }
  171. v = ValidFunc{vfunc, []interface{}{key + "." + vfunc}}
  172. return
  173. }
  174. end := strings.Index(vfunc, ")")
  175. if end == -1 {
  176. err = fmt.Errorf("invalid valid function")
  177. return
  178. }
  179. name := strings.TrimSpace(vfunc[:start])
  180. if num, err = numIn(name); err != nil {
  181. return
  182. }
  183. params := strings.Split(vfunc[start+1:end], ",")
  184. // the num of param must be equal
  185. if num != len(params) {
  186. err = fmt.Errorf("%s require %d parameters", name, num)
  187. return
  188. }
  189. tParams, err := trim(name, key+"."+name, params)
  190. if err != nil {
  191. return
  192. }
  193. v = ValidFunc{name, tParams}
  194. return
  195. }
  196. func numIn(name string) (num int, err error) {
  197. fn, ok := funcs[name]
  198. if !ok {
  199. err = fmt.Errorf("doesn't exsits %s valid function", name)
  200. return
  201. }
  202. // sub *Validation obj and key
  203. num = fn.Type().NumIn() - 3
  204. return
  205. }
  206. func trim(name, key string, s []string) (ts []interface{}, err error) {
  207. ts = make([]interface{}, len(s), len(s)+1)
  208. fn, ok := funcs[name]
  209. if !ok {
  210. err = fmt.Errorf("doesn't exsits %s valid function", name)
  211. return
  212. }
  213. for i := 0; i < len(s); i++ {
  214. var param interface{}
  215. // skip *Validation and obj params
  216. if param, err = parseParam(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil {
  217. return
  218. }
  219. ts[i] = param
  220. }
  221. ts = append(ts, key)
  222. return
  223. }
  224. // modify the parameters's type to adapt the function input parameters' type
  225. func parseParam(t reflect.Type, s string) (i interface{}, err error) {
  226. switch t.Kind() {
  227. case reflect.Int:
  228. i, err = strconv.Atoi(s)
  229. case reflect.Int64:
  230. if wordsize == 32 {
  231. return nil, ErrInt64On32
  232. }
  233. i, err = strconv.ParseInt(s, 10, 64)
  234. case reflect.Int32:
  235. var v int64
  236. v, err = strconv.ParseInt(s, 10, 32)
  237. if err == nil {
  238. i = int32(v)
  239. }
  240. case reflect.Int16:
  241. var v int64
  242. v, err = strconv.ParseInt(s, 10, 16)
  243. if err == nil {
  244. i = int16(v)
  245. }
  246. case reflect.Int8:
  247. var v int64
  248. v, err = strconv.ParseInt(s, 10, 8)
  249. if err == nil {
  250. i = int8(v)
  251. }
  252. case reflect.String:
  253. i = s
  254. case reflect.Ptr:
  255. if t.Elem().String() != "regexp.Regexp" {
  256. err = fmt.Errorf("not support %s", t.Elem().String())
  257. return
  258. }
  259. i, err = regexp.Compile(s)
  260. default:
  261. err = fmt.Errorf("not support %s", t.Kind().String())
  262. }
  263. return
  264. }
  265. func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} {
  266. return append([]interface{}{v, obj}, params...)
  267. }