Skip to content

Commit

Permalink
convert string dates to time
Browse files Browse the repository at this point in the history
  • Loading branch information
scottlepp committed Sep 26, 2024
1 parent 7c8f8ea commit 757a1ba
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
59 changes: 59 additions & 0 deletions duck/data/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package data
import (
"time"

"github.com/araddon/dateparse"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana-plugin-sdk-go/data/framestruct"
)
Expand Down Expand Up @@ -50,3 +51,61 @@ func parseDate(s string) (time.Time, error) {
}
return t.UTC(), nil
}

func ConvertDateFields(results []map[string]any) {
dateFields := findDateFields(results)
for row, result := range results {
for key, value := range result {
isDateField := dateFields[key]
if isDateField != nil && *isDateField {
if s, ok := value.(string); ok {
dateValue := isDate(s)
results[row][key] = dateValue
}
}
}
}
}

func findDateFields(results []map[string]any) map[string]*bool {
dateFields := make(map[string]*bool)
for _, result := range results {
if len(dateFields) == len(result) {
break
}
for key, value := range result {
if value == nil {
continue
}

isDateField := dateFields[key]
if isDateField != nil {
continue
}

if s, ok := value.(string); ok {
if s == "" {
continue
}

dateValue := isDate(s)
flag := true
flagPtr := &flag
if dateValue != nil {
dateFields[key] = flagPtr
} else {
*flagPtr = false
}
}
}
}
return dateFields
}

func isDate(s string) *time.Time {
val, err := dateparse.ParseStrict(s)
if err != nil {
return nil
}
return &val
}
3 changes: 3 additions & 0 deletions duck/duckdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ func resultsToFrame(name string, res string, f *sdk.Frame, frames []*sdk.Frame)
logger.Error("error unmarshalling results", "error", err)
return err
}

data.ConvertDateFields(results)

converters := data.Converters(frames)
resultsFrame, err := framestruct.ToDataFrame(name, results, converters...)

Expand Down
31 changes: 31 additions & 0 deletions duck/duckdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,37 @@ func TestLabelsMultiFrame(t *testing.T) {
assert.Contains(t, txt, "B")
}

func TestTimeSeriesAggregate(t *testing.T) {
db := NewInMemoryDB()

tt := "2024-02-23 09:01:54"
dd, err := dateparse.ParseAny(tt)
assert.Nil(t, err)

var values = []time.Time{dd, dd, dd}
timeField := data.NewField("time", nil, values)
valueField := data.NewField("value", nil, []*float64{new(float64), new(float64), new(float64)})
categoryField := data.NewField("category", nil, []string{"a", "a", "b"})

frame := data.NewFrame("foo", timeField, valueField, categoryField)
frame.RefID = "foo"

frames := []*data.Frame{frame}

model := &data.Frame{}
err = db.QueryFramesInto("foo", "select CURRENT_TIMESTAMP, min(time) as t, 1 as j from foo group by category", frames, model)
assert.Nil(t, err)

assert.Equal(t, data.FrameTypeTimeSeriesWide, model.Meta.Type)

assert.Equal(t, 2, model.Rows())
txt, err := model.StringTable(-1, -1)
assert.Nil(t, err)

fmt.Printf("GOT: %s", txt)
assert.Contains(t, txt, "Type: []*time.Time")
}

// TODO - don't think this is valid to have a frame with duplicate fields
// func TestWideFrameWithDuplicateFields(t *testing.T) {
// db := NewInMemoryDB()
Expand Down

0 comments on commit 757a1ba

Please sign in to comment.