forked from ebhomengo/niki
178 lines
4.5 KiB
Go
178 lines
4.5 KiB
Go
|
// Copyright 2016 Qiang Xue. All rights reserved.
|
||
|
// Use of this source code is governed by a MIT-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package validation
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type ThresholdRule struct {
|
||
|
threshold interface{}
|
||
|
operator int
|
||
|
message string
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
greaterThan = iota
|
||
|
greaterEqualThan
|
||
|
lessThan
|
||
|
lessEqualThan
|
||
|
)
|
||
|
|
||
|
// Min is 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,
|
||
|
message: fmt.Sprintf("must be no less than %v", min),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Max is 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,
|
||
|
message: fmt.Sprintf("must be no greater than %v", max),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Exclusive sets the comparison to exclude the boundary value.
|
||
|
func (r *ThresholdRule) Exclusive() *ThresholdRule {
|
||
|
if r.operator == greaterEqualThan {
|
||
|
r.operator = greaterThan
|
||
|
r.message = fmt.Sprintf("must be greater than %v", r.threshold)
|
||
|
} else if r.operator == lessEqualThan {
|
||
|
r.operator = lessThan
|
||
|
r.message = fmt.Sprintf("must be less than %v", r.threshold)
|
||
|
}
|
||
|
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 errors.New(r.message)
|
||
|
}
|
||
|
|
||
|
// Error sets the error message for the rule.
|
||
|
func (r *ThresholdRule) Error(message string) *ThresholdRule {
|
||
|
r.message = message
|
||
|
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)
|
||
|
}
|
||
|
}
|