util.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. package validator
  2. import (
  3. "fmt"
  4. "reflect"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. "time"
  9. )
  10. // extractTypeInternal gets the actual underlying type of field value.
  11. // It will dive into pointers, customTypes and return you the
  12. // underlying value and it's kind.
  13. func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) {
  14. BEGIN:
  15. switch current.Kind() {
  16. case reflect.Ptr:
  17. nullable = true
  18. if current.IsNil() {
  19. return current, reflect.Ptr, nullable
  20. }
  21. current = current.Elem()
  22. goto BEGIN
  23. case reflect.Interface:
  24. nullable = true
  25. if current.IsNil() {
  26. return current, reflect.Interface, nullable
  27. }
  28. current = current.Elem()
  29. goto BEGIN
  30. case reflect.Invalid:
  31. return current, reflect.Invalid, nullable
  32. default:
  33. if v.v.hasCustomFuncs {
  34. if fn, ok := v.v.customFuncs[current.Type()]; ok {
  35. current = reflect.ValueOf(fn(current))
  36. goto BEGIN
  37. }
  38. }
  39. return current, current.Kind(), nullable
  40. }
  41. }
  42. // getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and
  43. // returns the field, field kind and whether is was successful in retrieving the field at all.
  44. //
  45. // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
  46. // could not be retrieved because it didn't exist.
  47. func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) {
  48. BEGIN:
  49. current, kind, nullable = v.ExtractType(val)
  50. if kind == reflect.Invalid {
  51. return
  52. }
  53. if namespace == "" {
  54. found = true
  55. return
  56. }
  57. switch kind {
  58. case reflect.Ptr, reflect.Interface:
  59. return
  60. case reflect.Struct:
  61. typ := current.Type()
  62. fld := namespace
  63. var ns string
  64. if !typ.ConvertibleTo(timeType) {
  65. idx := strings.Index(namespace, namespaceSeparator)
  66. if idx != -1 {
  67. fld = namespace[:idx]
  68. ns = namespace[idx+1:]
  69. } else {
  70. ns = ""
  71. }
  72. bracketIdx := strings.Index(fld, leftBracket)
  73. if bracketIdx != -1 {
  74. fld = fld[:bracketIdx]
  75. ns = namespace[bracketIdx:]
  76. }
  77. val = current.FieldByName(fld)
  78. namespace = ns
  79. goto BEGIN
  80. }
  81. case reflect.Array, reflect.Slice:
  82. idx := strings.Index(namespace, leftBracket)
  83. idx2 := strings.Index(namespace, rightBracket)
  84. arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
  85. if arrIdx >= current.Len() {
  86. return
  87. }
  88. startIdx := idx2 + 1
  89. if startIdx < len(namespace) {
  90. if namespace[startIdx:startIdx+1] == namespaceSeparator {
  91. startIdx++
  92. }
  93. }
  94. val = current.Index(arrIdx)
  95. namespace = namespace[startIdx:]
  96. goto BEGIN
  97. case reflect.Map:
  98. idx := strings.Index(namespace, leftBracket) + 1
  99. idx2 := strings.Index(namespace, rightBracket)
  100. endIdx := idx2
  101. if endIdx+1 < len(namespace) {
  102. if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
  103. endIdx++
  104. }
  105. }
  106. key := namespace[idx:idx2]
  107. switch current.Type().Key().Kind() {
  108. case reflect.Int:
  109. i, _ := strconv.Atoi(key)
  110. val = current.MapIndex(reflect.ValueOf(i))
  111. namespace = namespace[endIdx+1:]
  112. case reflect.Int8:
  113. i, _ := strconv.ParseInt(key, 10, 8)
  114. val = current.MapIndex(reflect.ValueOf(int8(i)))
  115. namespace = namespace[endIdx+1:]
  116. case reflect.Int16:
  117. i, _ := strconv.ParseInt(key, 10, 16)
  118. val = current.MapIndex(reflect.ValueOf(int16(i)))
  119. namespace = namespace[endIdx+1:]
  120. case reflect.Int32:
  121. i, _ := strconv.ParseInt(key, 10, 32)
  122. val = current.MapIndex(reflect.ValueOf(int32(i)))
  123. namespace = namespace[endIdx+1:]
  124. case reflect.Int64:
  125. i, _ := strconv.ParseInt(key, 10, 64)
  126. val = current.MapIndex(reflect.ValueOf(i))
  127. namespace = namespace[endIdx+1:]
  128. case reflect.Uint:
  129. i, _ := strconv.ParseUint(key, 10, 0)
  130. val = current.MapIndex(reflect.ValueOf(uint(i)))
  131. namespace = namespace[endIdx+1:]
  132. case reflect.Uint8:
  133. i, _ := strconv.ParseUint(key, 10, 8)
  134. val = current.MapIndex(reflect.ValueOf(uint8(i)))
  135. namespace = namespace[endIdx+1:]
  136. case reflect.Uint16:
  137. i, _ := strconv.ParseUint(key, 10, 16)
  138. val = current.MapIndex(reflect.ValueOf(uint16(i)))
  139. namespace = namespace[endIdx+1:]
  140. case reflect.Uint32:
  141. i, _ := strconv.ParseUint(key, 10, 32)
  142. val = current.MapIndex(reflect.ValueOf(uint32(i)))
  143. namespace = namespace[endIdx+1:]
  144. case reflect.Uint64:
  145. i, _ := strconv.ParseUint(key, 10, 64)
  146. val = current.MapIndex(reflect.ValueOf(i))
  147. namespace = namespace[endIdx+1:]
  148. case reflect.Float32:
  149. f, _ := strconv.ParseFloat(key, 32)
  150. val = current.MapIndex(reflect.ValueOf(float32(f)))
  151. namespace = namespace[endIdx+1:]
  152. case reflect.Float64:
  153. f, _ := strconv.ParseFloat(key, 64)
  154. val = current.MapIndex(reflect.ValueOf(f))
  155. namespace = namespace[endIdx+1:]
  156. case reflect.Bool:
  157. b, _ := strconv.ParseBool(key)
  158. val = current.MapIndex(reflect.ValueOf(b))
  159. namespace = namespace[endIdx+1:]
  160. // reflect.Type = string
  161. default:
  162. val = current.MapIndex(reflect.ValueOf(key))
  163. namespace = namespace[endIdx+1:]
  164. }
  165. goto BEGIN
  166. }
  167. // if got here there was more namespace, cannot go any deeper
  168. panic("Invalid field namespace")
  169. }
  170. // asInt returns the parameter as a int64
  171. // or panics if it can't convert
  172. func asInt(param string) int64 {
  173. i, err := strconv.ParseInt(param, 0, 64)
  174. panicIf(err)
  175. return i
  176. }
  177. // asIntFromTimeDuration parses param as time.Duration and returns it as int64
  178. // or panics on error.
  179. func asIntFromTimeDuration(param string) int64 {
  180. d, err := time.ParseDuration(param)
  181. if err != nil {
  182. // attempt parsing as an integer assuming nanosecond precision
  183. return asInt(param)
  184. }
  185. return int64(d)
  186. }
  187. // asIntFromType calls the proper function to parse param as int64,
  188. // given a field's Type t.
  189. func asIntFromType(t reflect.Type, param string) int64 {
  190. switch t {
  191. case timeDurationType:
  192. return asIntFromTimeDuration(param)
  193. default:
  194. return asInt(param)
  195. }
  196. }
  197. // asUint returns the parameter as a uint64
  198. // or panics if it can't convert
  199. func asUint(param string) uint64 {
  200. i, err := strconv.ParseUint(param, 0, 64)
  201. panicIf(err)
  202. return i
  203. }
  204. // asFloat64 returns the parameter as a float64
  205. // or panics if it can't convert
  206. func asFloat64(param string) float64 {
  207. i, err := strconv.ParseFloat(param, 64)
  208. panicIf(err)
  209. return i
  210. }
  211. // asFloat32 returns the parameter as a float32
  212. // or panics if it can't convert
  213. func asFloat32(param string) float64 {
  214. i, err := strconv.ParseFloat(param, 32)
  215. panicIf(err)
  216. return i
  217. }
  218. // asBool returns the parameter as a bool
  219. // or panics if it can't convert
  220. func asBool(param string) bool {
  221. i, err := strconv.ParseBool(param)
  222. panicIf(err)
  223. return i
  224. }
  225. func panicIf(err error) {
  226. if err != nil {
  227. panic(err.Error())
  228. }
  229. }
  230. // Checks if field value matches regex. If fl.Field can be cast to Stringer, it uses the Stringer interfaces
  231. // String() return value. Otherwise, it uses fl.Field's String() value.
  232. func fieldMatchesRegexByStringerValOrString(regexFn func() *regexp.Regexp, fl FieldLevel) bool {
  233. regex := regexFn()
  234. switch fl.Field().Kind() {
  235. case reflect.String:
  236. return regex.MatchString(fl.Field().String())
  237. default:
  238. if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok {
  239. return regex.MatchString(stringer.String())
  240. } else {
  241. return regex.MatchString(fl.Field().String())
  242. }
  243. }
  244. }