struct_level.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package validator
  2. import (
  3. "context"
  4. "reflect"
  5. )
  6. // StructLevelFunc accepts all values needed for struct level validation
  7. type StructLevelFunc func(sl StructLevel)
  8. // StructLevelFuncCtx accepts all values needed for struct level validation
  9. // but also allows passing of contextual validation information vi context.Context.
  10. type StructLevelFuncCtx func(ctx context.Context, sl StructLevel)
  11. // wrapStructLevelFunc wraps noramal StructLevelFunc makes it compatible with StructLevelFuncCtx
  12. func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {
  13. return func(ctx context.Context, sl StructLevel) {
  14. fn(sl)
  15. }
  16. }
  17. // StructLevel contains all the information and helper functions
  18. // to validate a struct
  19. type StructLevel interface {
  20. // returns the main validation object, in case one want to call validations internally.
  21. // this is so you don;t have to use anonymous functoins to get access to the validate
  22. // instance.
  23. Validator() *Validate
  24. // returns the top level struct, if any
  25. Top() reflect.Value
  26. // returns the current fields parent struct, if any
  27. Parent() reflect.Value
  28. // returns the current struct.
  29. Current() reflect.Value
  30. // ExtractType gets the actual underlying type of field value.
  31. // It will dive into pointers, customTypes and return you the
  32. // underlying value and it's kind.
  33. ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool)
  34. // reports an error just by passing the field and tag information
  35. //
  36. // NOTES:
  37. //
  38. // fieldName and altName get appended to the existing namespace that
  39. // validator is on. eg. pass 'FirstName' or 'Names[0]' depending
  40. // on the nesting
  41. //
  42. // tag can be an existing validation tag or just something you make up
  43. // and process on the flip side it's up to you.
  44. ReportError(field interface{}, fieldName, structFieldName string, tag, param string)
  45. // reports an error just by passing ValidationErrors
  46. //
  47. // NOTES:
  48. //
  49. // relativeNamespace and relativeActualNamespace get appended to the
  50. // existing namespace that validator is on.
  51. // eg. pass 'User.FirstName' or 'Users[0].FirstName' depending
  52. // on the nesting. most of the time they will be blank, unless you validate
  53. // at a level lower the the current field depth
  54. ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors)
  55. }
  56. var _ StructLevel = new(validate)
  57. // Top returns the top level struct
  58. //
  59. // NOTE: this can be the same as the current struct being validated
  60. // if not is a nested struct.
  61. //
  62. // this is only called when within Struct and Field Level validation and
  63. // should not be relied upon for an acurate value otherwise.
  64. func (v *validate) Top() reflect.Value {
  65. return v.top
  66. }
  67. // Parent returns the current structs parent
  68. //
  69. // NOTE: this can be the same as the current struct being validated
  70. // if not is a nested struct.
  71. //
  72. // this is only called when within Struct and Field Level validation and
  73. // should not be relied upon for an acurate value otherwise.
  74. func (v *validate) Parent() reflect.Value {
  75. return v.slflParent
  76. }
  77. // Current returns the current struct.
  78. func (v *validate) Current() reflect.Value {
  79. return v.slCurrent
  80. }
  81. // Validator returns the main validation object, in case one want to call validations internally.
  82. func (v *validate) Validator() *Validate {
  83. return v.v
  84. }
  85. // ExtractType gets the actual underlying type of field value.
  86. func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) {
  87. return v.extractTypeInternal(field, false)
  88. }
  89. // ReportError reports an error just by passing the field and tag information
  90. func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) {
  91. fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false)
  92. if len(structFieldName) == 0 {
  93. structFieldName = fieldName
  94. }
  95. v.str1 = string(append(v.ns, fieldName...))
  96. if v.v.hasTagNameFunc || fieldName != structFieldName {
  97. v.str2 = string(append(v.actualNs, structFieldName...))
  98. } else {
  99. v.str2 = v.str1
  100. }
  101. if kind == reflect.Invalid {
  102. v.errs = append(v.errs,
  103. &fieldError{
  104. v: v.v,
  105. tag: tag,
  106. actualTag: tag,
  107. ns: v.str1,
  108. structNs: v.str2,
  109. fieldLen: uint8(len(fieldName)),
  110. structfieldLen: uint8(len(structFieldName)),
  111. param: param,
  112. kind: kind,
  113. },
  114. )
  115. return
  116. }
  117. v.errs = append(v.errs,
  118. &fieldError{
  119. v: v.v,
  120. tag: tag,
  121. actualTag: tag,
  122. ns: v.str1,
  123. structNs: v.str2,
  124. fieldLen: uint8(len(fieldName)),
  125. structfieldLen: uint8(len(structFieldName)),
  126. value: fv.Interface(),
  127. param: param,
  128. kind: kind,
  129. typ: fv.Type(),
  130. },
  131. )
  132. }
  133. // ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation.
  134. //
  135. // NOTE: this function prepends the current namespace to the relative ones.
  136. func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) {
  137. var err *fieldError
  138. for i := 0; i < len(errs); i++ {
  139. err = errs[i].(*fieldError)
  140. err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...))
  141. err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...))
  142. v.errs = append(v.errs, err)
  143. }
  144. }