mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Expressions: Use enumerations rather than strings (#83741)
This commit is contained in:
parent
c59ebfc60f
commit
5f6bf93dd5
@ -54,7 +54,7 @@ type condition struct {
|
|||||||
// Operator is the logical operator to use when there are two conditions in ConditionsCmd.
|
// Operator is the logical operator to use when there are two conditions in ConditionsCmd.
|
||||||
// If there are more than two conditions in ConditionsCmd then operator is used to compare
|
// If there are more than two conditions in ConditionsCmd then operator is used to compare
|
||||||
// the outcome of this condition with that of the condition before it.
|
// the outcome of this condition with that of the condition before it.
|
||||||
Operator string
|
Operator ConditionOperatorType
|
||||||
}
|
}
|
||||||
|
|
||||||
// NeedsVars returns the variable names (refIds) that are dependencies
|
// NeedsVars returns the variable names (refIds) that are dependencies
|
||||||
@ -216,7 +216,7 @@ func (cmd *ConditionsCmd) executeCond(_ context.Context, _ time.Time, cond condi
|
|||||||
return isCondFiring, isCondNoData, matches, nil
|
return isCondFiring, isCondNoData, matches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareWithOperator(b1, b2 bool, operator string) bool {
|
func compareWithOperator(b1, b2 bool, operator ConditionOperatorType) bool {
|
||||||
if operator == "or" {
|
if operator == "or" {
|
||||||
return b1 || b2
|
return b1 || b2
|
||||||
} else {
|
} else {
|
||||||
@ -262,8 +262,17 @@ type ConditionEvalJSON struct {
|
|||||||
Type string `json:"type"` // e.g. "gt"
|
Type string `json:"type"` // e.g. "gt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The reducer function
|
||||||
|
// +enum
|
||||||
|
type ConditionOperatorType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConditionOperatorAnd ConditionOperatorType = "and"
|
||||||
|
ConditionOperatorOr ConditionOperatorType = "or"
|
||||||
|
)
|
||||||
|
|
||||||
type ConditionOperatorJSON struct {
|
type ConditionOperatorJSON struct {
|
||||||
Type string `json:"type"`
|
Type ConditionOperatorType `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConditionQueryJSON struct {
|
type ConditionQueryJSON struct {
|
||||||
|
@ -205,14 +205,14 @@ func (gr *ReduceCommand) Execute(ctx context.Context, _ time.Time, vars mathexp.
|
|||||||
type ResampleCommand struct {
|
type ResampleCommand struct {
|
||||||
Window time.Duration
|
Window time.Duration
|
||||||
VarToResample string
|
VarToResample string
|
||||||
Downsampler string
|
Downsampler mathexp.ReducerID
|
||||||
Upsampler string
|
Upsampler mathexp.Upsampler
|
||||||
TimeRange TimeRange
|
TimeRange TimeRange
|
||||||
refID string
|
refID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResampleCommand creates a new ResampleCMD.
|
// NewResampleCommand creates a new ResampleCMD.
|
||||||
func NewResampleCommand(refID, rawWindow, varToResample string, downsampler string, upsampler string, tr TimeRange) (*ResampleCommand, error) {
|
func NewResampleCommand(refID, rawWindow, varToResample string, downsampler mathexp.ReducerID, upsampler mathexp.Upsampler, tr TimeRange) (*ResampleCommand, error) {
|
||||||
// TODO: validate reducer here, before execution
|
// TODO: validate reducer here, before execution
|
||||||
window, err := gtime.ParseDuration(rawWindow)
|
window, err := gtime.ParseDuration(rawWindow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -271,7 +271,11 @@ func UnmarshalResampleCommand(rn *rawNode) (*ResampleCommand, error) {
|
|||||||
return nil, fmt.Errorf("expected resample downsampler to be a string, got type %T", upsampler)
|
return nil, fmt.Errorf("expected resample downsampler to be a string, got type %T", upsampler)
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewResampleCommand(rn.RefID, window, varToResample, downsampler, upsampler, rn.TimeRange)
|
return NewResampleCommand(rn.RefID, window,
|
||||||
|
varToResample,
|
||||||
|
mathexp.ReducerID(downsampler),
|
||||||
|
mathexp.Upsampler(upsampler),
|
||||||
|
rn.TimeRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NeedsVars returns the variable names (refIds) that are dependencies
|
// NeedsVars returns the variable names (refIds) that are dependencies
|
||||||
|
@ -7,8 +7,23 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The upsample function
|
||||||
|
// +enum
|
||||||
|
type Upsampler string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Use the last seen value
|
||||||
|
UpsamplerPad Upsampler = "pad"
|
||||||
|
|
||||||
|
// backfill
|
||||||
|
UpsamplerBackfill Upsampler = "backfilling"
|
||||||
|
|
||||||
|
// Do not fill values (nill)
|
||||||
|
UpsamplerFillNA Upsampler = "fillna"
|
||||||
|
)
|
||||||
|
|
||||||
// Resample turns the Series into a Number based on the given reduction function
|
// Resample turns the Series into a Number based on the given reduction function
|
||||||
func (s Series) Resample(refID string, interval time.Duration, downsampler string, upsampler string, from, to time.Time) (Series, error) {
|
func (s Series) Resample(refID string, interval time.Duration, downsampler ReducerID, upsampler Upsampler, from, to time.Time) (Series, error) {
|
||||||
newSeriesLength := int(float64(to.Sub(from).Nanoseconds()) / float64(interval.Nanoseconds()))
|
newSeriesLength := int(float64(to.Sub(from).Nanoseconds()) / float64(interval.Nanoseconds()))
|
||||||
if newSeriesLength <= 0 {
|
if newSeriesLength <= 0 {
|
||||||
return s, fmt.Errorf("the series cannot be sampled further; the time range is shorter than the interval")
|
return s, fmt.Errorf("the series cannot be sampled further; the time range is shorter than the interval")
|
||||||
@ -37,19 +52,19 @@ func (s Series) Resample(refID string, interval time.Duration, downsampler strin
|
|||||||
var value *float64
|
var value *float64
|
||||||
if len(vals) == 0 { // upsampling
|
if len(vals) == 0 { // upsampling
|
||||||
switch upsampler {
|
switch upsampler {
|
||||||
case "pad":
|
case UpsamplerPad:
|
||||||
if lastSeen != nil {
|
if lastSeen != nil {
|
||||||
value = lastSeen
|
value = lastSeen
|
||||||
} else {
|
} else {
|
||||||
value = nil
|
value = nil
|
||||||
}
|
}
|
||||||
case "backfilling":
|
case UpsamplerBackfill:
|
||||||
if sIdx == s.Len() { // no vals left
|
if sIdx == s.Len() { // no vals left
|
||||||
value = nil
|
value = nil
|
||||||
} else {
|
} else {
|
||||||
_, value = s.GetPoint(sIdx)
|
_, value = s.GetPoint(sIdx)
|
||||||
}
|
}
|
||||||
case "fillna":
|
case UpsamplerFillNA:
|
||||||
value = nil
|
value = nil
|
||||||
default:
|
default:
|
||||||
return s, fmt.Errorf("upsampling %v not implemented", upsampler)
|
return s, fmt.Errorf("upsampling %v not implemented", upsampler)
|
||||||
@ -61,15 +76,15 @@ func (s Series) Resample(refID string, interval time.Duration, downsampler strin
|
|||||||
ff := Float64Field(*fVec)
|
ff := Float64Field(*fVec)
|
||||||
var tmp *float64
|
var tmp *float64
|
||||||
switch downsampler {
|
switch downsampler {
|
||||||
case "sum":
|
case ReducerSum:
|
||||||
tmp = Sum(&ff)
|
tmp = Sum(&ff)
|
||||||
case "mean":
|
case ReducerMean:
|
||||||
tmp = Avg(&ff)
|
tmp = Avg(&ff)
|
||||||
case "min":
|
case ReducerMin:
|
||||||
tmp = Min(&ff)
|
tmp = Min(&ff)
|
||||||
case "max":
|
case ReducerMax:
|
||||||
tmp = Max(&ff)
|
tmp = Max(&ff)
|
||||||
case "last":
|
case ReducerLast:
|
||||||
tmp = Last(&ff)
|
tmp = Last(&ff)
|
||||||
default:
|
default:
|
||||||
return s, fmt.Errorf("downsampling %v not implemented", downsampler)
|
return s, fmt.Errorf("downsampling %v not implemented", downsampler)
|
||||||
|
@ -13,8 +13,8 @@ func TestResampleSeries(t *testing.T) {
|
|||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
interval time.Duration
|
interval time.Duration
|
||||||
downsampler string
|
downsampler ReducerID
|
||||||
upsampler string
|
upsampler Upsampler
|
||||||
timeRange backend.TimeRange
|
timeRange backend.TimeRange
|
||||||
seriesToResample Series
|
seriesToResample Series
|
||||||
series Series
|
series Series
|
||||||
|
@ -54,10 +54,10 @@ type ResampleQuery struct {
|
|||||||
Window string `json:"window" jsonschema:"minLength=1,example=1w,example=10m"`
|
Window string `json:"window" jsonschema:"minLength=1,example=1w,example=10m"`
|
||||||
|
|
||||||
// The downsample function
|
// The downsample function
|
||||||
Downsampler string `json:"downsampler"`
|
Downsampler mathexp.ReducerID `json:"downsampler"`
|
||||||
|
|
||||||
// The upsample function
|
// The upsample function
|
||||||
Upsampler string `json:"upsampler"`
|
Upsampler mathexp.Upsampler `json:"upsampler"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ThresholdQuery struct {
|
type ThresholdQuery struct {
|
||||||
|
@ -156,7 +156,7 @@ func (h *ExpressionQueryReader) ReadQuery(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getReferenceVar(exp string, refId string) (string, error) {
|
func getReferenceVar(exp string, refId string) (string, error) {
|
||||||
exp = strings.TrimPrefix(exp, "%")
|
exp = strings.TrimPrefix(exp, "$")
|
||||||
if exp == "" {
|
if exp == "" {
|
||||||
return "", fmt.Errorf("no variable specified to reference for refId %v", refId)
|
return "", fmt.Errorf("no variable specified to reference for refId %v", refId)
|
||||||
}
|
}
|
||||||
|
@ -18,23 +18,31 @@ import (
|
|||||||
type ThresholdCommand struct {
|
type ThresholdCommand struct {
|
||||||
ReferenceVar string
|
ReferenceVar string
|
||||||
RefID string
|
RefID string
|
||||||
ThresholdFunc string
|
ThresholdFunc ThresholdType
|
||||||
Conditions []float64
|
Conditions []float64
|
||||||
Invert bool
|
Invert bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +enum
|
||||||
|
type ThresholdType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ThresholdIsAbove = "gt"
|
ThresholdIsAbove ThresholdType = "gt"
|
||||||
ThresholdIsBelow = "lt"
|
ThresholdIsBelow ThresholdType = "lt"
|
||||||
ThresholdIsWithinRange = "within_range"
|
ThresholdIsWithinRange ThresholdType = "within_range"
|
||||||
ThresholdIsOutsideRange = "outside_range"
|
ThresholdIsOutsideRange ThresholdType = "outside_range"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
supportedThresholdFuncs = []string{ThresholdIsAbove, ThresholdIsBelow, ThresholdIsWithinRange, ThresholdIsOutsideRange}
|
supportedThresholdFuncs = []string{
|
||||||
|
string(ThresholdIsAbove),
|
||||||
|
string(ThresholdIsBelow),
|
||||||
|
string(ThresholdIsWithinRange),
|
||||||
|
string(ThresholdIsOutsideRange),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewThresholdCommand(refID, referenceVar, thresholdFunc string, conditions []float64) (*ThresholdCommand, error) {
|
func NewThresholdCommand(refID, referenceVar string, thresholdFunc ThresholdType, conditions []float64) (*ThresholdCommand, error) {
|
||||||
switch thresholdFunc {
|
switch thresholdFunc {
|
||||||
case ThresholdIsOutsideRange, ThresholdIsWithinRange:
|
case ThresholdIsOutsideRange, ThresholdIsWithinRange:
|
||||||
if len(conditions) < 2 {
|
if len(conditions) < 2 {
|
||||||
@ -58,7 +66,7 @@ func NewThresholdCommand(refID, referenceVar, thresholdFunc string, conditions [
|
|||||||
|
|
||||||
type ConditionEvalJSON struct {
|
type ConditionEvalJSON struct {
|
||||||
Params []float64 `json:"params"`
|
Params []float64 `json:"params"`
|
||||||
Type string `json:"type"` // e.g. "gt"
|
Type ThresholdType `json:"type"` // e.g. "gt"
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalResampleCommand creates a ResampleCMD from Grafana's frontend query.
|
// UnmarshalResampleCommand creates a ResampleCMD from Grafana's frontend query.
|
||||||
@ -121,7 +129,7 @@ func (tc *ThresholdCommand) Execute(ctx context.Context, now time.Time, vars mat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createMathExpression converts all the info we have about a "threshold" expression in to a Math expression
|
// createMathExpression converts all the info we have about a "threshold" expression in to a Math expression
|
||||||
func createMathExpression(referenceVar string, thresholdFunc string, args []float64, invert bool) (string, error) {
|
func createMathExpression(referenceVar string, thresholdFunc ThresholdType, args []float64, invert bool) (string, error) {
|
||||||
var exp string
|
var exp string
|
||||||
switch thresholdFunc {
|
switch thresholdFunc {
|
||||||
case ThresholdIsAbove:
|
case ThresholdIsAbove:
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
func TestNewThresholdCommand(t *testing.T) {
|
func TestNewThresholdCommand(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
fn string
|
fn ThresholdType
|
||||||
args []float64
|
args []float64
|
||||||
shouldError bool
|
shouldError bool
|
||||||
expectedError string
|
expectedError string
|
||||||
@ -107,7 +107,7 @@ func TestUnmarshalThresholdCommand(t *testing.T) {
|
|||||||
require.IsType(t, &ThresholdCommand{}, command)
|
require.IsType(t, &ThresholdCommand{}, command)
|
||||||
cmd := command.(*ThresholdCommand)
|
cmd := command.(*ThresholdCommand)
|
||||||
require.Equal(t, []string{"A"}, cmd.NeedsVars())
|
require.Equal(t, []string{"A"}, cmd.NeedsVars())
|
||||||
require.Equal(t, "gt", cmd.ThresholdFunc)
|
require.Equal(t, ThresholdIsAbove, cmd.ThresholdFunc)
|
||||||
require.Equal(t, []float64{20.0, 80.0}, cmd.Conditions)
|
require.Equal(t, []float64{20.0, 80.0}, cmd.Conditions)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -172,10 +172,10 @@ func TestUnmarshalThresholdCommand(t *testing.T) {
|
|||||||
cmd := c.(*HysteresisCommand)
|
cmd := c.(*HysteresisCommand)
|
||||||
require.Equal(t, []string{"B"}, cmd.NeedsVars())
|
require.Equal(t, []string{"B"}, cmd.NeedsVars())
|
||||||
require.Equal(t, []string{"B"}, cmd.LoadingThresholdFunc.NeedsVars())
|
require.Equal(t, []string{"B"}, cmd.LoadingThresholdFunc.NeedsVars())
|
||||||
require.Equal(t, "gt", cmd.LoadingThresholdFunc.ThresholdFunc)
|
require.Equal(t, ThresholdIsAbove, cmd.LoadingThresholdFunc.ThresholdFunc)
|
||||||
require.Equal(t, []float64{100.0}, cmd.LoadingThresholdFunc.Conditions)
|
require.Equal(t, []float64{100.0}, cmd.LoadingThresholdFunc.Conditions)
|
||||||
require.Equal(t, []string{"B"}, cmd.UnloadingThresholdFunc.NeedsVars())
|
require.Equal(t, []string{"B"}, cmd.UnloadingThresholdFunc.NeedsVars())
|
||||||
require.Equal(t, "lt", cmd.UnloadingThresholdFunc.ThresholdFunc)
|
require.Equal(t, ThresholdIsBelow, cmd.UnloadingThresholdFunc.ThresholdFunc)
|
||||||
require.Equal(t, []float64{31.0}, cmd.UnloadingThresholdFunc.Conditions)
|
require.Equal(t, []float64{31.0}, cmd.UnloadingThresholdFunc.Conditions)
|
||||||
require.True(t, cmd.UnloadingThresholdFunc.Invert)
|
require.True(t, cmd.UnloadingThresholdFunc.Invert)
|
||||||
require.NotNil(t, cmd.LoadedDimensions)
|
require.NotNil(t, cmd.LoadedDimensions)
|
||||||
@ -233,7 +233,7 @@ func TestCreateMathExpression(t *testing.T) {
|
|||||||
expected string
|
expected string
|
||||||
|
|
||||||
ref string
|
ref string
|
||||||
function string
|
function ThresholdType
|
||||||
params []float64
|
params []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ func TestCreateMathExpression(t *testing.T) {
|
|||||||
|
|
||||||
func TestIsSupportedThresholdFunc(t *testing.T) {
|
func TestIsSupportedThresholdFunc(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
function string
|
function ThresholdType
|
||||||
supported bool
|
supported bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,8 +325,8 @@ func TestIsSupportedThresholdFunc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.function, func(t *testing.T) {
|
t.Run(string(tc.function), func(t *testing.T) {
|
||||||
supported := IsSupportedThresholdFunc(tc.function)
|
supported := IsSupportedThresholdFunc(string(tc.function))
|
||||||
require.Equal(t, supported, tc.supported)
|
require.Equal(t, supported, tc.supported)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ import (
|
|||||||
type dataEvaluator struct {
|
type dataEvaluator struct {
|
||||||
refID string
|
refID string
|
||||||
data []mathexp.Series
|
data []mathexp.Series
|
||||||
downsampleFunction string
|
downsampleFunction mathexp.ReducerID
|
||||||
upsampleFunction string
|
upsampleFunction mathexp.Upsampler
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDataEvaluator(refID string, frame *data.Frame) (*dataEvaluator, error) {
|
func newDataEvaluator(refID string, frame *data.Frame) (*dataEvaluator, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user