go-playground / validator

:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
MIT License
16.41k stars 1.31k forks source link

oneof support float #1105

Open LjtGentle opened 1 year ago

LjtGentle commented 1 year ago

Package version eg. v10:

Issue, Question or Enhancement:

json.Unmarshal value is map[string]interface number will be float64, so i want oneof can support float whitout fractional

Code sample, to showcase or reproduce:

func isOneOf(fl FieldLevel) bool {
    vals := parseOneOfParam2(fl.Param())

    field := fl.Field()

    var v string
    switch field.Kind() {
    case reflect.String:
        v = field.String()
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        v = strconv.FormatInt(field.Int(), 10)
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
        v = strconv.FormatUint(field.Uint(), 10)
    case reflect.Float32, reflect.Float64:
        v = decimal2String(field.Float())

    default:
        panic(fmt.Sprintf("Bad field type %T", field.Interface()))
    }
    for i := 0; i < len(vals); i++ {
        if vals[i] == v {
            return true
        }
    }
    return false
}
func decimal2String(f float64) string {
    _, frac := math.Modf(f)
    if frac != 0 {
        panic(fmt.Sprintf("The float %v has a fractional part of %v.\n", f, frac))
    }
    return strconv.FormatFloat(f, 'f', 0, 64)
}
alirezakazemeini commented 1 year ago

It seems like you are having a problem with the validation function that checks if a field value is one of the specified values. It handles various data types including strings, integers, and floats. However, it seems like you're having an issue with floats containing fractional parts.

To modify the code and make it support float values without fractions, you can update the decimal2String function to round the float value instead of throwing a panic when there is a fractional part. Here's an updated version of the function:

func decimal2String(f float64) string {
    rounded := math.Round(f)
    return strconv.FormatFloat(rounded, 'f', 0, 64)
}

or you can use it inline like:

v = strconv.FormatFloat(math.Round(field.Float()), 'f', 0, 64)

By using the math.Round function, the float value will be rounded to the nearest integer. This way, when converting the float to a string, you'll have the desired behavior of supporting float values without fractional parts.

I also added this functionality and requested a merge.