123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package valid
- import (
- "context"
- "reflect"
- "strings"
- )
- func ValidateStruct(structPtr interface{}, fields ...*FieldRules) error {
- return ValidateStructWithContext(nil, structPtr, fields...)
- }
- func ValidateStructWithContext(ctx context.Context, structPtr interface{}, fields ...*FieldRules) error {
- value := reflect.ValueOf(structPtr)
- if value.Kind() != reflect.Ptr || !value.IsNil() && value.Elem().Kind() != reflect.Struct {
-
- return NewInternalError(ErrStructPointer)
- }
- if value.IsNil() {
-
- return nil
- }
- value = value.Elem()
- errs := Errors{}
- for i, fr := range fields {
- fv := reflect.ValueOf(fr.fieldPtr)
- if fv.Kind() != reflect.Ptr {
- return NewInternalError(ErrFieldPointer(i))
- }
- ft := findStructField(value, fv)
- if ft == nil {
- return NewInternalError(ErrFieldNotFound(i))
- }
- var err error
- if ctx == nil {
- err = Validate(fv.Elem().Interface(), fr.rules...)
- } else {
- err = ValidateWithContext(ctx, fv.Elem().Interface(), fr.rules...)
- }
- if err != nil {
- if ie, ok := err.(InternalError); ok && ie.InternalError() != nil {
- return err
- }
- if ft.Anonymous {
-
- if es, ok := err.(Errors); ok {
- for name, value := range es {
- errs[name] = value
- }
- continue
- }
- }
- errs[getErrorFieldName(ft)] = err
- }
- }
- if len(errs) > 0 {
- return errs
- }
- return nil
- }
- type FieldRules struct {
- fieldPtr interface{}
- rules []Rule
- }
- func Field(fieldPtr interface{}, rules ...Rule) *FieldRules {
- return &FieldRules{
- fieldPtr: fieldPtr,
- rules: rules,
- }
- }
- func findStructField(structValue reflect.Value, fieldValue reflect.Value) *reflect.StructField {
- ptr := fieldValue.Pointer()
- for i := structValue.NumField() - 1; i >= 0; i-- {
- sf := structValue.Type().Field(i)
- if ptr == structValue.Field(i).UnsafeAddr() {
-
-
- if sf.Type == fieldValue.Elem().Type() {
- return &sf
- }
- }
- if sf.Anonymous {
-
- fi := structValue.Field(i)
- if sf.Type.Kind() == reflect.Ptr {
- fi = fi.Elem()
- }
- if fi.Kind() == reflect.Struct {
- if f := findStructField(fi, fieldValue); f != nil {
- return f
- }
- }
- }
- }
- return nil
- }
- func getErrorFieldName(f *reflect.StructField) string {
- if tag := f.Tag.Get(ErrorTag); tag != "" && tag != "-" {
- if cps := strings.SplitN(tag, ",", 2); cps[0] != "" {
- return cps[0]
- }
- }
- return f.Name
- }
|