diff --git a/pkg/schema/field/number.go b/pkg/schema/field/number.go index b954294901f5cbd7201d6c76c5f8c563e6cfccff..0236fbb68acceb5f297c6a03332c771dd773a8b6 100644 --- a/pkg/schema/field/number.go +++ b/pkg/schema/field/number.go @@ -2,9 +2,9 @@ package field import ( "context" + "encoding/json" "math" "reflect" - "strconv" "github.com/pkg/errors" ) @@ -52,34 +52,25 @@ func toNumberReflect(i interface{}) (interface{}, error) { return v.Uint(), nil case reflect.Float32, reflect.Float64: return v.Float(), nil - case reflect.String: - return parseNumberFromString(v.String()) default: return 0, errors.Errorf("error convert \"%s\" to number", i) } } -func parseNumberFromString(str string) (interface{}, error) { - if str == "" { - return nil, errors.New("cannot convert empty string to number") - } - - // Сначала пробуем парсить как целое число - intVal, err := strconv.ParseInt(str, 10, 64) - if err == nil { - return intVal, nil - } - - // Если не получилось, пробуем как дробное число - floatVal, err := strconv.ParseFloat(str, 64) - if err == nil { - return floatVal, nil - } - return nil, err -} - func ToNumber(i interface{}) (interface{}, error) { switch v := i.(type) { + case json.Number: + // Сначала пробуем парсить как целое число + intVal, err := v.Int64() + if err == nil { + return intVal, nil + } + // Если не получилось, пробуем как дробное число + floatVal, err := v.Float64() + if err == nil { + return floatVal, nil + } + return nil, err case int64: return v, nil case int: diff --git a/pkg/schema/field/number_test.go b/pkg/schema/field/number_test.go index 2d9f98ff47da22e83966ab86b54040d8d3460536..a95215e6e00bbe0f4960d1499f0c7da6405a6ee1 100644 --- a/pkg/schema/field/number_test.go +++ b/pkg/schema/field/number_test.go @@ -42,8 +42,7 @@ func TestNumberField_Decode(t *testing.T) { {"Correct", Number("float"), int64(2), 2.0, false}, // #18 {"Correct", Number("float"), json.Number("2"), 2.0, false}, // #19 {"Correct", Number("int"), json.Number("2"), int64(2), false}, // #20 - {"Correct", Number("int"), "2", int64(2), false}, // #21 - {"Correct", Number("float"), "2.0", 2.0, false}, // #22 + {"Correct", Number("float"), json.Number("2.2"), 2.2, false}, // #21 {"Wrong data", Number("int"), "", nil, true}, // #0 {"Wrong data", Number("int"), []byte(""), nil, true}, // #1 diff --git a/pkg/schema/field/timestamp.go b/pkg/schema/field/timestamp.go index 4338cd4b5932acf019c32ba6de699fb2c5217068..f79a29121a28745c2d4e64cca63e746d5402a916 100644 --- a/pkg/schema/field/timestamp.go +++ b/pkg/schema/field/timestamp.go @@ -2,8 +2,8 @@ package field import ( "context" + "encoding/json" "fmt" - "reflect" "time" ) @@ -58,30 +58,34 @@ func toTimestamp(i interface{}) (interface{}, error) { case float64: return int64(v), nil default: - if reflect.ValueOf(v).Kind() == reflect.String { - return timestampFromString(reflect.ValueOf(v).String()) - } return nil, fmt.Errorf("unsupported value type: \"%T\"", i) } } -func timestampFromString(v string) (interface{}, error) { - duration, err := time.ParseDuration(v) - if err == nil { - return duration.Nanoseconds(), nil - } - t, err := time.Parse(time.TimeOnly, v) - - if err == nil { - return t.AddDate(1, 0, 0).Sub(zeroTime).Nanoseconds(), nil - } - return parseNumberFromString(v) -} - func (TimestampType) Decode(_ context.Context, _ *Field, v interface{}) (interface{}, error) { switch i := v.(type) { case string: - return timestampFromString(i) + duration, err := time.ParseDuration(i) + if err == nil { + return duration.Nanoseconds(), nil + } + t, err := time.Parse(time.TimeOnly, i) + if err == nil { + return t.AddDate(1, 0, 0).Sub(zeroTime).Nanoseconds(), nil + } + return nil, err + case json.Number: + // Пробуем парсить json.Number как int64 + intVal, err := i.Int64() + if err == nil { + return intVal, nil + } + // Если не получилось, пробуем как float64 и приводим к int64 + floatVal, err := i.Float64() + if err == nil { + return int64(floatVal), nil + } + return nil, err default: return toTimestamp(i) } diff --git a/pkg/schema/field/timestamp_test.go b/pkg/schema/field/timestamp_test.go index f172a7fa76cf8cc195190e6dcb9e62473647724c..52f30a9eb1c3b6f665bd23ba7ee8316c0f2e5faa 100644 --- a/pkg/schema/field/timestamp_test.go +++ b/pkg/schema/field/timestamp_test.go @@ -33,7 +33,7 @@ func TestTimestamp_Decode(t *testing.T) { {"Correct", Timestamp(), nil, nil, false, ""}, // #12 {"Correct", Timestamp(), 2.0, int64(2), false, ""}, // #13 {"Correct", Timestamp(), json.Number("24"), int64(24), false, ""}, // #14 - {"Correct", Timestamp(), "24", int64(24), false, ""}, // #15 + {"Correct", Timestamp(), json.Number("2.4"), int64(2), false, ""}, // #15 { "Wrong data", @@ -41,7 +41,7 @@ func TestTimestamp_Decode(t *testing.T) { "", nil, true, - "decode error: cannot convert empty string to number", + "decode error: parsing time \"\" as \"15:04:05\": cannot parse \"\" as \"15\"", }, // #0 { "Wrong data", @@ -57,7 +57,7 @@ func TestTimestamp_Decode(t *testing.T) { "13:10", nil, true, - "decode error: strconv.ParseFloat: parsing \"13:10\": invalid syntax", + "decode error: parsing time \"13:10\" as \"15:04:05\": cannot parse \"\" as \":\"", }, // #2 { "Wrong data", @@ -65,7 +65,7 @@ func TestTimestamp_Decode(t *testing.T) { "24:00:00", nil, true, - "decode error: strconv.ParseFloat: parsing \"24:00:00\": invalid syntax", + "decode error: parsing time \"24:00:00\": hour out of range", }, // #3 } @@ -97,7 +97,7 @@ func TestTimestamp_Encode(t *testing.T) { {"Correct", Timestamp(), uint64(2), int64(2), false, ""}, // #2 {"Correct", Timestamp(), 2.0, int64(2), false, ""}, // #3 - {"Wrong data", Timestamp(), "", nil, true, "encode error: cannot convert empty string to number"}, // #0 + {"Wrong data", Timestamp(), "", nil, true, "encode error: unsupported value type: \"string\""}, // #0 {"Wrong data", Timestamp(), []byte(""), nil, true, "encode error: unsupported value type: \"[]uint8\""}, // #1 }