github.com/sandwich-go/boost@v1.3.29/validator/validator.go (about)

     1  package validator
     2  
     3  import (
     4  	"context"
     5  	ut "github.com/go-playground/universal-translator"
     6  	validator2 "github.com/go-playground/validator/v10"
     7  	"github.com/sandwich-go/boost/xerror"
     8  	"reflect"
     9  )
    10  
    11  type (
    12  	// FieldError contains all functions to get error details
    13  	FieldError = validator2.FieldError
    14  	// FieldLevel contains all the information and helper functions
    15  	// to validate a field
    16  	FieldLevel = validator2.FieldLevel
    17  	// StructLevel contains all the information and helper functions
    18  	// to validate a struct
    19  	StructLevel = validator2.StructLevel
    20  	// TagNameFunc allows for adding of a custom tag name parser
    21  	TagNameFunc = validator2.TagNameFunc
    22  	// Func accepts a context.Context and FieldLevel interface for all
    23  	// validation needs. The return value should be true when validation succeeds.
    24  	Func = validator2.FuncCtx
    25  	// StructLevelFunc accepts all values needed for struct level validation
    26  	// but also allows passing of contextual validation information via context.Context.
    27  	StructLevelFunc = validator2.StructLevelFuncCtx
    28  	// CustomTypeFunc allows for overriding or adding custom field type handler functions
    29  	// field = field value of the type to return a value to be validated
    30  	// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29
    31  	CustomTypeFunc = validator2.CustomTypeFunc
    32  	// RegisterTranslationsFunc allows for registering of translations
    33  	// for a 'ut.Translator' for use within the 'TranslationFunc'
    34  	RegisterTranslationsFunc = validator2.RegisterTranslationsFunc
    35  	// TranslationFunc is the function type used to register or override
    36  	// custom translations
    37  	TranslationFunc = validator2.TranslationFunc
    38  	// FilterFunc is the type used to filter fields using
    39  	// StructFiltered(...) function.
    40  	// returning true results in the field being filtered/skiped from
    41  	// validation
    42  	FilterFunc = validator2.FilterFunc
    43  
    44  	// ValidationErrors is an array of FieldError's
    45  	// for use in custom error messages post validation.
    46  	ValidationErrors = validator2.ValidationErrors
    47  )
    48  
    49  // Validator validator
    50  type Validator interface {
    51  	// SetTagName allows for changing of the default tag name of Validator
    52  	SetTagName(name string)
    53  
    54  	// ValidateMap validates a map using a map of validation rules and allows passing of contextual
    55  	// validation validation information via context.Context.
    56  	ValidateMap(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{}
    57  
    58  	// RegisterTagNameFunc registers a function to get alternate names for StructFields.
    59  	//
    60  	// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
    61  	//
    62  	//    validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
    63  	//        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
    64  	//        // skip if tag key says it should be ignored
    65  	//        if name == "-" {
    66  	//            return ""
    67  	//        }
    68  	//        return name
    69  	//    })
    70  	RegisterTagNameFunc(fn TagNameFunc)
    71  
    72  	// RegisterAlias registers a mapping of a single validation tag that
    73  	// defines a common or complex set of validation(s) to simplify adding validation
    74  	// to structs.
    75  	//
    76  	// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation
    77  	RegisterAlias(alias, tags string)
    78  
    79  	// RegisterValidation adds a validation with the given tag
    80  	// allowing context.Context validation support.
    81  	//
    82  	// NOTES:
    83  	// - if the key already exists, the previous validation function will be replaced.
    84  	// - this method is not thread-safe it is intended that these all be registered prior to any validation
    85  	RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error
    86  
    87  	// RegisterStructValidation registers a StructLevelFunc against a number of types and allows passing
    88  	// of contextual validation information via context.Context.
    89  	//
    90  	// NOTE:
    91  	// - this method is not thread-safe it is intended that these all be registered prior to any validation
    92  	RegisterStructValidation(fn StructLevelFunc, types ...interface{})
    93  
    94  	// RegisterStructValidationMapRules registers validate map rules.
    95  	// Be aware that map validation rules supersede those defined on a/the struct if present.
    96  	//
    97  	// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
    98  	RegisterStructValidationMapRules(rules map[string]string, types ...interface{})
    99  
   100  	// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
   101  	//
   102  	// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
   103  	RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{})
   104  
   105  	// RegisterTranslation registers translations against the provided tag.
   106  	RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) error
   107  
   108  	// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified
   109  	// and also allows passing of context.Context for contextual validation information.
   110  	//
   111  	// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   112  	// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   113  	Struct(ctx context.Context, s interface{}) error
   114  
   115  	// StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates
   116  	// nested structs, unless otherwise specified and also allows passing of contextual validation information via
   117  	// context.Context
   118  	//
   119  	// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   120  	// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   121  	StructFiltered(ctx context.Context, s interface{}, fn FilterFunc) error
   122  
   123  	// StructPartial validates the fields passed in only, ignoring all others and allows passing of contextual
   124  	// validation validation information via context.Context
   125  	// Fields may be provided in a namespaced fashion relative to the  struct provided
   126  	// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
   127  	//
   128  	// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   129  	// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   130  	StructPartial(ctx context.Context, s interface{}, fields ...string) error
   131  
   132  	// StructExcept validates all fields except the ones passed in and allows passing of contextual
   133  	// validation validation information via context.Context
   134  	// Fields may be provided in a namespaced fashion relative to the  struct provided
   135  	// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
   136  	//
   137  	// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   138  	// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   139  	StructExcept(ctx context.Context, s interface{}, fields ...string) error
   140  
   141  	// Var validates a single variable using tag style validation and allows passing of contextual
   142  	// validation validation information via context.Context.
   143  	// eg.
   144  	// var i int
   145  	// validate.Var(i, "gt=1,lt=10")
   146  	//
   147  	// WARNING: a struct can be passed for validation eg. time.Time is a struct or
   148  	// if you have a custom type and have registered a custom type handler, so must
   149  	// allow it; however unforeseen validations will occur if trying to validate a
   150  	// struct that is meant to be passed to 'validate.Struct'
   151  	//
   152  	// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   153  	// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   154  	// validate Array, Slice and maps fields which may contain more than one error
   155  	Var(ctx context.Context, val interface{}, tag string) error
   156  
   157  	// VarWithValue validates a single variable, against another variable/field's value using tag style validation and
   158  	// allows passing of contextual validation validation information via context.Context.
   159  	// eg.
   160  	// s1 := "abcd"
   161  	// s2 := "abcd"
   162  	// validate.VarWithValue(s1, s2, "eqcsfield") // returns true
   163  	//
   164  	// WARNING: a struct can be passed for validation eg. time.Time is a struct or
   165  	// if you have a custom type and have registered a custom type handler, so must
   166  	// allow it; however unforeseen validations will occur if trying to validate a
   167  	// struct that is meant to be passed to 'validate.Struct'
   168  	//
   169  	// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
   170  	// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
   171  	// validate Array, Slice and maps fields which may contain more than one error
   172  	VarWithValue(ctx context.Context, field interface{}, other interface{}, tag string) error
   173  }
   174  
   175  var (
   176  	Default  = New()
   177  	Validate = Default
   178  )
   179  
   180  type validate struct {
   181  	v *validator2.Validate
   182  }
   183  
   184  // New returns a new Validator with sane defaults.
   185  // Validator is designed to be thread-safe and used as a singleton instance.
   186  // It caches information about your struct and validations,
   187  // in essence only parsing your validation tags once per struct type.
   188  // Using multiple instances neglects the benefit of caching.
   189  func New() Validator {
   190  	return &validate{v: validator2.New()}
   191  }
   192  
   193  func (v *validate) SetTagName(name string)             { v.v.SetTagName(name) }
   194  func (v *validate) RegisterTagNameFunc(fn TagNameFunc) { v.v.RegisterTagNameFunc(fn) }
   195  func (v *validate) RegisterAlias(alias, tags string)   { v.v.RegisterAlias(alias, tags) }
   196  func (v *validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error {
   197  	return v.v.RegisterValidationCtx(tag, fn, callValidationEvenIfNull...)
   198  }
   199  func (v *validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) {
   200  	v.v.RegisterStructValidationCtx(fn, types...)
   201  }
   202  func (v *validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) {
   203  	v.v.RegisterStructValidationMapRules(rules, types...)
   204  }
   205  func (v *validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {
   206  	v.v.RegisterCustomTypeFunc(fn, types...)
   207  }
   208  func (v *validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) error {
   209  	return v.v.RegisterTranslation(tag, trans, registerFn, translationFn)
   210  }
   211  func (v *validate) ValidateMap(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
   212  	return v.v.ValidateMapCtx(ctx, data, rules)
   213  }
   214  func (v *validate) Var(ctx context.Context, val interface{}, tag string) (err error) {
   215  	defer func() {
   216  		if r := recover(); r != nil {
   217  			err = xerror.NewText("validate panic with val: %v, tag: %s, reason: %v", val, tag, r)
   218  		}
   219  	}()
   220  	err = v.v.VarCtx(ctx, val, tag)
   221  	return
   222  }
   223  func (v *validate) Struct(ctx context.Context, s interface{}) (err error) {
   224  	defer func() {
   225  		if r := recover(); r != nil {
   226  			err = xerror.NewText("validate panic with struct: %s, reason: %v", reflect.TypeOf(s).String(), r)
   227  		}
   228  	}()
   229  	err = v.v.StructCtx(ctx, s)
   230  	return
   231  }
   232  func (v *validate) StructFiltered(ctx context.Context, s interface{}, fn FilterFunc) error {
   233  	return v.v.StructFilteredCtx(ctx, s, fn)
   234  }
   235  func (v *validate) StructPartial(ctx context.Context, s interface{}, fields ...string) error {
   236  	return v.v.StructPartialCtx(ctx, s, fields...)
   237  }
   238  func (v *validate) StructExcept(ctx context.Context, s interface{}, fields ...string) error {
   239  	return v.v.StructExceptCtx(ctx, s, fields...)
   240  }
   241  func (v *validate) VarWithValue(ctx context.Context, field interface{}, other interface{}, tag string) error {
   242  	return v.v.VarWithValueCtx(ctx, field, other, tag)
   243  }