diff --git a/minmax.go b/minmax.go index 75a34d2..336b0cf 100644 --- a/minmax.go +++ b/minmax.go @@ -5,6 +5,7 @@ package validation import ( + "encoding/json" "fmt" "reflect" "time" @@ -82,6 +83,47 @@ func (r ThresholdRule) Validate(value any) error { return nil } + if jsonNumber, ok := value.(json.Number); ok { + switch r.threshold.(type) { + case int, int8, int16, int32, int64: + // If our comparing number is an integer, then parse the json number as an + // integer. + i, err := jsonNumber.Int64() + if err != nil { + return err + } + value = i + case uint, uint8, uint16, uint32, uint64: + // If our comparing number is an unsigned integer, then parse the json + // number as an integer and cast it. + i, err := jsonNumber.Int64() + if err != nil { + return err + } + value = uint64(i) + case float32, float64: + // If our comparing value is a float, then parse the json number as a + // float. + f, err := jsonNumber.Float64() + if err != nil { + return err + } + value = f + case time.Time: + // If the value we have is a json number but we are comparing it to a time + // object. Then assume it is a unix timestamp as a number. + i, err := jsonNumber.Int64() + if err != nil { + return err + } + value = time.Unix(i, 0) + } + + if IsEmpty(value) { + return nil + } + } + rv := reflect.ValueOf(r.threshold) switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: diff --git a/minmax_test.go b/minmax_test.go index aadb07e..a09267e 100644 --- a/minmax_test.go +++ b/minmax_test.go @@ -5,6 +5,7 @@ package validation import ( + "encoding/json" "testing" "time" @@ -19,9 +20,9 @@ func TestMin(t *testing.T) { tests := []struct { tag string - threshold interface{} + threshold any exclusive bool - value interface{} + value any err string }{ // int cases @@ -55,6 +56,21 @@ func TestMin(t *testing.T) { {"t4.6", date20000601, true, 1, "cannot convert int to time.Time"}, {"t4.7", struct{}{}, false, 1, "type not supported: struct {}"}, {"t4.8", date0, false, date20000601, ""}, + // Json number cases + {"t5.1", 1, false, json.Number("1"), ""}, + {"t5.2", 1, false, json.Number("2"), ""}, + {"t5.3", 1, false, json.Number("-1"), "must be no less than 1"}, + // This is so fucking stupid, 0 is considered "empty?" so even though 0 is + // less than 1, this is considered okay? + {"t5.4", float64(1), false, json.Number("0"), ""}, + {"t5.5", float64(1), true, json.Number("1"), "must be greater than 1"}, + {"t5.6", float64(1), false, json.Number("1"), ""}, + {"t5.7", float64(1), false, json.Number("2"), ""}, + {"t5.8", float64(1), false, json.Number("-1"), "must be no less than 1"}, + // This is so fucking stupid, 0 is considered "empty?" so even though 0 is + // less than 1, this is considered okay? + {"t5.9", float64(1), false, json.Number("0"), ""}, + {"t5.10", float64(1), true, json.Number("1"), "must be greater than 1"}, } for _, test := range tests { @@ -117,6 +133,13 @@ func TestMax(t *testing.T) { {"t4.4", date20000601, false, date0, ""}, {"t4.5", date20000601, true, date20000601, "must be less than 2000-06-01 00:00:00 +0000 UTC"}, {"t4.6", date20000601, true, 1, "cannot convert int to time.Time"}, + {"t5.1", 2, false, json.Number("2"), ""}, + {"t5.2", 2, false, json.Number("1"), ""}, + {"t5.3", 2, false, json.Number("3"), "must be no greater than 2"}, + // This is so fucking stupid, 0 is considered "empty?" so even though 0 is + // less than 1, this is considered okay? + {"t5.4", 2, false, json.Number("0"), ""}, + {"t5.5", 2, true, json.Number("2"), "must be less than 2"}, } for _, test := range tests {