forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/go-ozzo/ozzo-validation/util.go

288 lines
4.8 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
// Copyright 2016 Qiang Xue. All rights reserved.
2024-02-18 10:42:21 +00:00
// Use of this source code is governed by a MIT-style
2024-02-18 10:42:21 +00:00
// license that can be found in the LICENSE file.
package validation
import (
"database/sql/driver"
"errors"
"fmt"
"reflect"
"time"
)
var (
bytesType = reflect.TypeOf([]byte(nil))
2024-02-18 10:42:21 +00:00
valuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
)
// EnsureString ensures the given value is a string.
2024-02-18 10:42:21 +00:00
// If the value is a byte slice, it will be typecast into a string.
2024-02-18 10:42:21 +00:00
// An error is returned otherwise.
2024-02-18 10:42:21 +00:00
func EnsureString(value interface{}) (string, error) {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
if v.Kind() == reflect.String {
2024-02-18 10:42:21 +00:00
return v.String(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if v.Type() == bytesType {
2024-02-18 10:42:21 +00:00
return string(v.Interface().([]byte)), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return "", errors.New("must be either a string or byte slice")
2024-02-18 10:42:21 +00:00
}
// StringOrBytes typecasts a value into a string or byte slice.
2024-02-18 10:42:21 +00:00
// Boolean flags are returned to indicate if the typecasting succeeds or not.
2024-02-18 10:42:21 +00:00
func StringOrBytes(value interface{}) (isString bool, str string, isBytes bool, bs []byte) {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
if v.Kind() == reflect.String {
2024-02-18 10:42:21 +00:00
str = v.String()
2024-02-18 10:42:21 +00:00
isString = true
2024-02-18 10:42:21 +00:00
} else if v.Kind() == reflect.Slice && v.Type() == bytesType {
2024-02-18 10:42:21 +00:00
bs = v.Interface().([]byte)
2024-02-18 10:42:21 +00:00
isBytes = true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
}
// LengthOfValue returns the length of a value that is a string, slice, map, or array.
2024-02-18 10:42:21 +00:00
// An error is returned for all other types.
2024-02-18 10:42:21 +00:00
func LengthOfValue(value interface{}) (int, error) {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
switch v.Kind() {
2024-02-18 10:42:21 +00:00
case reflect.String, reflect.Slice, reflect.Map, reflect.Array:
2024-02-18 10:42:21 +00:00
return v.Len(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("cannot get the length of %v", v.Kind())
2024-02-18 10:42:21 +00:00
}
// ToInt converts the given value to an int64.
2024-02-18 10:42:21 +00:00
// An error is returned for all incompatible types.
2024-02-18 10:42:21 +00:00
func ToInt(value interface{}) (int64, error) {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
switch v.Kind() {
2024-02-18 10:42:21 +00:00
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2024-02-18 10:42:21 +00:00
return v.Int(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("cannot convert %v to int64", v.Kind())
2024-02-18 10:42:21 +00:00
}
// ToUint converts the given value to an uint64.
2024-02-18 10:42:21 +00:00
// An error is returned for all incompatible types.
2024-02-18 10:42:21 +00:00
func ToUint(value interface{}) (uint64, error) {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
switch v.Kind() {
2024-02-18 10:42:21 +00:00
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2024-02-18 10:42:21 +00:00
return v.Uint(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("cannot convert %v to uint64", v.Kind())
2024-02-18 10:42:21 +00:00
}
// ToFloat converts the given value to a float64.
2024-02-18 10:42:21 +00:00
// An error is returned for all incompatible types.
2024-02-18 10:42:21 +00:00
func ToFloat(value interface{}) (float64, error) {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
switch v.Kind() {
2024-02-18 10:42:21 +00:00
case reflect.Float32, reflect.Float64:
2024-02-18 10:42:21 +00:00
return v.Float(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("cannot convert %v to float64", v.Kind())
2024-02-18 10:42:21 +00:00
}
// IsEmpty checks if a value is empty or not.
2024-02-18 10:42:21 +00:00
// A value is considered empty if
2024-02-18 10:42:21 +00:00
// - integer, float: zero
2024-02-18 10:42:21 +00:00
// - bool: false
2024-02-18 10:42:21 +00:00
// - string, array: len() == 0
2024-02-18 10:42:21 +00:00
// - slice, map: nil or len() == 0
2024-02-18 10:42:21 +00:00
// - interface, pointer: nil or the referenced value is empty
2024-02-18 10:42:21 +00:00
func IsEmpty(value interface{}) bool {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
switch v.Kind() {
2024-02-18 10:42:21 +00:00
case reflect.String, reflect.Array, reflect.Map, reflect.Slice:
2024-02-18 10:42:21 +00:00
return v.Len() == 0
2024-02-18 10:42:21 +00:00
case reflect.Bool:
2024-02-18 10:42:21 +00:00
return !v.Bool()
2024-02-18 10:42:21 +00:00
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2024-02-18 10:42:21 +00:00
return v.Int() == 0
2024-02-18 10:42:21 +00:00
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2024-02-18 10:42:21 +00:00
return v.Uint() == 0
2024-02-18 10:42:21 +00:00
case reflect.Float32, reflect.Float64:
2024-02-18 10:42:21 +00:00
return v.Float() == 0
2024-02-18 10:42:21 +00:00
case reflect.Invalid:
2024-02-18 10:42:21 +00:00
return true
2024-02-18 10:42:21 +00:00
case reflect.Interface, reflect.Ptr:
2024-02-18 10:42:21 +00:00
if v.IsNil() {
2024-02-18 10:42:21 +00:00
return true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return IsEmpty(v.Elem().Interface())
2024-02-18 10:42:21 +00:00
case reflect.Struct:
2024-02-18 10:42:21 +00:00
v, ok := value.(time.Time)
2024-02-18 10:42:21 +00:00
if ok && v.IsZero() {
2024-02-18 10:42:21 +00:00
return true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return false
2024-02-18 10:42:21 +00:00
}
// Indirect returns the value that the given interface or pointer references to.
2024-02-18 10:42:21 +00:00
// If the value implements driver.Valuer, it will deal with the value returned by
2024-02-18 10:42:21 +00:00
// the Value() method instead. A boolean value is also returned to indicate if
2024-02-18 10:42:21 +00:00
// the value is nil or not (only applicable to interface, pointer, map, and slice).
2024-02-18 10:42:21 +00:00
// If the value is neither an interface nor a pointer, it will be returned back.
2024-02-18 10:42:21 +00:00
func Indirect(value interface{}) (interface{}, bool) {
2024-02-18 10:42:21 +00:00
rv := reflect.ValueOf(value)
2024-02-18 10:42:21 +00:00
kind := rv.Kind()
2024-02-18 10:42:21 +00:00
switch kind {
2024-02-18 10:42:21 +00:00
case reflect.Invalid:
2024-02-18 10:42:21 +00:00
return nil, true
2024-02-18 10:42:21 +00:00
case reflect.Ptr, reflect.Interface:
2024-02-18 10:42:21 +00:00
if rv.IsNil() {
2024-02-18 10:42:21 +00:00
return nil, true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return Indirect(rv.Elem().Interface())
2024-02-18 10:42:21 +00:00
case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan:
2024-02-18 10:42:21 +00:00
if rv.IsNil() {
2024-02-18 10:42:21 +00:00
return nil, true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if rv.Type().Implements(valuerType) {
2024-02-18 10:42:21 +00:00
return indirectValuer(value.(driver.Valuer))
2024-02-18 10:42:21 +00:00
}
return value, false
2024-02-18 10:42:21 +00:00
}
func indirectValuer(valuer driver.Valuer) (interface{}, bool) {
2024-02-18 10:42:21 +00:00
if value, err := valuer.Value(); value != nil && err == nil {
2024-02-18 10:42:21 +00:00
return Indirect(value)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil, true
2024-02-18 10:42:21 +00:00
}