validator.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. package validator
  2. import (
  3. "context"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. )
  8. // per validate contruct
  9. type validate struct {
  10. v *Validate
  11. top reflect.Value
  12. ns []byte
  13. actualNs []byte
  14. errs ValidationErrors
  15. isPartial bool
  16. hasExcludes bool
  17. includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise
  18. ffn FilterFunc
  19. // StructLevel & FieldLevel fields
  20. slflParent reflect.Value
  21. slCurrent reflect.Value
  22. flField reflect.Value
  23. fldIsPointer bool
  24. cf *cField
  25. ct *cTag
  26. // misc reusable values
  27. misc []byte
  28. str1 string
  29. str2 string
  30. }
  31. // parent and current will be the same the first run of validateStruct
  32. func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) {
  33. cs, ok := v.v.structCache.Get(typ)
  34. if !ok {
  35. cs = v.v.extractStructCache(current, typ.Name())
  36. }
  37. if len(ns) == 0 && len(cs.name) != 0 {
  38. ns = append(ns, cs.name...)
  39. ns = append(ns, '.')
  40. structNs = append(structNs, cs.name...)
  41. structNs = append(structNs, '.')
  42. }
  43. // ct is nil on top level struct, and structs as fields that have no tag info
  44. // so if nil or if not nil and the structonly tag isn't present
  45. if ct == nil || ct.typeof != typeStructOnly {
  46. var f *cField
  47. for i := 0; i < len(cs.fields); i++ {
  48. f = cs.fields[i]
  49. if v.isPartial {
  50. if v.ffn != nil {
  51. // used with StructFiltered
  52. if v.ffn(append(structNs, f.name...)) {
  53. continue
  54. }
  55. } else {
  56. // used with StructPartial & StructExcept
  57. _, ok = v.includeExclude[string(append(structNs, f.name...))]
  58. if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) {
  59. continue
  60. }
  61. }
  62. }
  63. v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags)
  64. }
  65. }
  66. // check if any struct level validations, after all field validations already checked.
  67. // first iteration will have no info about nostructlevel tag, and is checked prior to
  68. // calling the next iteration of validateStruct called from traverseField.
  69. if cs.fn != nil {
  70. v.slflParent = parent
  71. v.slCurrent = current
  72. v.ns = ns
  73. v.actualNs = structNs
  74. cs.fn(ctx, v)
  75. }
  76. }
  77. // traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
  78. func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) {
  79. var typ reflect.Type
  80. var kind reflect.Kind
  81. current, kind, v.fldIsPointer = v.extractTypeInternal(current, false)
  82. switch kind {
  83. case reflect.Ptr, reflect.Interface, reflect.Invalid:
  84. if ct == nil {
  85. return
  86. }
  87. if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault {
  88. return
  89. }
  90. if ct.hasTag {
  91. v.str1 = string(append(ns, cf.altName...))
  92. if v.v.hasTagNameFunc {
  93. v.str2 = string(append(structNs, cf.name...))
  94. } else {
  95. v.str2 = v.str1
  96. }
  97. if kind == reflect.Invalid {
  98. v.errs = append(v.errs,
  99. &fieldError{
  100. v: v.v,
  101. tag: ct.aliasTag,
  102. actualTag: ct.tag,
  103. ns: v.str1,
  104. structNs: v.str2,
  105. fieldLen: uint8(len(cf.altName)),
  106. structfieldLen: uint8(len(cf.name)),
  107. param: ct.param,
  108. kind: kind,
  109. },
  110. )
  111. return
  112. }
  113. v.errs = append(v.errs,
  114. &fieldError{
  115. v: v.v,
  116. tag: ct.aliasTag,
  117. actualTag: ct.tag,
  118. ns: v.str1,
  119. structNs: v.str2,
  120. fieldLen: uint8(len(cf.altName)),
  121. structfieldLen: uint8(len(cf.name)),
  122. value: current.Interface(),
  123. param: ct.param,
  124. kind: kind,
  125. typ: current.Type(),
  126. },
  127. )
  128. return
  129. }
  130. case reflect.Struct:
  131. typ = current.Type()
  132. if typ != timeType {
  133. if ct != nil {
  134. if ct.typeof == typeStructOnly {
  135. goto CONTINUE
  136. } else if ct.typeof == typeIsDefault {
  137. // set Field Level fields
  138. v.slflParent = parent
  139. v.flField = current
  140. v.cf = cf
  141. v.ct = ct
  142. if !ct.fn(ctx, v) {
  143. v.str1 = string(append(ns, cf.altName...))
  144. if v.v.hasTagNameFunc {
  145. v.str2 = string(append(structNs, cf.name...))
  146. } else {
  147. v.str2 = v.str1
  148. }
  149. v.errs = append(v.errs,
  150. &fieldError{
  151. v: v.v,
  152. tag: ct.aliasTag,
  153. actualTag: ct.tag,
  154. ns: v.str1,
  155. structNs: v.str2,
  156. fieldLen: uint8(len(cf.altName)),
  157. structfieldLen: uint8(len(cf.name)),
  158. value: current.Interface(),
  159. param: ct.param,
  160. kind: kind,
  161. typ: typ,
  162. },
  163. )
  164. return
  165. }
  166. }
  167. ct = ct.next
  168. }
  169. if ct != nil && ct.typeof == typeNoStructLevel {
  170. return
  171. }
  172. CONTINUE:
  173. // if len == 0 then validating using 'Var' or 'VarWithValue'
  174. // Var - doesn't make much sense to do it that way, should call 'Struct', but no harm...
  175. // VarWithField - this allows for validating against each field withing the struct against a specific value
  176. // pretty handly in certain situations
  177. if len(cf.name) > 0 {
  178. ns = append(append(ns, cf.altName...), '.')
  179. structNs = append(append(structNs, cf.name...), '.')
  180. }
  181. v.validateStruct(ctx, current, current, typ, ns, structNs, ct)
  182. return
  183. }
  184. }
  185. if !ct.hasTag {
  186. return
  187. }
  188. typ = current.Type()
  189. OUTER:
  190. for {
  191. if ct == nil {
  192. return
  193. }
  194. switch ct.typeof {
  195. case typeOmitEmpty:
  196. // set Field Level fields
  197. v.slflParent = parent
  198. v.flField = current
  199. v.cf = cf
  200. v.ct = ct
  201. if !v.fldIsPointer && !hasValue(v) {
  202. return
  203. }
  204. ct = ct.next
  205. continue
  206. case typeEndKeys:
  207. return
  208. case typeDive:
  209. ct = ct.next
  210. // traverse slice or map here
  211. // or panic ;)
  212. switch kind {
  213. case reflect.Slice, reflect.Array:
  214. var i64 int64
  215. reusableCF := &cField{}
  216. for i := 0; i < current.Len(); i++ {
  217. i64 = int64(i)
  218. v.misc = append(v.misc[0:0], cf.name...)
  219. v.misc = append(v.misc, '[')
  220. v.misc = strconv.AppendInt(v.misc, i64, 10)
  221. v.misc = append(v.misc, ']')
  222. reusableCF.name = string(v.misc)
  223. if cf.namesEqual {
  224. reusableCF.altName = reusableCF.name
  225. } else {
  226. v.misc = append(v.misc[0:0], cf.altName...)
  227. v.misc = append(v.misc, '[')
  228. v.misc = strconv.AppendInt(v.misc, i64, 10)
  229. v.misc = append(v.misc, ']')
  230. reusableCF.altName = string(v.misc)
  231. }
  232. v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct)
  233. }
  234. case reflect.Map:
  235. var pv string
  236. reusableCF := &cField{}
  237. for _, key := range current.MapKeys() {
  238. pv = fmt.Sprintf("%v", key.Interface())
  239. v.misc = append(v.misc[0:0], cf.name...)
  240. v.misc = append(v.misc, '[')
  241. v.misc = append(v.misc, pv...)
  242. v.misc = append(v.misc, ']')
  243. reusableCF.name = string(v.misc)
  244. if cf.namesEqual {
  245. reusableCF.altName = reusableCF.name
  246. } else {
  247. v.misc = append(v.misc[0:0], cf.altName...)
  248. v.misc = append(v.misc, '[')
  249. v.misc = append(v.misc, pv...)
  250. v.misc = append(v.misc, ']')
  251. reusableCF.altName = string(v.misc)
  252. }
  253. if ct != nil && ct.typeof == typeKeys && ct.keys != nil {
  254. v.traverseField(ctx, parent, key, ns, structNs, reusableCF, ct.keys)
  255. // can be nil when just keys being validated
  256. if ct.next != nil {
  257. v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next)
  258. }
  259. } else {
  260. v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct)
  261. }
  262. }
  263. default:
  264. // throw error, if not a slice or map then should not have gotten here
  265. // bad dive tag
  266. panic("dive error! can't dive on a non slice or map")
  267. }
  268. return
  269. case typeOr:
  270. v.misc = v.misc[0:0]
  271. for {
  272. // set Field Level fields
  273. v.slflParent = parent
  274. v.flField = current
  275. v.cf = cf
  276. v.ct = ct
  277. if ct.fn(ctx, v) {
  278. // drain rest of the 'or' values, then continue or leave
  279. for {
  280. ct = ct.next
  281. if ct == nil {
  282. return
  283. }
  284. if ct.typeof != typeOr {
  285. continue OUTER
  286. }
  287. }
  288. }
  289. v.misc = append(v.misc, '|')
  290. v.misc = append(v.misc, ct.tag...)
  291. if ct.hasParam {
  292. v.misc = append(v.misc, '=')
  293. v.misc = append(v.misc, ct.param...)
  294. }
  295. if ct.isBlockEnd || ct.next == nil {
  296. // if we get here, no valid 'or' value and no more tags
  297. v.str1 = string(append(ns, cf.altName...))
  298. if v.v.hasTagNameFunc {
  299. v.str2 = string(append(structNs, cf.name...))
  300. } else {
  301. v.str2 = v.str1
  302. }
  303. if ct.hasAlias {
  304. v.errs = append(v.errs,
  305. &fieldError{
  306. v: v.v,
  307. tag: ct.aliasTag,
  308. actualTag: ct.actualAliasTag,
  309. ns: v.str1,
  310. structNs: v.str2,
  311. fieldLen: uint8(len(cf.altName)),
  312. structfieldLen: uint8(len(cf.name)),
  313. value: current.Interface(),
  314. param: ct.param,
  315. kind: kind,
  316. typ: typ,
  317. },
  318. )
  319. } else {
  320. tVal := string(v.misc)[1:]
  321. v.errs = append(v.errs,
  322. &fieldError{
  323. v: v.v,
  324. tag: tVal,
  325. actualTag: tVal,
  326. ns: v.str1,
  327. structNs: v.str2,
  328. fieldLen: uint8(len(cf.altName)),
  329. structfieldLen: uint8(len(cf.name)),
  330. value: current.Interface(),
  331. param: ct.param,
  332. kind: kind,
  333. typ: typ,
  334. },
  335. )
  336. }
  337. return
  338. }
  339. ct = ct.next
  340. }
  341. default:
  342. // set Field Level fields
  343. v.slflParent = parent
  344. v.flField = current
  345. v.cf = cf
  346. v.ct = ct
  347. if !ct.fn(ctx, v) {
  348. v.str1 = string(append(ns, cf.altName...))
  349. if v.v.hasTagNameFunc {
  350. v.str2 = string(append(structNs, cf.name...))
  351. } else {
  352. v.str2 = v.str1
  353. }
  354. v.errs = append(v.errs,
  355. &fieldError{
  356. v: v.v,
  357. tag: ct.aliasTag,
  358. actualTag: ct.tag,
  359. ns: v.str1,
  360. structNs: v.str2,
  361. fieldLen: uint8(len(cf.altName)),
  362. structfieldLen: uint8(len(cf.name)),
  363. value: current.Interface(),
  364. param: ct.param,
  365. kind: kind,
  366. typ: typ,
  367. },
  368. )
  369. return
  370. }
  371. ct = ct.next
  372. }
  373. }
  374. }