grafana / timestream-datasource

Amazon Timestream in Grafana
https://grafana.com/grafana/plugins/grafana-timestream-datasource
Apache License 2.0
24 stars 19 forks source link

macro suggestion : 'now' #49

Closed squalou closed 3 years ago

squalou commented 3 years ago

Hi,

Timestream DB does not provide 'now' function or equivalent. A macro would be useful.

I've just quickly built a hack from sources providing $__now_ms macro, which is the current time in milliseconds.

I don"t know how to contribute to the project. There are barely 10 lines of code I could post them here, or submit a PR.

squalou commented 3 years ago

for the records, 12 interesting lines, and a few more for a somewhat dummy unit test. Diff against commit 7da9b30

diff --git a/pkg/timestream/macros.go b/pkg/timestream/macros.go
index 305dac1..27c032e 100644
--- a/pkg/timestream/macros.go
+++ b/pkg/timestream/macros.go
@@ -4,12 +4,14 @@ import (
    "fmt"
    "regexp"
    "strings"
+   "time"

    "github.com/grafana/timestream-datasource/pkg/models"
 )

 const timeFilter = `\$__timeFilter`
 const intervalStr = `$__interval_ms`
+const nowStr = `$__now_ms`

 // WHERE time > from_unixtime(unixtime)
 // WHERE time > from_iso8601_timestamp(iso_8601_string_format)
@@ -51,6 +53,12 @@ func Interpolate(query models.QueryModel, settings models.DatasourceSettings) (s
        txt = strings.ReplaceAll(txt, intervalStr, replacement)
    }

+   if strings.Contains(txt, nowStr) {
+       now := int(time.Now().UnixNano() / int64(time.Millisecond))
+       replacement := fmt.Sprintf("%d", now)
+       txt = strings.ReplaceAll(txt, nowStr, replacement)
+   }
+
    return txt, err
 }

diff --git a/pkg/timestream/macros_test.go b/pkg/timestream/macros_test.go
index 7582e2b..c20469d 100644
--- a/pkg/timestream/macros_test.go
+++ b/pkg/timestream/macros_test.go
@@ -1,6 +1,7 @@
 package timestream

 import (
+   "fmt"
    "testing"
    "time"

@@ -67,4 +68,29 @@ func TestInterpolate(t *testing.T) {
            t.Fatalf("Result mismatch (-want +got):\n%s", diff)
        }
    })
+
+   t.Run("using now", func(t *testing.T) {
+       sqltxt := `$__now_ms`
+       query := models.QueryModel{
+           RawQuery: sqltxt,
+       }
+       text, _ := Interpolate(query, models.DatasourceSettings{})
+       expect := int(time.Now().UnixNano() / int64(time.Millisecond))
+
+       precision := 10
+       opt := cmp.Comparer(func(x, y int) bool {
+           return x-y <= precision || y-x < precision
+       })
+
+       var numtext int
+       _, e := fmt.Sscan(text, &numtext)
+
+       if e != nil {
+           t.Fatalf(e.Error())
+       }
+
+       if !cmp.Equal(numtext, expect, opt) {
+           t.Fatalf("Result above tolerated precision %d : %d, %d", precision, numtext, expect)
+       }
+   })
 }
diff --git a/src/SchemaInfo.ts b/src/SchemaInfo.ts
index e196c9d..6462abc 100644
--- a/src/SchemaInfo.ts
+++ b/src/SchemaInfo.ts
@@ -77,6 +77,11 @@ export class SchemaInfo {
         kind: CodeEditorSuggestionItemKind.Method,
         detail: '(Macro)',
       },
+      {
+        label: '$__now_ms',
+        kind: CodeEditorSuggestionItemKind.Method,
+        detail: '(Macro)',
+      },
       {
         label: '$__database',
         kind: CodeEditorSuggestionItemKind.Method,
ryantxu commented 3 years ago

go ahead and submit a pull request and we can incorporate this

squalou commented 3 years ago

EDIT : Pull Request submitted.

(bad habbits from other scm : I forgot to fork then submit PR :-)

araddas commented 3 years ago

@squalou it is undocumented, but you can use now() in your timestream queries.

squalou commented 3 years ago

good to know, will try. (a colleague told me he tried without success, will try again)

ryantxu commented 3 years ago

__now_ms was added in v1.2.0