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.
|
||||
// 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.
|
||||
Operator string
|
||||
Operator ConditionOperatorType
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func compareWithOperator(b1, b2 bool, operator string) bool {
|
||||
func compareWithOperator(b1, b2 bool, operator ConditionOperatorType) bool {
|
||||
if operator == "or" {
|
||||
return b1 || b2
|
||||
} else {
|
||||
@ -262,8 +262,17 @@ type ConditionEvalJSON struct {
|
||||
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 string `json:"type"`
|
||||
Type ConditionOperatorType `json:"type"`
|
||||
}
|
||||
|
||||
type ConditionQueryJSON struct {
|
||||
|
@ -205,14 +205,14 @@ func (gr *ReduceCommand) Execute(ctx context.Context, _ time.Time, vars mathexp.
|
||||
type ResampleCommand struct {
|
||||
Window time.Duration
|
||||
VarToResample string
|
||||
Downsampler string
|
||||
Upsampler string
|
||||
Downsampler mathexp.ReducerID
|
||||
Upsampler mathexp.Upsampler
|
||||
TimeRange TimeRange
|
||||
refID string
|
||||
}
|
||||
|
||||
// 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
|
||||
window, err := gtime.ParseDuration(rawWindow)
|
||||
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 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
|
||||
|
@ -7,8 +7,23 @@ import (
|
||||
"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
|
||||
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()))
|
||||
if newSeriesLength <= 0 {
|
||||
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
|
||||
if len(vals) == 0 { // upsampling
|
||||
switch upsampler {
|
||||
case "pad":
|
||||
case UpsamplerPad:
|
||||
if lastSeen != nil {
|
||||
value = lastSeen
|
||||
} else {
|
||||
value = nil
|
||||
}
|
||||
case "backfilling":
|
||||
case UpsamplerBackfill:
|
||||
if sIdx == s.Len() { // no vals left
|
||||
value = nil
|
||||
} else {
|
||||
_, value = s.GetPoint(sIdx)
|
||||
}
|
||||
case "fillna":
|
||||
case UpsamplerFillNA:
|
||||
value = nil
|
||||
default:
|
||||
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)
|
||||
var tmp *float64
|
||||
switch downsampler {
|
||||
case "sum":
|
||||
case ReducerSum:
|
||||
tmp = Sum(&ff)
|
||||
case "mean":
|
||||
case ReducerMean:
|
||||
tmp = Avg(&ff)
|
||||
case "min":
|
||||
case ReducerMin:
|
||||
tmp = Min(&ff)
|
||||
case "max":
|
||||
case ReducerMax:
|
||||
tmp = Max(&ff)
|
||||
case "last":
|
||||
case ReducerLast:
|
||||
tmp = Last(&ff)
|
||||
default:
|
||||
return s, fmt.Errorf("downsampling %v not implemented", downsampler)
|
||||
|
@ -13,8 +13,8 @@ func TestResampleSeries(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
interval time.Duration
|
||||
downsampler string
|
||||
upsampler string
|
||||
downsampler ReducerID
|
||||
upsampler Upsampler
|
||||
timeRange backend.TimeRange
|
||||
seriesToResample Series
|
||||
series Series
|
||||
|
@ -54,10 +54,10 @@ type ResampleQuery struct {
|
||||
Window string `json:"window" jsonschema:"minLength=1,example=1w,example=10m"`
|
||||
|
||||
// The downsample function
|
||||
Downsampler string `json:"downsampler"`
|
||||
Downsampler mathexp.ReducerID `json:"downsampler"`
|
||||
|
||||
// The upsample function
|
||||
Upsampler string `json:"upsampler"`
|
||||
Upsampler mathexp.Upsampler `json:"upsampler"`
|
||||
}
|
||||
|
||||
type ThresholdQuery struct {
|
||||
|
@ -156,7 +156,7 @@ func (h *ExpressionQueryReader) ReadQuery(
|
||||
}
|
||||
|
||||
func getReferenceVar(exp string, refId string) (string, error) {
|
||||
exp = strings.TrimPrefix(exp, "%")
|
||||
exp = strings.TrimPrefix(exp, "$")
|
||||
if exp == "" {
|
||||
return "", fmt.Errorf("no variable specified to reference for refId %v", refId)
|
||||
}
|
||||
|
@ -18,23 +18,31 @@ import (
|
||||
type ThresholdCommand struct {
|
||||
ReferenceVar string
|
||||
RefID string
|
||||
ThresholdFunc string
|
||||
ThresholdFunc ThresholdType
|
||||
Conditions []float64
|
||||
Invert bool
|
||||
}
|
||||
|
||||
// +enum
|
||||
type ThresholdType string
|
||||
|
||||
const (
|
||||
ThresholdIsAbove = "gt"
|
||||
ThresholdIsBelow = "lt"
|
||||
ThresholdIsWithinRange = "within_range"
|
||||
ThresholdIsOutsideRange = "outside_range"
|
||||
ThresholdIsAbove ThresholdType = "gt"
|
||||
ThresholdIsBelow ThresholdType = "lt"
|
||||
ThresholdIsWithinRange ThresholdType = "within_range"
|
||||
ThresholdIsOutsideRange ThresholdType = "outside_range"
|
||||
)
|
||||
|
||||
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 {
|
||||
case ThresholdIsOutsideRange, ThresholdIsWithinRange:
|
||||
if len(conditions) < 2 {
|
||||
@ -57,8 +65,8 @@ func NewThresholdCommand(refID, referenceVar, thresholdFunc string, conditions [
|
||||
}
|
||||
|
||||
type ConditionEvalJSON struct {
|
||||
Params []float64 `json:"params"`
|
||||
Type string `json:"type"` // e.g. "gt"
|
||||
Params []float64 `json:"params"`
|
||||
Type ThresholdType `json:"type"` // e.g. "gt"
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
switch thresholdFunc {
|
||||
case ThresholdIsAbove:
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
func TestNewThresholdCommand(t *testing.T) {
|
||||
type testCase struct {
|
||||
fn string
|
||||
fn ThresholdType
|
||||
args []float64
|
||||
shouldError bool
|
||||
expectedError string
|
||||
@ -107,7 +107,7 @@ func TestUnmarshalThresholdCommand(t *testing.T) {
|
||||
require.IsType(t, &ThresholdCommand{}, command)
|
||||
cmd := command.(*ThresholdCommand)
|
||||
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)
|
||||
},
|
||||
},
|
||||
@ -172,10 +172,10 @@ func TestUnmarshalThresholdCommand(t *testing.T) {
|
||||
cmd := c.(*HysteresisCommand)
|
||||
require.Equal(t, []string{"B"}, cmd.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, []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.True(t, cmd.UnloadingThresholdFunc.Invert)
|
||||
require.NotNil(t, cmd.LoadedDimensions)
|
||||
@ -233,7 +233,7 @@ func TestCreateMathExpression(t *testing.T) {
|
||||
expected string
|
||||
|
||||
ref string
|
||||
function string
|
||||
function ThresholdType
|
||||
params []float64
|
||||
}
|
||||
|
||||
@ -297,7 +297,7 @@ func TestCreateMathExpression(t *testing.T) {
|
||||
|
||||
func TestIsSupportedThresholdFunc(t *testing.T) {
|
||||
type testCase struct {
|
||||
function string
|
||||
function ThresholdType
|
||||
supported bool
|
||||
}
|
||||
|
||||
@ -325,8 +325,8 @@ func TestIsSupportedThresholdFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.function, func(t *testing.T) {
|
||||
supported := IsSupportedThresholdFunc(tc.function)
|
||||
t.Run(string(tc.function), func(t *testing.T) {
|
||||
supported := IsSupportedThresholdFunc(string(tc.function))
|
||||
require.Equal(t, supported, tc.supported)
|
||||
})
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ import (
|
||||
type dataEvaluator struct {
|
||||
refID string
|
||||
data []mathexp.Series
|
||||
downsampleFunction string
|
||||
upsampleFunction string
|
||||
downsampleFunction mathexp.ReducerID
|
||||
upsampleFunction mathexp.Upsampler
|
||||
}
|
||||
|
||||
func newDataEvaluator(refID string, frame *data.Frame) (*dataEvaluator, error) {
|
||||
|
Loading…
Reference in New Issue
Block a user