From 3cb0bc3da1216fd76b22c16e00b4b02d54b1a3a9 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Tue, 20 Mar 2018 19:40:10 +0100 Subject: [PATCH] sql datasource: extract common logic for converting time column to epoch time in ms --- pkg/tsdb/sql_engine.go | 28 ++++++++++++++++++++++ pkg/tsdb/sql_engine_test.go | 46 +++++++++++++++++++++++++++++++++++++ pkg/tsdb/time_range.go | 10 ++++++++ 3 files changed, 84 insertions(+) create mode 100644 pkg/tsdb/sql_engine_test.go diff --git a/pkg/tsdb/sql_engine.go b/pkg/tsdb/sql_engine.go index 7ea0682235f..16370a4ea7f 100644 --- a/pkg/tsdb/sql_engine.go +++ b/pkg/tsdb/sql_engine.go @@ -3,6 +3,7 @@ package tsdb import ( "context" "sync" + "time" "github.com/go-xorm/core" "github.com/go-xorm/xorm" @@ -133,3 +134,30 @@ func (e *DefaultSqlEngine) Query( return result, nil } + +// ConvertTimeColumnToEpochMs converts column named time to unix timestamp in milliseconds +// to make native datetime types and epoch dates work in annotation and table queries. +func ConvertSqlTimeColumnToEpochMs(values RowValues, timeIndex int) { + if timeIndex >= 0 { + switch value := values[timeIndex].(type) { + case time.Time: + values[timeIndex] = EpochPrecisionToMs(float64(value.Unix())) + case *time.Time: + if value != nil { + values[timeIndex] = EpochPrecisionToMs(float64((*value).Unix())) + } + case int64: + values[timeIndex] = int64(EpochPrecisionToMs(float64(value))) + case *int64: + if value != nil { + values[timeIndex] = int64(EpochPrecisionToMs(float64(*value))) + } + case float64: + values[timeIndex] = EpochPrecisionToMs(value) + case *float64: + if value != nil { + values[timeIndex] = EpochPrecisionToMs(*value) + } + } + } +} diff --git a/pkg/tsdb/sql_engine_test.go b/pkg/tsdb/sql_engine_test.go new file mode 100644 index 00000000000..48aac2c4d45 --- /dev/null +++ b/pkg/tsdb/sql_engine_test.go @@ -0,0 +1,46 @@ +package tsdb + +import ( + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestSqlEngine(t *testing.T) { + Convey("SqlEngine", t, func() { + Convey("Given row values with time columns when converting them", func() { + dt := time.Date(2018, 3, 14, 21, 20, 6, 527e6, time.UTC) + fixtures := make([]interface{}, 8) + fixtures[0] = dt + fixtures[1] = dt.Unix() * 1000 + fixtures[2] = dt.Unix() + fixtures[3] = float64(dt.Unix() * 1000) + fixtures[4] = float64(dt.Unix()) + + var nilDt *time.Time + var nilInt64 *int64 + var nilFloat64 *float64 + fixtures[5] = nilDt + fixtures[6] = nilInt64 + fixtures[7] = nilFloat64 + + for i := range fixtures { + ConvertSqlTimeColumnToEpochMs(fixtures, i) + } + + Convey("Should convert sql time columns to epoch time in ms ", func() { + expected := float64(dt.Unix() * 1000) + So(fixtures[0].(float64), ShouldEqual, expected) + So(fixtures[1].(int64), ShouldEqual, expected) + So(fixtures[2].(int64), ShouldEqual, expected) + So(fixtures[3].(float64), ShouldEqual, expected) + So(fixtures[4].(float64), ShouldEqual, expected) + + So(fixtures[5], ShouldBeNil) + So(fixtures[6], ShouldBeNil) + So(fixtures[7], ShouldBeNil) + }) + }) + }) +} diff --git a/pkg/tsdb/time_range.go b/pkg/tsdb/time_range.go index fd797bf731a..fd0cb3f8e82 100644 --- a/pkg/tsdb/time_range.go +++ b/pkg/tsdb/time_range.go @@ -88,3 +88,13 @@ func (tr *TimeRange) ParseTo() (time.Time, error) { return time.Time{}, fmt.Errorf("cannot parse to value %s", tr.To) } + +// EpochPrecisionToMs converts epoch precision to millisecond, if needed. +// Only seconds to milliseconds supported right now +func EpochPrecisionToMs(value float64) float64 { + if int64(value)/1e10 == 0 { + return float64(value * 1e3) + } + + return float64(value) +}