@@ -2,10 +2,12 @@ package validator
22
33import (
44 "bytes"
5+ "cmp"
56 "context"
67 "crypto/sha256"
78 "encoding/hex"
89 "encoding/json"
10+ "errors"
911 "fmt"
1012 "io/fs"
1113 "net"
@@ -3049,27 +3051,58 @@ func isEIN(fl FieldLevel) bool {
30493051}
30503052
30513053func isValidateFn (fl FieldLevel ) bool {
3052- if instance , ok := tryConvertFieldTo [interface { Validate () error }](fl .Field ()); ok {
3053- return instance .Validate () == nil
3054+ const defaultParam = `Validate`
3055+
3056+ field := fl .Field ()
3057+ param := cmp .Or (fl .Param (), defaultParam )
3058+
3059+ ok , err := tryCallValidateFn (field , param )
3060+ if err != nil {
3061+ panic (err )
30543062 }
30553063
3056- return false
3064+ return ok
30573065}
30583066
3059- func tryConvertFieldTo [V any ](field reflect.Value ) (v V , ok bool ) {
3060- v , ok = convertFieldTo [V ](field )
3061- if ! ok && field .CanAddr () {
3062- v , ok = convertFieldTo [V ](field .Addr ())
3067+ var (
3068+ errMethodNotFound = errors .New (`method not found` )
3069+ errMethodReturnNoValues = errors .New (`method return o values (void)` )
3070+ errMethodReturnInvalidType = errors .New (`method should return invalid type` )
3071+ )
3072+
3073+ func tryCallValidateFn (field reflect.Value , methodName string ) (bool , error ) {
3074+ method := field .MethodByName (methodName )
3075+ if ! method .IsValid () {
3076+ method = field .Addr ().MethodByName (methodName )
30633077 }
30643078
3065- return v , ok
3066- }
3079+ if ! method .IsValid () {
3080+ return false , fmt .Errorf ("unable to call %q on type %q: %w" ,
3081+ methodName , field .Type ().String (), errMethodNotFound )
3082+ }
30673083
3068- func convertFieldTo [V any ](field reflect.Value ) (v V , ok bool ) {
3069- if v , ok = field .Interface ().(V ); ok {
3070- return v , ok
3084+ returnValues := method .Call ([]reflect.Value {})
3085+ if len (returnValues ) == 0 {
3086+ return false , fmt .Errorf ("unable to use result of method %q on type %q: %w" ,
3087+ methodName , field .Type ().String (), errMethodReturnNoValues )
30713088 }
30723089
3073- var zero V
3074- return zero , false
3090+ firstReturnValue := returnValues [0 ]
3091+
3092+ switch firstReturnValue .Kind () {
3093+ case reflect .Bool :
3094+ return firstReturnValue .Bool (), nil
3095+ case reflect .Interface :
3096+ errorType := reflect .TypeOf ((* error )(nil )).Elem ()
3097+
3098+ if firstReturnValue .Type ().Implements (errorType ) {
3099+ return firstReturnValue .IsNil (), nil
3100+ }
3101+
3102+ return false , fmt .Errorf ("unable to use result of method %q on type %q: %w (got interface %v expect error)" ,
3103+ methodName , field .Type ().String (), errMethodReturnInvalidType , firstReturnValue .Type ().String ())
3104+ default :
3105+ return false , fmt .Errorf ("unable to use result of method %q on type %q: %w (got %v expect error or bool)" ,
3106+ methodName , field .Type ().String (), errMethodReturnInvalidType , firstReturnValue .Type ().String ())
3107+ }
30753108}
0 commit comments