Browse Source

sql datasource: extract common logic for converting time column to epoch time in ms

Marcus Efraimsson 7 years ago
parent
commit
3cb0bc3da1
3 changed files with 84 additions and 0 deletions
  1. 28 0
      pkg/tsdb/sql_engine.go
  2. 46 0
      pkg/tsdb/sql_engine_test.go
  3. 10 0
      pkg/tsdb/time_range.go

+ 28 - 0
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)
+			}
+		}
+	}
+}

+ 46 - 0
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)
+			})
+		})
+	})
+}

+ 10 - 0
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)
+}