Browse Source

MySQL/Postgres/MSSQL: Add parsing for day, weeks and year intervals in macros (#13086)

closes #11431
Bernard Duggan 6 years ago
parent
commit
a0bb01103e

+ 28 - 0
pkg/components/gtime/gtime.go

@@ -0,0 +1,28 @@
+package gtime
+
+import (
+	"regexp"
+	"strconv"
+	"time"
+)
+
+// ParseInterval parses and interval with support for all units that Grafana uses.
+func ParseInterval(interval string) (time.Duration, error) {
+	re := regexp.MustCompile(`(\d+)([wdy])`)
+	result := re.FindSubmatch([]byte(interval))
+
+	if len(result) == 3 {
+		num, _ := strconv.Atoi(string(result[1]))
+		period := string(result[2])
+
+		if period == `d` {
+			return time.Hour * 24 * time.Duration(num), nil
+		} else if period == `w` {
+			return time.Hour * 24 * 7 * time.Duration(num), nil
+		} else {
+			return time.Hour * 24 * 7 * 365 * time.Duration(num), nil
+		}
+	} else {
+		return time.ParseDuration(interval)
+	}
+}

+ 34 - 0
pkg/components/gtime/gtime_test.go

@@ -0,0 +1,34 @@
+package gtime
+
+import (
+	"errors"
+	"fmt"
+	"testing"
+	"time"
+)
+
+func TestParseInterval(t *testing.T) {
+	tcs := []struct {
+		interval string
+		duration time.Duration
+		err      error
+	}{
+		{interval: "1d", duration: time.Hour * 24},
+		{interval: "1w", duration: time.Hour * 24 * 7},
+		{interval: "1y", duration: time.Hour * 24 * 7 * 365},
+		{interval: "1M", err: errors.New("time: unknown unit M in duration 1M")},
+		{interval: "invalid-duration", err: errors.New("time: invalid duration invalid-duration")},
+	}
+
+	for i, tc := range tcs {
+		t.Run(fmt.Sprintf("testcase %d", i), func(t *testing.T) {
+			res, err := ParseInterval(tc.interval)
+			if err != nil && err.Error() != tc.err.Error() {
+				t.Fatalf("expected '%v' got '%v'", tc.err, err)
+			}
+			if res != tc.duration {
+				t.Errorf("expected %v got %v", tc.duration, res)
+			}
+		})
+	}
+}

+ 3 - 2
pkg/tsdb/mssql/macros.go

@@ -6,6 +6,7 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/grafana/grafana/pkg/components/gtime"
 	"github.com/grafana/grafana/pkg/tsdb"
 	"github.com/grafana/grafana/pkg/tsdb"
 )
 )
 
 
@@ -74,7 +75,7 @@ func (m *msSqlMacroEngine) evaluateMacro(name string, args []string) (string, er
 		if len(args) < 2 {
 		if len(args) < 2 {
 			return "", fmt.Errorf("macro %v needs time column and interval", name)
 			return "", fmt.Errorf("macro %v needs time column and interval", name)
 		}
 		}
-		interval, err := time.ParseDuration(strings.Trim(args[1], `'"`))
+		interval, err := gtime.ParseInterval(strings.Trim(args[1], `'"`))
 		if err != nil {
 		if err != nil {
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 		}
 		}
@@ -109,7 +110,7 @@ func (m *msSqlMacroEngine) evaluateMacro(name string, args []string) (string, er
 		if len(args) < 2 {
 		if len(args) < 2 {
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 		}
 		}
-		interval, err := time.ParseDuration(strings.Trim(args[1], `'`))
+		interval, err := gtime.ParseInterval(strings.Trim(args[1], `'`))
 		if err != nil {
 		if err != nil {
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 		}
 		}

+ 3 - 3
pkg/tsdb/mysql/macros.go

@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"fmt"
 	"regexp"
 	"regexp"
 	"strings"
 	"strings"
-	"time"
 
 
+	"github.com/grafana/grafana/pkg/components/gtime"
 	"github.com/grafana/grafana/pkg/tsdb"
 	"github.com/grafana/grafana/pkg/tsdb"
 )
 )
 
 
@@ -69,7 +69,7 @@ func (m *mySqlMacroEngine) evaluateMacro(name string, args []string) (string, er
 		if len(args) < 2 {
 		if len(args) < 2 {
 			return "", fmt.Errorf("macro %v needs time column and interval", name)
 			return "", fmt.Errorf("macro %v needs time column and interval", name)
 		}
 		}
-		interval, err := time.ParseDuration(strings.Trim(args[1], `'"`))
+		interval, err := gtime.ParseInterval(strings.Trim(args[1], `'"`))
 		if err != nil {
 		if err != nil {
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 		}
 		}
@@ -104,7 +104,7 @@ func (m *mySqlMacroEngine) evaluateMacro(name string, args []string) (string, er
 		if len(args) < 2 {
 		if len(args) < 2 {
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 		}
 		}
-		interval, err := time.ParseDuration(strings.Trim(args[1], `'`))
+		interval, err := gtime.ParseInterval(strings.Trim(args[1], `'`))
 		if err != nil {
 		if err != nil {
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 		}
 		}

+ 3 - 2
pkg/tsdb/postgres/macros.go

@@ -6,6 +6,7 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/grafana/grafana/pkg/components/gtime"
 	"github.com/grafana/grafana/pkg/tsdb"
 	"github.com/grafana/grafana/pkg/tsdb"
 )
 )
 
 
@@ -95,7 +96,7 @@ func (m *postgresMacroEngine) evaluateMacro(name string, args []string) (string,
 		if len(args) < 2 {
 		if len(args) < 2 {
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 		}
 		}
-		interval, err := time.ParseDuration(strings.Trim(args[1], `'`))
+		interval, err := gtime.ParseInterval(strings.Trim(args[1], `'`))
 		if err != nil {
 		if err != nil {
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 		}
 		}
@@ -139,7 +140,7 @@ func (m *postgresMacroEngine) evaluateMacro(name string, args []string) (string,
 		if len(args) < 2 {
 		if len(args) < 2 {
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 			return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name)
 		}
 		}
-		interval, err := time.ParseDuration(strings.Trim(args[1], `'`))
+		interval, err := gtime.ParseInterval(strings.Trim(args[1], `'`))
 		if err != nil {
 		if err != nil {
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 			return "", fmt.Errorf("error parsing interval %v", args[1])
 		}
 		}