123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- package valid
- import (
- "fmt"
- "reflect"
- "time"
- )
- var (
- // ErrMinGreaterEqualThanRequired is the error that returns when a value is less than a specified threshold.
- ErrMinGreaterEqualThanRequired = NewError("validation_min_greater_equal_than_required", "must be no less than {{.threshold}}")
- // ErrMaxLessEqualThanRequired is the error that returns when a value is greater than a specified threshold.
- ErrMaxLessEqualThanRequired = NewError("validation_max_less_equal_than_required", "must be no greater than {{.threshold}}")
- // ErrMinGreaterThanRequired is the error that returns when a value is less than or equal to a specified threshold.
- ErrMinGreaterThanRequired = NewError("validation_min_greater_than_required", "must be greater than {{.threshold}}")
- // ErrMaxLessThanRequired is the error that returns when a value is greater than or equal to a specified threshold.
- ErrMaxLessThanRequired = NewError("validation_max_less_than_required", "must be less than {{.threshold}}")
- )
- // ThresholdRule is a validation rule that checks if a value satisfies the specified threshold requirement.
- type ThresholdRule struct {
- threshold interface{}
- operator int
- err Error
- }
- const (
- greaterThan = iota
- greaterEqualThan
- lessThan
- lessEqualThan
- )
- // Min returns a validation rule that checks if a value is greater or equal than the specified value.
- // By calling Exclusive, the rule will check if the value is strictly greater than the specified value.
- // Note that the value being checked and the threshold value must be of the same type.
- // Only int, uint, float and time.Time types are supported.
- // An empty value is considered valid. Please use the Required rule to make sure a value is not empty.
- func Min(min interface{}) ThresholdRule {
- return ThresholdRule{
- threshold: min,
- operator: greaterEqualThan,
- err: ErrMinGreaterEqualThanRequired,
- }
- }
- // Max returns a validation rule that checks if a value is less or equal than the specified value.
- // By calling Exclusive, the rule will check if the value is strictly less than the specified value.
- // Note that the value being checked and the threshold value must be of the same type.
- // Only int, uint, float and time.Time types are supported.
- // An empty value is considered valid. Please use the Required rule to make sure a value is not empty.
- func Max(max interface{}) ThresholdRule {
- return ThresholdRule{
- threshold: max,
- operator: lessEqualThan,
- err: ErrMaxLessEqualThanRequired,
- }
- }
- // Exclusive sets the comparison to exclude the boundary value.
- func (r ThresholdRule) Exclusive() ThresholdRule {
- if r.operator == greaterEqualThan {
- r.operator = greaterThan
- r.err = ErrMinGreaterThanRequired
- } else if r.operator == lessEqualThan {
- r.operator = lessThan
- r.err = ErrMaxLessThanRequired
- }
- return r
- }
- // Validate checks if the given value is valid or not.
- func (r ThresholdRule) Validate(value interface{}) error {
- value, isNil := Indirect(value)
- if isNil || IsEmpty(value) {
- return nil
- }
- rv := reflect.ValueOf(r.threshold)
- switch rv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- v, err := ToInt(value)
- if err != nil {
- return err
- }
- if r.compareInt(rv.Int(), v) {
- return nil
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- v, err := ToUint(value)
- if err != nil {
- return err
- }
- if r.compareUint(rv.Uint(), v) {
- return nil
- }
- case reflect.Float32, reflect.Float64:
- v, err := ToFloat(value)
- if err != nil {
- return err
- }
- if r.compareFloat(rv.Float(), v) {
- return nil
- }
- case reflect.Struct:
- t, ok := r.threshold.(time.Time)
- if !ok {
- return fmt.Errorf("type not supported: %v", rv.Type())
- }
- v, ok := value.(time.Time)
- if !ok {
- return fmt.Errorf("cannot convert %v to time.Time", reflect.TypeOf(value))
- }
- if v.IsZero() || r.compareTime(t, v) {
- return nil
- }
- default:
- return fmt.Errorf("type not supported: %v", rv.Type())
- }
- return r.err.SetParams(map[string]interface{}{"threshold": r.threshold})
- }
- // Error sets the error message for the rule.
- func (r ThresholdRule) Error(message string) ThresholdRule {
- r.err = r.err.SetMessage(message)
- return r
- }
- // ErrorObject sets the error struct for the rule.
- func (r ThresholdRule) ErrorObject(err Error) ThresholdRule {
- r.err = err
- return r
- }
- func (r ThresholdRule) compareInt(threshold, value int64) bool {
- switch r.operator {
- case greaterThan:
- return value > threshold
- case greaterEqualThan:
- return value >= threshold
- case lessThan:
- return value < threshold
- default:
- return value <= threshold
- }
- }
- func (r ThresholdRule) compareUint(threshold, value uint64) bool {
- switch r.operator {
- case greaterThan:
- return value > threshold
- case greaterEqualThan:
- return value >= threshold
- case lessThan:
- return value < threshold
- default:
- return value <= threshold
- }
- }
- func (r ThresholdRule) compareFloat(threshold, value float64) bool {
- switch r.operator {
- case greaterThan:
- return value > threshold
- case greaterEqualThan:
- return value >= threshold
- case lessThan:
- return value < threshold
- default:
- return value <= threshold
- }
- }
- func (r ThresholdRule) compareTime(threshold, value time.Time) bool {
- switch r.operator {
- case greaterThan:
- return value.After(threshold)
- case greaterEqualThan:
- return value.After(threshold) || value.Equal(threshold)
- case lessThan:
- return value.Before(threshold)
- default:
- return value.Before(threshold) || value.Equal(threshold)
- }
- }
|