|
|
|
@ -1,6 +1,9 @@ |
|
|
|
|
package tsdb |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"encoding/json" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/data" |
|
|
|
|
"github.com/grafana/grafana/pkg/components/null" |
|
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson" |
|
|
|
|
"github.com/grafana/grafana/pkg/models" |
|
|
|
@ -36,7 +39,7 @@ type QueryResult struct { |
|
|
|
|
Meta *simplejson.Json `json:"meta,omitempty"` |
|
|
|
|
Series TimeSeriesSlice `json:"series"` |
|
|
|
|
Tables []*Table `json:"tables"` |
|
|
|
|
Dataframes [][]byte `json:"dataframes"` |
|
|
|
|
Dataframes DataFrames `json:"dataframes"` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type TimeSeries struct { |
|
|
|
@ -85,3 +88,80 @@ func NewTimeSeries(name string, points TimeSeriesPoints) *TimeSeries { |
|
|
|
|
Points: points, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// DataFrames interface for retrieving encoded and decoded data frames.
|
|
|
|
|
//
|
|
|
|
|
// See NewDecodedDataFrames and NewEncodedDataFrames for more information.
|
|
|
|
|
type DataFrames interface { |
|
|
|
|
// Encoded encodes Frames into a slice of []byte.
|
|
|
|
|
// If an error occurs [][]byte will be nil.
|
|
|
|
|
// The encoded result, if any, will be cached and returned next time Encoded is called.
|
|
|
|
|
Encoded() ([][]byte, error) |
|
|
|
|
|
|
|
|
|
// Decoded decodes a slice of Arrow encoded frames to data.Frames ([]*data.Frame).
|
|
|
|
|
// If an error occurs Frames will be nil.
|
|
|
|
|
// The decoded result, if any, will be cached and returned next time Decoded is called.
|
|
|
|
|
Decoded() (data.Frames, error) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type dataFrames struct { |
|
|
|
|
decoded data.Frames |
|
|
|
|
encoded [][]byte |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewDecodedDataFrames create new DataFrames from decoded frames.
|
|
|
|
|
//
|
|
|
|
|
// This should be the primary function for creating DataFrames if your implementing a plugin.
|
|
|
|
|
// In Grafana alerting scenario it needs to operate on decoded frames why this function is
|
|
|
|
|
// preferrable. When encoded data frames is needed, e.g. returned from Grafana HTTP API, it will
|
|
|
|
|
// happen automatically when MarshalJSON() is called.
|
|
|
|
|
func NewDecodedDataFrames(decodedFrames data.Frames) DataFrames { |
|
|
|
|
return &dataFrames{ |
|
|
|
|
decoded: decodedFrames, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewEncodedDataFrames create new DataFrames from encoded frames.
|
|
|
|
|
//
|
|
|
|
|
// This one is primarily used for creating DataFrames when receiving encoded data frames from an external
|
|
|
|
|
// plugin or similar. This may allow the encoded data frames to be returned to Grafana UI without any additional
|
|
|
|
|
// decoding/encoding required. In Grafana alerting scenario it needs to operate on decoded data frames why encoded
|
|
|
|
|
// frames needs to be decoded before usage.
|
|
|
|
|
func NewEncodedDataFrames(encodedFrames [][]byte) DataFrames { |
|
|
|
|
return &dataFrames{ |
|
|
|
|
encoded: encodedFrames, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (df *dataFrames) Encoded() ([][]byte, error) { |
|
|
|
|
if df.encoded == nil { |
|
|
|
|
encoded, err := df.decoded.MarshalArrow() |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
df.encoded = encoded |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return df.encoded, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (df *dataFrames) Decoded() (data.Frames, error) { |
|
|
|
|
if df.decoded == nil { |
|
|
|
|
decoded, err := data.UnmarshalArrowFrames(df.encoded) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
df.decoded = decoded |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return df.decoded, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (df *dataFrames) MarshalJSON() ([]byte, error) { |
|
|
|
|
encoded, err := df.Encoded() |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return json.Marshal(encoded) |
|
|
|
|
} |
|
|
|
|