From 4093fae99a6e687e1757d8cc6365c1de20e994d9 Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Wed, 2 Jun 2021 12:29:19 -0400 Subject: [PATCH] SSE: Refactor to simplify Series type (#35063) Co-authored-by: Arve Knudsen --- pkg/expr/classic/reduce.go | 2 +- pkg/expr/classic/reduce_test.go | 13 +- pkg/expr/mathexp/exp.go | 13 +- pkg/expr/mathexp/exp_nan_null_val_test.go | 131 +++---- pkg/expr/mathexp/exp_series_test.go | 394 ++++++---------------- pkg/expr/mathexp/exp_test.go | 122 +------ pkg/expr/mathexp/funcs.go | 5 +- pkg/expr/mathexp/funcs_test.go | 17 +- pkg/expr/mathexp/reduce.go | 2 +- pkg/expr/mathexp/reduce_test.go | 27 +- pkg/expr/mathexp/resample.go | 5 +- pkg/expr/mathexp/resample_test.go | 268 +++++++-------- pkg/expr/mathexp/type_series.go | 175 +++++----- pkg/expr/mathexp/types_test.go | 85 +++-- pkg/expr/mathexp/union_test.go | 98 +++--- pkg/expr/service_test.go | 9 +- 16 files changed, 517 insertions(+), 849 deletions(-) diff --git a/pkg/expr/classic/reduce.go b/pkg/expr/classic/reduce.go index 3a6fda0cc05..3fd74b6b4d8 100644 --- a/pkg/expr/classic/reduce.go +++ b/pkg/expr/classic/reduce.go @@ -38,7 +38,7 @@ func (cr classicReducer) Reduce(series mathexp.Series) mathexp.Number { value := float64(0) allNull := true - vF := series.Frame.Fields[series.ValueIdx] + vF := series.Frame.Fields[1] ff := mathexp.Float64Field(*vF) switch cr { diff --git a/pkg/expr/classic/reduce_test.go b/pkg/expr/classic/reduce_test.go index 7361e9295c6..f4a5a39c37c 100644 --- a/pkg/expr/classic/reduce_test.go +++ b/pkg/expr/classic/reduce_test.go @@ -399,9 +399,9 @@ func TestPercentDiffAbsReducer(t *testing.T) { } func valBasedSeries(vals ...*float64) mathexp.Series { - newSeries := mathexp.NewSeries("", nil, 0, false, 1, true, len(vals)) + newSeries := mathexp.NewSeries("", nil, len(vals)) for idx, f := range vals { - err := newSeries.SetPoint(idx, unixTimePointer(int64(idx)), f) + err := newSeries.SetPoint(idx, time.Unix(int64(idx), 0), f) if err != nil { panic(err) } @@ -410,9 +410,9 @@ func valBasedSeries(vals ...*float64) mathexp.Series { } func valBasedSeriesWithLabels(l data.Labels, vals ...*float64) mathexp.Series { - newSeries := mathexp.NewSeries("", l, 0, false, 1, true, len(vals)) + newSeries := mathexp.NewSeries("", l, len(vals)) for idx, f := range vals { - err := newSeries.SetPoint(idx, unixTimePointer(int64(idx)), f) + err := newSeries.SetPoint(idx, time.Unix(int64(idx), 0), f) if err != nil { panic(err) } @@ -420,11 +420,6 @@ func valBasedSeriesWithLabels(l data.Labels, vals ...*float64) mathexp.Series { return newSeries } -func unixTimePointer(sec int64) *time.Time { - t := time.Unix(sec, 0) - return &t -} - func valBasedNumber(f *float64) mathexp.Number { newNumber := mathexp.NewNumber("", nil) newNumber.SetValue(f) diff --git a/pkg/expr/mathexp/exp.go b/pkg/expr/mathexp/exp.go index fe18378fd80..43b9d11689e 100644 --- a/pkg/expr/mathexp/exp.go +++ b/pkg/expr/mathexp/exp.go @@ -129,7 +129,7 @@ func (e *State) walkUnary(node *parse.UnaryNode) (Results, error) { } func (e *State) unarySeries(s Series, op string) (Series, error) { - newSeries := NewSeries(e.RefID, s.GetLabels(), s.TimeIdx, s.TimeIsNullable, s.ValueIdx, s.ValueIsNullable, s.Len()) + newSeries := NewSeries(e.RefID, s.GetLabels(), s.Len()) for i := 0; i < s.Len(); i++ { t, f := s.GetPoint(i) if f == nil { @@ -431,7 +431,7 @@ func (e *State) biScalarNumber(labels data.Labels, op string, number Number, sca } func (e *State) biSeriesNumber(labels data.Labels, op string, s Series, scalarVal *float64, seriesFirst bool) (Series, error) { - newSeries := NewSeries(e.RefID, labels, s.TimeIdx, s.TimeIsNullable, s.ValueIdx, s.ValueIsNullable, s.Len()) + newSeries := NewSeries(e.RefID, labels, s.Len()) var err error for i := 0; i < s.Len(); i++ { nF := math.NaN() @@ -464,15 +464,10 @@ func (e *State) biSeriesSeries(labels data.Labels, op string, aSeries, bSeries S bPoints := make(map[string]*float64) for i := 0; i < bSeries.Len(); i++ { t, f := bSeries.GetPoint(i) - if t != nil { - bPoints[t.UTC().String()] = f - } + bPoints[t.UTC().String()] = f } - newSeries := NewSeries( - e.RefID, labels, aSeries.TimeIdx, aSeries.TimeIsNullable || bSeries.TimeIsNullable, aSeries.ValueIdx, - aSeries.ValueIsNullable || bSeries.ValueIsNullable, 0, - ) + newSeries := NewSeries(e.RefID, labels, 0) for aIdx := 0; aIdx < aSeries.Len(); aIdx++ { aTime, aF := aSeries.GetPoint(aIdx) bF, ok := bPoints[aTime.UTC().String()] diff --git a/pkg/expr/mathexp/exp_nan_null_val_test.go b/pkg/expr/mathexp/exp_nan_null_val_test.go index 866125e3174..7c0e8fbd99f 100644 --- a/pkg/expr/mathexp/exp_nan_null_val_test.go +++ b/pkg/expr/mathexp/exp_nan_null_val_test.go @@ -3,6 +3,7 @@ package mathexp import ( "math" "testing" + "time" "github.com/google/go-cmp/cmp" "github.com/grafana/grafana-plugin-sdk-go/data" @@ -29,7 +30,7 @@ func TestNaN(t *testing.T) { }, { name: "unary -: Op Number(NaN) is NaN", - expr: "! $A", + expr: "-$A", vars: Vars{"A": Results{[]Value{makeNumber("", nil, NaN)}}}, newErrIs: assert.NoError, execErrIs: assert.NoError, @@ -57,10 +58,10 @@ func TestNaN(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("temp", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), NaN, + makeSeries("temp", nil, tp{ + time.Unix(5, 0), float64Pointer(2), + }, tp{ + time.Unix(10, 0), NaN, }), }, }, @@ -69,10 +70,10 @@ func TestNaN(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(-1), - }, nullTimeTP{ - unixTimePointer(10, 0), NaN, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(-1), + }, tp{ + time.Unix(10, 0), NaN, }), }, }, @@ -83,10 +84,10 @@ func TestNaN(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("temp", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), NaN, + makeSeries("temp", nil, tp{ + time.Unix(5, 0), float64Pointer(2), + }, tp{ + time.Unix(10, 0), NaN, }), }, }, @@ -96,10 +97,10 @@ func TestNaN(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(0), - }, nullTimeTP{ - unixTimePointer(10, 0), NaN, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(0), + }, tp{ + time.Unix(10, 0), NaN, }), }, }, @@ -110,10 +111,10 @@ func TestNaN(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("temp", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), NaN, + makeSeries("temp", nil, tp{ + time.Unix(5, 0), float64Pointer(2), + }, tp{ + time.Unix(10, 0), NaN, }), }, }, @@ -123,10 +124,10 @@ func TestNaN(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), NaN, - }, nullTimeTP{ - unixTimePointer(10, 0), NaN, + makeSeries("", nil, tp{ + time.Unix(5, 0), NaN, + }, tp{ + time.Unix(10, 0), NaN, }), }, }, @@ -197,10 +198,10 @@ func TestNullValues(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -209,10 +210,10 @@ func TestNullValues(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(-1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(-1), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -223,10 +224,10 @@ func TestNullValues(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -235,10 +236,10 @@ func TestNullValues(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(0), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(0), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -249,10 +250,10 @@ func TestNullValues(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -261,10 +262,10 @@ func TestNullValues(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(0), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(0), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -339,10 +340,10 @@ func TestNullValues(t *testing.T) { }, "B": Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -351,10 +352,10 @@ func TestNullValues(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -370,10 +371,10 @@ func TestNullValues(t *testing.T) { }, "B": Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), nil, }), }, }, @@ -382,10 +383,10 @@ func TestNullValues(t *testing.T) { execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), nil, - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + makeSeries("", nil, tp{ + time.Unix(5, 0), nil, + }, tp{ + time.Unix(10, 0), nil, }), }, }, diff --git a/pkg/expr/mathexp/exp_series_test.go b/pkg/expr/mathexp/exp_series_test.go index 877f1a0d0cd..63f0cf68ea5 100644 --- a/pkg/expr/mathexp/exp_series_test.go +++ b/pkg/expr/mathexp/exp_series_test.go @@ -21,185 +21,6 @@ func TestSeriesExpr(t *testing.T) { { name: "unary series", expr: "! ! $A", - vars: aSeriesNullableTime, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ // Not sure about preservering names... - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1), - }), - }, - }, - }, - { - name: "binary scalar Op series", - expr: "98 + $A", - vars: aSeriesNullableTime, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ // Not sure about preservering names... - unixTimePointer(5, 0), float64Pointer(100), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(99), - }), - }, - }, - }, - { - name: "binary series Op scalar", - expr: "$A + 98", - vars: aSeriesNullableTime, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ // Not sure about preservering names... - unixTimePointer(5, 0), float64Pointer(100), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(99), - }), - }, - }, - }, - { - name: "series Op series", - expr: "$A + $A", - vars: aSeriesNullableTime, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ // Not sure about preservering names... - unixTimePointer(5, 0), float64Pointer(4), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(2), - }), - }, - }, - }, - { - name: "series Op number", - expr: "$A + $B", - vars: aSeriesbNumber, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", data.Labels{"id": "1"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(9), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(8), - }), - }, - }, - }, - { - name: "number Op series", - expr: "$B + $A", - vars: aSeriesbNumber, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", data.Labels{"id": "1"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(9), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(8), - }), - }, - }, - }, - { - name: "series Op series with label union", - expr: "$A * $B", - vars: twoSeriesSets, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", data.Labels{"sensor": "a", "turbine": "1"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(6 * .5), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(8 * .2), - }), - makeSeriesNullableTime("", data.Labels{"sensor": "b", "turbine": "1"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(10 * .5), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(16 * .2), - }), - }, - }, - }, - // Length of resulting series is A when A + B. However, only points where the time matches - // for A and B are added to the result - { - name: "series Op series with sparse time join", - expr: "$A + $B", - vars: Vars{ - "A": Results{ - []Value{ - makeSeriesNullableTime("temp", data.Labels{}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(2), - }), - }, - }, - "B": Results{ - []Value{ - makeSeriesNullableTime("efficiency", data.Labels{}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(9, 0), float64Pointer(4), - }), - }, - }, - }, - - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ // Not sure about preserving names... - unixTimePointer(5, 0), float64Pointer(4), - }), - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - e, err := New(tt.expr) - tt.newErrIs(t, err) - if e != nil { - res, err := e.Execute("", tt.vars) - tt.execErrIs(t, err) - if diff := cmp.Diff(tt.results, res, data.FrameTestCompareOptions()...); diff != "" { - t.Errorf("Result mismatch (-want +got):\n%s", diff) - } - } - }) - } -} - -func TestSeriesAlternateFormsExpr(t *testing.T) { - var tests = []struct { - name string - expr string - vars Vars - newErrIs assert.ErrorAssertionFunc - execErrIs assert.ErrorAssertionFunc - results Results - }{ - { - name: "unary series: non-nullable time", - expr: "! ! $A", vars: aSeries, newErrIs: assert.NoError, execErrIs: assert.NoError, @@ -214,159 +35,144 @@ func TestSeriesAlternateFormsExpr(t *testing.T) { }, }, { - name: "unary series: non-nullable time, time second", - expr: "! ! $A", - vars: aSeriesTimeSecond, + name: "binary scalar Op series", + expr: "98 + $A", + vars: aSeries, newErrIs: assert.NoError, execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesTimeSecond("", nil, timeSecondTP{ // Not sure about preservering names... - float64Pointer(1), time.Unix(5, 0), - }, timeSecondTP{ - float64Pointer(1), time.Unix(10, 0), + makeSeries("", nil, tp{ // Not sure about preservering names... + time.Unix(5, 0), float64Pointer(100), + }, tp{ + time.Unix(10, 0), float64Pointer(99), }), }, }, }, { - name: "unary series: non-nullable value", - expr: "! ! $A", - vars: aSeriesNoNull, + name: "binary series Op scalar", + expr: "$A + 98", + vars: aSeries, newErrIs: assert.NoError, execErrIs: assert.NoError, results: Results{ []Value{ - makeNoNullSeries("", nil, noNullTP{ // Not sure about preservering names... - time.Unix(5, 0), 1, - }, noNullTP{ - time.Unix(10, 0), 1, + makeSeries("", nil, tp{ // Not sure about preservering names... + time.Unix(5, 0), float64Pointer(100), + }, tp{ + time.Unix(10, 0), float64Pointer(99), }), }, }, }, { - name: "series Op series: nullable and non-nullable time", - expr: "$A + $B", - vars: Vars{ - "A": Results{ - []Value{ - makeSeries("temp", data.Labels{}, tp{ - time.Unix(5, 0), float64Pointer(1), - }, tp{ - time.Unix(10, 0), float64Pointer(2), - }), - }, - }, - "B": Results{ - []Value{ - makeSeriesNullableTime("efficiency", data.Labels{}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(4), - }), - }, - }, - }, + name: "series Op series", + expr: "$A + $A", + vars: aSeries, newErrIs: assert.NoError, execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(4), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(6), - }), - }, - }, - }, - { - name: "series Op series: nullable (time second) and non-nullable time (time first)", - expr: "$B + $A", // takes order from first operator - vars: Vars{ - "A": Results{ - []Value{ - makeSeriesTimeSecond("temp", data.Labels{}, timeSecondTP{ - float64Pointer(1), time.Unix(5, 0), - }, timeSecondTP{ - float64Pointer(2), time.Unix(10, 0), - }), - }, - }, - "B": Results{ - []Value{ - makeSeriesNullableTime("efficiency", data.Labels{}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(4), - }), - }, - }, - }, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(4), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(6), - }), - }, - }, - }, - { - name: "series Op series: nullable and non-nullable values", - expr: "$A + $B", - vars: Vars{ - "A": Results{ - []Value{ - makeSeries("temp", data.Labels{}, tp{ - time.Unix(5, 0), float64Pointer(1), - }, tp{ - time.Unix(10, 0), float64Pointer(2), - }), - }, - }, - "B": Results{ - []Value{ - makeNoNullSeries("efficiency", data.Labels{}, noNullTP{ - time.Unix(5, 0), 3, - }, noNullTP{ - time.Unix(10, 0), 4, - }), - }, - }, - }, - newErrIs: assert.NoError, - execErrIs: assert.NoError, - results: Results{ - []Value{ - makeSeries("", nil, tp{ + makeSeries("", nil, tp{ // Not sure about preservering names... time.Unix(5, 0), float64Pointer(4), }, tp{ - time.Unix(10, 0), float64Pointer(6), + time.Unix(10, 0), float64Pointer(2), }), }, }, }, { - name: "binary scalar Op series: non-nullable time second", - expr: "98 + $A", - vars: aSeriesTimeSecond, + name: "series Op number", + expr: "$A + $B", + vars: aSeriesbNumber, newErrIs: assert.NoError, execErrIs: assert.NoError, results: Results{ []Value{ - makeSeriesTimeSecond("", nil, timeSecondTP{ // Not sure about preservering names... - float64Pointer(100), time.Unix(5, 0), - }, timeSecondTP{ - float64Pointer(99), time.Unix(10, 0), + makeSeries("", data.Labels{"id": "1"}, tp{ + time.Unix(5, 0), float64Pointer(9), + }, tp{ + time.Unix(10, 0), float64Pointer(8), + }), + }, + }, + }, + { + name: "number Op series", + expr: "$B + $A", + vars: aSeriesbNumber, + newErrIs: assert.NoError, + execErrIs: assert.NoError, + results: Results{ + []Value{ + makeSeries("", data.Labels{"id": "1"}, tp{ + time.Unix(5, 0), float64Pointer(9), + }, tp{ + time.Unix(10, 0), float64Pointer(8), + }), + }, + }, + }, + { + name: "series Op series with label union", + expr: "$A * $B", + vars: twoSeriesSets, + newErrIs: assert.NoError, + execErrIs: assert.NoError, + results: Results{ + []Value{ + makeSeries("", data.Labels{"sensor": "a", "turbine": "1"}, tp{ + time.Unix(5, 0), float64Pointer(6 * .5), + }, tp{ + time.Unix(10, 0), float64Pointer(8 * .2), + }), + makeSeries("", data.Labels{"sensor": "b", "turbine": "1"}, tp{ + time.Unix(5, 0), float64Pointer(10 * .5), + }, tp{ + time.Unix(10, 0), float64Pointer(16 * .2), + }), + }, + }, + }, + // Length of resulting series is A when A + B. However, only points where the time matches + // for A and B are added to the result + { + name: "series Op series with sparse time join", + expr: "$A + $B", + vars: Vars{ + "A": Results{ + []Value{ + makeSeries("temp", data.Labels{}, tp{ + time.Unix(5, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), float64Pointer(2), + }), + }, + }, + "B": Results{ + []Value{ + makeSeries("efficiency", data.Labels{}, tp{ + time.Unix(5, 0), float64Pointer(3), + }, tp{ + time.Unix(9, 0), float64Pointer(4), + }), + }, + }, + }, + + newErrIs: assert.NoError, + execErrIs: assert.NoError, + results: Results{ + []Value{ + makeSeries("", nil, tp{ // Not sure about preserving names... + time.Unix(5, 0), float64Pointer(4), }), }, }, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { e, err := New(tt.expr) diff --git a/pkg/expr/mathexp/exp_test.go b/pkg/expr/mathexp/exp_test.go index 3d4eac31411..3fc57462519 100644 --- a/pkg/expr/mathexp/exp_test.go +++ b/pkg/expr/mathexp/exp_test.go @@ -8,60 +8,15 @@ import ( ) // Common Test Constructor Utils and Types -type nullTimeTP struct { - t *time.Time - f *float64 -} - type tp struct { t time.Time f *float64 } -type timeSecondTP struct { - f *float64 - t time.Time -} - -type noNullTP struct { - t time.Time - f float64 -} - -func makeSeriesNullableTime(name string, labels data.Labels, points ...nullTimeTP) Series { - newSeries := NewSeries(name, labels, 0, true, 1, true, len(points)) - for idx, p := range points { - _ = newSeries.SetPoint(idx, p.t, p.f) - } - return newSeries -} - func makeSeries(name string, labels data.Labels, points ...tp) Series { - newSeries := NewSeries(name, labels, 0, false, 1, true, len(points)) + newSeries := NewSeries(name, labels, len(points)) for idx, p := range points { - err := newSeries.SetPoint(idx, &p.t, p.f) - if err != nil { - panic(err) - } - } - return newSeries -} - -func makeNoNullSeries(name string, labels data.Labels, points ...noNullTP) Series { - newSeries := NewSeries(name, labels, 0, false, 1, false, len(points)) - for idx, p := range points { - err := newSeries.SetPoint(idx, &p.t, &p.f) - if err != nil { - panic(err) - } - } - return newSeries -} - -func makeSeriesTimeSecond(name string, labels data.Labels, points ...timeSecondTP) Series { - newSeries := NewSeries(name, labels, 1, false, 0, true, len(points)) - for idx, p := range points { - err := newSeries.SetPoint(idx, &p.t, p.f) + err := newSeries.SetPoint(idx, p.t, p.f) if err != nil { panic(err) } @@ -75,27 +30,10 @@ func makeNumber(name string, labels data.Labels, f *float64) Number { return newNumber } -func unixTimePointer(sec, nsec int64) *time.Time { - t := time.Unix(sec, nsec) - return &t -} - func float64Pointer(f float64) *float64 { return &f } -var aSeriesNullableTime = Vars{ - "A": Results{ - []Value{ - makeSeriesNullableTime("temp", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1), - }), - }, - }, -} - var aSeries = Vars{ "A": Results{ []Value{ @@ -108,37 +46,13 @@ var aSeries = Vars{ }, } -var aSeriesTimeSecond = Vars{ - "A": Results{ - []Value{ - makeSeriesTimeSecond("temp", nil, timeSecondTP{ - float64Pointer(2), time.Unix(5, 0), - }, timeSecondTP{ - float64Pointer(1), time.Unix(10, 0), - }), - }, - }, -} - -var aSeriesNoNull = Vars{ - "A": Results{ - []Value{ - makeNoNullSeries("temp", nil, noNullTP{ - time.Unix(5, 0), 2, - }, noNullTP{ - time.Unix(10, 0), 1, - }), - }, - }, -} - var aSeriesbNumber = Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("temp", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1), + makeSeries("temp", nil, tp{ + time.Unix(5, 0), float64Pointer(2), + }, tp{ + time.Unix(10, 0), float64Pointer(1), }), }, }, @@ -152,24 +66,24 @@ var aSeriesbNumber = Vars{ var twoSeriesSets = Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("temp", data.Labels{"sensor": "a", "turbine": "1"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(6), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(8), + makeSeries("temp", data.Labels{"sensor": "a", "turbine": "1"}, tp{ + time.Unix(5, 0), float64Pointer(6), + }, tp{ + time.Unix(10, 0), float64Pointer(8), }), - makeSeriesNullableTime("temp", data.Labels{"sensor": "b", "turbine": "1"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(10), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(16), + makeSeries("temp", data.Labels{"sensor": "b", "turbine": "1"}, tp{ + time.Unix(5, 0), float64Pointer(10), + }, tp{ + time.Unix(10, 0), float64Pointer(16), }), }, }, "B": Results{ []Value{ - makeSeriesNullableTime("efficiency", data.Labels{"turbine": "1"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(.5), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(.2), + makeSeries("efficiency", data.Labels{"turbine": "1"}, tp{ + time.Unix(5, 0), float64Pointer(.5), + }, tp{ + time.Unix(10, 0), float64Pointer(.2), }), }, }, diff --git a/pkg/expr/mathexp/funcs.go b/pkg/expr/mathexp/funcs.go index d9a7ddb38bb..a8c99f7ac4c 100644 --- a/pkg/expr/mathexp/funcs.go +++ b/pkg/expr/mathexp/funcs.go @@ -95,10 +95,7 @@ func perFloat(e *State, val Value, floatF func(x float64) float64) (Value, error newVal = NewScalar(e.RefID, &nF) case parse.TypeSeriesSet: resSeries := val.(Series) - newSeries := NewSeries( - e.RefID, resSeries.GetLabels(), resSeries.TimeIdx, resSeries.TimeIsNullable, resSeries.ValueIdx, - resSeries.ValueIsNullable, resSeries.Len(), - ) + newSeries := NewSeries(e.RefID, resSeries.GetLabels(), resSeries.Len()) for i := 0; i < resSeries.Len(); i++ { t, f := resSeries.GetPoint(i) nF := math.NaN() diff --git a/pkg/expr/mathexp/funcs_test.go b/pkg/expr/mathexp/funcs_test.go index 87764c79481..707fe7917ec 100644 --- a/pkg/expr/mathexp/funcs_test.go +++ b/pkg/expr/mathexp/funcs_test.go @@ -2,6 +2,7 @@ package mathexp import ( "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -46,10 +47,10 @@ func TestFunc(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(-2), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(-1), + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(-2), + }, tp{ + time.Unix(10, 0), float64Pointer(-1), }), }, }, @@ -59,10 +60,10 @@ func TestFunc(t *testing.T) { resultIs: assert.Equal, results: Results{ []Value{ - makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1), + makeSeries("", nil, tp{ + time.Unix(5, 0), float64Pointer(2), + }, tp{ + time.Unix(10, 0), float64Pointer(1), }), }, }, diff --git a/pkg/expr/mathexp/reduce.go b/pkg/expr/mathexp/reduce.go index 6591ad23cb6..f306cd24a3d 100644 --- a/pkg/expr/mathexp/reduce.go +++ b/pkg/expr/mathexp/reduce.go @@ -77,7 +77,7 @@ func (s Series) Reduce(refID, rFunc string) (Number, error) { } number := NewNumber(refID, l) var f *float64 - fVec := s.Frame.Fields[s.ValueIdx] + fVec := s.Frame.Fields[seriesTypeValIdx] floatField := Float64Field(*fVec) switch rFunc { case "sum": diff --git a/pkg/expr/mathexp/reduce_test.go b/pkg/expr/mathexp/reduce_test.go index 4a0efdce7ed..7d83c123b71 100644 --- a/pkg/expr/mathexp/reduce_test.go +++ b/pkg/expr/mathexp/reduce_test.go @@ -44,7 +44,7 @@ func TestSeriesReduce(t *testing.T) { name: "foo reduction will error", red: "foo", varToReduce: "A", - vars: aSeriesNullableTime, + vars: aSeries, errIs: require.Error, resultsIs: require.Equal, }, @@ -52,7 +52,7 @@ func TestSeriesReduce(t *testing.T) { name: "sum series", red: "sum", varToReduce: "A", - vars: aSeriesNullableTime, + vars: aSeries, errIs: require.NoError, resultsIs: require.Equal, results: Results{ @@ -169,20 +169,7 @@ func TestSeriesReduce(t *testing.T) { name: "mean series", red: "mean", varToReduce: "A", - vars: aSeriesNullableTime, - errIs: require.NoError, - resultsIs: require.Equal, - results: Results{ - []Value{ - makeNumber("", nil, float64Pointer(1.5)), - }, - }, - }, - { - name: "mean series (non-null-value)", - red: "mean", - varToReduce: "A", - vars: aSeriesNoNull, + vars: aSeries, errIs: require.NoError, resultsIs: require.Equal, results: Results{ @@ -211,10 +198,10 @@ func TestSeriesReduce(t *testing.T) { vars: Vars{ "A": Results{ []Value{ - makeSeriesNullableTime("temp", data.Labels{"host": "a"}, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1), + makeSeries("temp", data.Labels{"host": "a"}, tp{ + time.Unix(5, 0), float64Pointer(2), + }, tp{ + time.Unix(10, 0), float64Pointer(1), }), }, }, diff --git a/pkg/expr/mathexp/resample.go b/pkg/expr/mathexp/resample.go index 73257ab7401..e568adc5fbd 100644 --- a/pkg/expr/mathexp/resample.go +++ b/pkg/expr/mathexp/resample.go @@ -13,7 +13,7 @@ func (s Series) Resample(refID string, interval time.Duration, downsampler strin if newSeriesLength <= 0 { return s, fmt.Errorf("the series cannot be sampled further; the time range is shorter than the interval") } - resampled := NewSeries(refID, s.GetLabels(), s.TimeIdx, true, s.ValueIdx, true, newSeriesLength+1) + resampled := NewSeries(refID, s.GetLabels(), newSeriesLength+1) bookmark := 0 var lastSeen *float64 idx := 0 @@ -72,8 +72,7 @@ func (s Series) Resample(refID string, interval time.Duration, downsampler strin } value = tmp } - tv := t // his is required otherwise all points keep the latest timestamp; anything better? - if err := resampled.SetPoint(idx, &tv, value); err != nil { + if err := resampled.SetPoint(idx, t, value); err != nil { return resampled, err } t = t.Add(interval) diff --git a/pkg/expr/mathexp/resample_test.go b/pkg/expr/mathexp/resample_test.go index 9d01ac923bf..352d979ed6c 100644 --- a/pkg/expr/mathexp/resample_test.go +++ b/pkg/expr/mathexp/resample_test.go @@ -28,10 +28,10 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(4, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(7, 0), float64Pointer(1), }), }, { @@ -43,10 +43,10 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(11, 0), To: time.Unix(0, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(7, 0), float64Pointer(1), }), }, { @@ -58,51 +58,23 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(16, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(4, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(9, 0), float64Pointer(2), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(4, 0), float64Pointer(3), + }, tp{ + time.Unix(7, 0), float64Pointer(1), + }, tp{ + time.Unix(9, 0), float64Pointer(2), }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), nil, - }, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2.5), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1.5), - }, nullTimeTP{ - unixTimePointer(15, 0), float64Pointer(2), - }), - }, - { - name: "resample series: downsampling (mean / pad) (no-nullable)", - interval: time.Second * 5, - downsampler: "mean", - upsampler: "pad", - timeRange: backend.TimeRange{ - From: time.Unix(0, 0), - To: time.Unix(16, 0), - }, - seriesToResample: makeNoNullSeries("", nil, noNullTP{ - time.Unix(2, 0), 2, - }, noNullTP{ - time.Unix(4, 0), 3, - }, noNullTP{ - time.Unix(7, 0), 1, - }, noNullTP{ - time.Unix(9, 0), 2, - }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), nil, - }, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2.5), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1.5), - }, nullTimeTP{ - unixTimePointer(15, 0), float64Pointer(2), + series: makeSeries("", nil, tp{ + time.Unix(0, 0), nil, + }, tp{ + time.Unix(5, 0), float64Pointer(2.5), + }, tp{ + time.Unix(10, 0), float64Pointer(1.5), + }, tp{ + time.Unix(15, 0), float64Pointer(2), }), }, { @@ -114,23 +86,23 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(16, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(4, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(9, 0), float64Pointer(2), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(4, 0), float64Pointer(3), + }, tp{ + time.Unix(7, 0), float64Pointer(1), + }, tp{ + time.Unix(9, 0), float64Pointer(2), }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), nil, - }, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(15, 0), nil, + series: makeSeries("", nil, tp{ + time.Unix(0, 0), nil, + }, tp{ + time.Unix(5, 0), float64Pointer(3), + }, tp{ + time.Unix(10, 0), float64Pointer(2), + }, tp{ + time.Unix(15, 0), nil, }), }, { @@ -142,23 +114,23 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(16, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(4, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(9, 0), float64Pointer(2), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(4, 0), float64Pointer(3), + }, tp{ + time.Unix(7, 0), float64Pointer(1), + }, tp{ + time.Unix(9, 0), float64Pointer(2), }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), nil, - }, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(15, 0), nil, + series: makeSeries("", nil, tp{ + time.Unix(0, 0), nil, + }, tp{ + time.Unix(5, 0), float64Pointer(2), + }, tp{ + time.Unix(10, 0), float64Pointer(1), + }, tp{ + time.Unix(15, 0), nil, }), }, { @@ -170,23 +142,23 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(16, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(4, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(9, 0), float64Pointer(2), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(4, 0), float64Pointer(3), + }, tp{ + time.Unix(7, 0), float64Pointer(1), + }, tp{ + time.Unix(9, 0), float64Pointer(2), }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), nil, - }, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(5), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(15, 0), nil, + series: makeSeries("", nil, tp{ + time.Unix(0, 0), nil, + }, tp{ + time.Unix(5, 0), float64Pointer(5), + }, tp{ + time.Unix(10, 0), float64Pointer(3), + }, tp{ + time.Unix(15, 0), nil, }), }, { @@ -198,23 +170,23 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(16, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(4, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(9, 0), float64Pointer(2), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(4, 0), float64Pointer(3), + }, tp{ + time.Unix(7, 0), float64Pointer(1), + }, tp{ + time.Unix(9, 0), float64Pointer(2), }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), nil, - }, nullTimeTP{ - unixTimePointer(5, 0), float64Pointer(2.5), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1.5), - }, nullTimeTP{ - unixTimePointer(15, 0), nil, + series: makeSeries("", nil, tp{ + time.Unix(0, 0), nil, + }, tp{ + time.Unix(5, 0), float64Pointer(2.5), + }, tp{ + time.Unix(10, 0), float64Pointer(1.5), + }, tp{ + time.Unix(15, 0), nil, }), }, { @@ -226,23 +198,23 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(11, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(7, 0), float64Pointer(1), }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), nil, - }, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(4, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(6, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(8, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), float64Pointer(1), + series: makeSeries("", nil, tp{ + time.Unix(0, 0), nil, + }, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(4, 0), float64Pointer(2), + }, tp{ + time.Unix(6, 0), float64Pointer(2), + }, tp{ + time.Unix(8, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), float64Pointer(1), }), }, { @@ -254,23 +226,23 @@ func TestResampleSeries(t *testing.T) { From: time.Unix(0, 0), To: time.Unix(11, 0), }, - seriesToResample: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(7, 0), float64Pointer(1), + seriesToResample: makeSeries("", nil, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(7, 0), float64Pointer(1), }), - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(0, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(4, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(6, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(8, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(10, 0), nil, + series: makeSeries("", nil, tp{ + time.Unix(0, 0), float64Pointer(2), + }, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(4, 0), float64Pointer(1), + }, tp{ + time.Unix(6, 0), float64Pointer(1), + }, tp{ + time.Unix(8, 0), float64Pointer(1), + }, tp{ + time.Unix(10, 0), nil, }), }, } diff --git a/pkg/expr/mathexp/type_series.go b/pkg/expr/mathexp/type_series.go index a4146d9abf9..5633519ffda 100644 --- a/pkg/expr/mathexp/type_series.go +++ b/pkg/expr/mathexp/type_series.go @@ -9,79 +9,108 @@ import ( "github.com/grafana/grafana/pkg/expr/mathexp/parse" ) -// Series has time.Time and ...? *float64 fields. +// seriesTypeTimeIdx is the data frame field index for the Series type's Time column. +const seriesTypeTimeIdx = 0 + +// seriesTypeValIdx is the data frame field index for the Series type's Value column. +const seriesTypeValIdx = 1 + +// Series has a time.Time and a *float64 fields. type Series struct { - Frame *data.Frame - TimeIsNullable bool - TimeIdx int - ValueIsNullable bool - ValueIdx int + Frame *data.Frame // TODO: - // - Multiple Value Fields // - Value can be different number types } // SeriesFromFrame validates that the dataframe can be considered a Series type -// and populate meta information on Series about the frame. +// and mutates the frame to be in the format that additional SSE operations expect. func SeriesFromFrame(frame *data.Frame) (s Series, err error) { if len(frame.Fields) != 2 { return s, fmt.Errorf("frame must have exactly two fields to be a series, has %v", len(frame.Fields)) } - foundTime := false - foundValue := false + valueIdx := -1 + timeIdx := -1 + + timeNullable := false + valueNullable := false + +FIELDS: for i, field := range frame.Fields { switch field.Type() { case data.FieldTypeTime: - s.TimeIdx = i - foundTime = true + timeIdx = i case data.FieldTypeNullableTime: - s.TimeIsNullable = true - foundTime = true - s.TimeIdx = i + timeNullable = true + timeIdx = i case data.FieldTypeFloat64: - foundValue = true - s.ValueIdx = i + valueIdx = i case data.FieldTypeNullableFloat64: - s.ValueIsNullable = true - foundValue = true - s.ValueIdx = i + valueNullable = true + valueIdx = i default: - // Handle default case + if valueIdx != -1 && timeIdx != -1 { + break FIELDS + } } } - if !foundTime { + + if timeIdx == -1 { return s, fmt.Errorf("no time column found in frame %v", frame.Name) } - if !foundValue { + if valueIdx == -1 { return s, fmt.Errorf("no float64 value column found in frame %v", frame.Name) } + + if timeNullable { // make time not nullable if it is in the input + timeSlice := make([]time.Time, 0, frame.Fields[timeIdx].Len()) + for rowIdx := 0; rowIdx < frame.Fields[timeIdx].Len(); rowIdx++ { + val, ok := frame.At(0, rowIdx).(*time.Time) + if !ok { + return s, fmt.Errorf("unexpected time type, expected *time.Time but got %T", val) + } + if val == nil { + return s, fmt.Errorf("time series with null time stamps are not supported") + } + timeSlice = append(timeSlice, *val) + } + nF := data.NewField(frame.Fields[timeIdx].Name, nil, timeSlice) // (labels are not used on time field) + nF.Config = frame.Fields[timeIdx].Config + frame.Fields[timeIdx] = nF + } + + if !valueNullable { // make value nullable if it is not in the input + floatSlice := make([]*float64, 0, frame.Fields[valueIdx].Len()) + for rowIdx := 0; rowIdx < frame.Fields[valueIdx].Len(); rowIdx++ { + val, ok := frame.At(valueIdx, rowIdx).(float64) + if !ok { + return s, fmt.Errorf("unexpected time type, expected float64 but got %T", val) + } + floatSlice = append(floatSlice, &val) + } + nF := data.NewField(frame.Fields[valueIdx].Name, frame.Fields[valueIdx].Labels, floatSlice) + nF.Config = frame.Fields[valueIdx].Config + frame.Fields[valueIdx] = nF + } + + fields := make([]*data.Field, 2) + fields[seriesTypeTimeIdx] = frame.Fields[timeIdx] + fields[seriesTypeValIdx] = frame.Fields[valueIdx] + + frame.Fields = fields s.Frame = frame + return s, nil } // NewSeries returns a dataframe of type Series. -func NewSeries(refID string, labels data.Labels, timeIdx int, nullableTime bool, valueIdx int, nullableValue bool, size int) Series { +func NewSeries(refID string, labels data.Labels, size int) Series { fields := make([]*data.Field, 2) - - if nullableValue { - fields[valueIdx] = data.NewField(refID, labels, make([]*float64, size)) - } else { - fields[valueIdx] = data.NewField(refID, labels, make([]float64, size)) - } - - if nullableTime { - fields[timeIdx] = data.NewField("Time", nil, make([]*time.Time, size)) - } else { - fields[timeIdx] = data.NewField("Time", nil, make([]time.Time, size)) - } + fields[seriesTypeTimeIdx] = data.NewField("Time", nil, make([]time.Time, size)) + fields[seriesTypeValIdx] = data.NewField(refID, labels, make([]*float64, size)) return Series{ - Frame: data.NewFrame("", fields...), - TimeIsNullable: nullableTime, - TimeIdx: timeIdx, - ValueIsNullable: nullableValue, - ValueIdx: valueIdx, + Frame: data.NewFrame("", fields...), } } @@ -91,9 +120,9 @@ func (s Series) Type() parse.ReturnType { return parse.TypeSeriesSet } // Value returns the actual value allows it to fulfill the Value interface. func (s Series) Value() interface{} { return &s } -func (s Series) GetLabels() data.Labels { return s.Frame.Fields[s.ValueIdx].Labels } +func (s Series) GetLabels() data.Labels { return s.Frame.Fields[seriesTypeValIdx].Labels } -func (s Series) SetLabels(ls data.Labels) { s.Frame.Fields[s.ValueIdx].Labels = ls } +func (s Series) SetLabels(ls data.Labels) { s.Frame.Fields[seriesTypeValIdx].Labels = ls } func (s Series) GetName() string { return s.Frame.Name } @@ -109,73 +138,37 @@ func (s Series) SetMeta(v interface{}) { func (s Series) AsDataFrame() *data.Frame { return s.Frame } // GetPoint returns the time and value at the specified index. -func (s Series) GetPoint(pointIdx int) (*time.Time, *float64) { +func (s Series) GetPoint(pointIdx int) (time.Time, *float64) { return s.GetTime(pointIdx), s.GetValue(pointIdx) } // SetPoint sets the time and value on the corresponding vectors at the specified index. -func (s Series) SetPoint(pointIdx int, t *time.Time, f *float64) (err error) { - if s.TimeIsNullable { - s.Frame.Fields[s.TimeIdx].Set(pointIdx, t) - } else { - if t == nil { - return fmt.Errorf("can not set null time value on non-nullable time field for series name %v", s.Frame.Name) - } - s.Frame.Fields[s.TimeIdx].Set(pointIdx, *t) - } - if s.ValueIsNullable { - s.Frame.Fields[s.ValueIdx].Set(pointIdx, f) - } else { - if f == nil { - return fmt.Errorf("can not set null float value on non-nullable float field for series name %v", s.Frame.Name) - } - s.Frame.Fields[s.ValueIdx].Set(pointIdx, *f) - } +func (s Series) SetPoint(pointIdx int, t time.Time, f *float64) (err error) { + s.Frame.Fields[seriesTypeTimeIdx].Set(pointIdx, t) + s.Frame.Fields[seriesTypeValIdx].Set(pointIdx, f) return } // AppendPoint appends a point (time/value). -func (s Series) AppendPoint(pointIdx int, t *time.Time, f *float64) (err error) { - if s.TimeIsNullable { - s.Frame.Fields[s.TimeIdx].Append(t) - } else { - if t == nil { - return fmt.Errorf("can not append null time value on non-nullable time field for series name %v", s.Frame.Name) - } - s.Frame.Fields[s.TimeIdx].Append(*t) - } - if s.ValueIsNullable { - s.Frame.Fields[s.ValueIdx].Append(f) - } else { - if f == nil { - return fmt.Errorf("can not append null float value on non-nullable float field for series name %v", s.Frame.Name) - } - s.Frame.Fields[s.ValueIdx].Append(*f) - } +func (s Series) AppendPoint(pointIdx int, t time.Time, f *float64) (err error) { + s.Frame.Fields[seriesTypeTimeIdx].Append(t) + s.Frame.Fields[seriesTypeValIdx].Append(f) return } // Len returns the length of the series. func (s Series) Len() int { - return s.Frame.Fields[0].Len() + return s.Frame.Fields[seriesTypeTimeIdx].Len() } // GetTime returns the time at the specified index. -func (s Series) GetTime(pointIdx int) *time.Time { - if s.TimeIsNullable { - return s.Frame.Fields[s.TimeIdx].At(pointIdx).(*time.Time) - } - t := s.Frame.Fields[s.TimeIdx].At(pointIdx).(time.Time) - return &t +func (s Series) GetTime(pointIdx int) time.Time { + return s.Frame.Fields[seriesTypeTimeIdx].At(pointIdx).(time.Time) } // GetValue returns the float value at the specified index. func (s Series) GetValue(pointIdx int) *float64 { - if s.ValueIsNullable { - return s.Frame.Fields[s.ValueIdx].At(pointIdx).(*float64) - } - f := s.Frame.Fields[s.ValueIdx].At(pointIdx).(float64) - return &f + return s.Frame.Fields[seriesTypeValIdx].At(pointIdx).(*float64) } // SortByTime sorts the series by the time from oldest to newest. @@ -205,5 +198,5 @@ func (ss SortSeriesByTime) Swap(i, j int) { func (ss SortSeriesByTime) Less(i, j int) bool { iTimeVal := Series(ss).GetTime(i) jTimeVal := Series(ss).GetTime(j) - return iTimeVal.Before(*jTimeVal) + return iTimeVal.Before(jTimeVal) } diff --git a/pkg/expr/mathexp/types_test.go b/pkg/expr/mathexp/types_test.go index fd75aee295b..397ccdf7577 100644 --- a/pkg/expr/mathexp/types_test.go +++ b/pkg/expr/mathexp/types_test.go @@ -20,39 +20,39 @@ func TestSeriesSort(t *testing.T) { { name: "unordered series should sort by time ascending", descending: false, - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(3, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(1, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), + series: makeSeries("", nil, tp{ + time.Unix(3, 0), float64Pointer(3), + }, tp{ + time.Unix(1, 0), float64Pointer(1), + }, tp{ + time.Unix(2, 0), float64Pointer(2), }), sortedSeriesIs: assert.Equal, - sortedSeries: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(1, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(3, 0), float64Pointer(3), + sortedSeries: makeSeries("", nil, tp{ + time.Unix(1, 0), float64Pointer(1), + }, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(3, 0), float64Pointer(3), }), }, { name: "unordered series should sort by time descending", descending: true, - series: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(3, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(1, 0), float64Pointer(1), - }, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), + series: makeSeries("", nil, tp{ + time.Unix(3, 0), float64Pointer(3), + }, tp{ + time.Unix(1, 0), float64Pointer(1), + }, tp{ + time.Unix(2, 0), float64Pointer(2), }), sortedSeriesIs: assert.Equal, - sortedSeries: makeSeriesNullableTime("", nil, nullTimeTP{ - unixTimePointer(3, 0), float64Pointer(3), - }, nullTimeTP{ - unixTimePointer(2, 0), float64Pointer(2), - }, nullTimeTP{ - unixTimePointer(1, 0), float64Pointer(1), + sortedSeries: makeSeries("", nil, tp{ + time.Unix(3, 0), float64Pointer(3), + }, tp{ + time.Unix(2, 0), float64Pointer(2), + }, tp{ + time.Unix(1, 0), float64Pointer(1), }), }, } @@ -89,22 +89,18 @@ func TestSeriesFromFrame(t *testing.T) { Name: "test", Fields: []*data.Field{ data.NewField("time", nil, []time.Time{}), - data.NewField("value", nil, []float64{}), + data.NewField("value", nil, []*float64{}), }, }, - TimeIdx: 0, - TimeIsNullable: false, - ValueIdx: 1, - ValueIsNullable: false, }, }, { - name: "[]*float, []*time frame should convert", + name: "[]time, []*float frame should convert", frame: &data.Frame{ Name: "test", Fields: []*data.Field{ + data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), data.NewField("value", nil, []*float64{float64Pointer(5)}), - data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), }, }, errIs: assert.NoError, @@ -113,14 +109,31 @@ func TestSeriesFromFrame(t *testing.T) { Frame: &data.Frame{ Name: "test", Fields: []*data.Field{ + data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), + data.NewField("value", nil, []*float64{float64Pointer(5)}), + }, + }, + }, + }, + { + name: "[]*float, []time frame should convert", + frame: &data.Frame{ + Name: "test", + Fields: []*data.Field{ + data.NewField("value", nil, []*float64{float64Pointer(5)}), + data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), + }, + }, + errIs: assert.NoError, + Is: assert.Equal, + Series: Series{ + Frame: &data.Frame{ + Name: "test", + Fields: []*data.Field{ + data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), data.NewField("value", nil, []*float64{float64Pointer(5)}), - data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), }, }, - TimeIdx: 1, - TimeIsNullable: true, - ValueIdx: 0, - ValueIsNullable: true, }, }, { diff --git a/pkg/expr/mathexp/union_test.go b/pkg/expr/mathexp/union_test.go index 56339f46489..f46f7672185 100644 --- a/pkg/expr/mathexp/union_test.go +++ b/pkg/expr/mathexp/union_test.go @@ -19,20 +19,20 @@ func Test_union(t *testing.T) { name: "equal tags single union", aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1"}), + makeSeries("a", data.Labels{"id": "1"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "1"}), + makeSeries("b", data.Labels{"id": "1"}), }, }, unionsAre: assert.EqualValues, unions: []*Union{ { Labels: data.Labels{"id": "1"}, - A: makeSeriesNullableTime("a", data.Labels{"id": "1"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "1"}), + A: makeSeries("a", data.Labels{"id": "1"}), + B: makeSeries("b", data.Labels{"id": "1"}), }, }, }, @@ -40,19 +40,19 @@ func Test_union(t *testing.T) { name: "equal tags keys with no matching values will result in a union when len(A) == 1 && len(B) == 1", aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1"}), + makeSeries("a", data.Labels{"id": "1"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "2"}), + makeSeries("b", data.Labels{"id": "2"}), }, }, unionsAre: assert.EqualValues, unions: []*Union{ { - A: makeSeriesNullableTime("a", data.Labels{"id": "1"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "2"}), + A: makeSeries("a", data.Labels{"id": "1"}), + B: makeSeries("b", data.Labels{"id": "2"}), }, }, }, @@ -60,13 +60,13 @@ func Test_union(t *testing.T) { name: "equal tags keys with no matching values will result in no unions when len(A) != 1 && len(B) != 1", aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1"}), - makeSeriesNullableTime("q", data.Labels{"id": "3"}), + makeSeries("a", data.Labels{"id": "1"}), + makeSeries("q", data.Labels{"id": "3"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "2"}), + makeSeries("b", data.Labels{"id": "2"}), }, }, unionsAre: assert.EqualValues, @@ -83,13 +83,13 @@ func Test_union(t *testing.T) { name: "incompatible tags of different length with will result in no unions when len(A) != 1 && len(B) != 1", aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"ID": "1"}), - makeSeriesNullableTime("q", data.Labels{"ID": "3"}), + makeSeries("a", data.Labels{"ID": "1"}), + makeSeries("q", data.Labels{"ID": "3"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "red snapper"}), + makeSeries("b", data.Labels{"id": "1", "fish": "red snapper"}), }, }, unionsAre: assert.EqualValues, @@ -99,20 +99,20 @@ func Test_union(t *testing.T) { name: "A is subset of B results in single union with Labels of B", aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1"}), + makeSeries("a", data.Labels{"id": "1"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), + makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), }, }, unionsAre: assert.EqualValues, unions: []*Union{ { Labels: data.Labels{"id": "1", "fish": "herring"}, // Union gets the labels that is not the subset - A: makeSeriesNullableTime("a", data.Labels{"id": "1"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), + A: makeSeries("a", data.Labels{"id": "1"}), + B: makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), }, }, }, @@ -120,20 +120,20 @@ func Test_union(t *testing.T) { name: "B is subset of A results in single union with Labels of A", aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1", "fish": "herring"}), + makeSeries("a", data.Labels{"id": "1", "fish": "herring"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "1"}), + makeSeries("b", data.Labels{"id": "1"}), }, }, unionsAre: assert.EqualValues, unions: []*Union{ { Labels: data.Labels{"id": "1", "fish": "herring"}, // Union gets the labels that is not the subset - A: makeSeriesNullableTime("a", data.Labels{"id": "1", "fish": "herring"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "1"}), + A: makeSeries("a", data.Labels{"id": "1", "fish": "herring"}), + B: makeSeries("b", data.Labels{"id": "1"}), }, }, }, @@ -141,26 +141,26 @@ func Test_union(t *testing.T) { name: "single valued A is subset of many valued B, results in many union with Labels of B", aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1"}), + makeSeries("a", data.Labels{"id": "1"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), - makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "red snapper"}), + makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), + makeSeries("b", data.Labels{"id": "1", "fish": "red snapper"}), }, }, unionsAre: assert.EqualValues, unions: []*Union{ { Labels: data.Labels{"id": "1", "fish": "herring"}, - A: makeSeriesNullableTime("a", data.Labels{"id": "1"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), + A: makeSeries("a", data.Labels{"id": "1"}), + B: makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), }, { Labels: data.Labels{"id": "1", "fish": "red snapper"}, - A: makeSeriesNullableTime("a", data.Labels{"id": "1"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "red snapper"}), + A: makeSeries("a", data.Labels{"id": "1"}), + B: makeSeries("b", data.Labels{"id": "1", "fish": "red snapper"}), }, }, }, @@ -170,32 +170,32 @@ func Test_union(t *testing.T) { // be uniquely identifiable. aResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1"}), - makeSeriesNullableTime("aa", data.Labels{"id": "1", "fish": "herring"}), + makeSeries("a", data.Labels{"id": "1"}), + makeSeries("aa", data.Labels{"id": "1", "fish": "herring"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), - makeSeriesNullableTime("bb", data.Labels{"id": "1", "fish": "red snapper"}), + makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), + makeSeries("bb", data.Labels{"id": "1", "fish": "red snapper"}), }, }, unionsAre: assert.EqualValues, unions: []*Union{ { Labels: data.Labels{"id": "1", "fish": "herring"}, - A: makeSeriesNullableTime("a", data.Labels{"id": "1"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), + A: makeSeries("a", data.Labels{"id": "1"}), + B: makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), }, { Labels: data.Labels{"id": "1", "fish": "red snapper"}, - A: makeSeriesNullableTime("a", data.Labels{"id": "1"}), - B: makeSeriesNullableTime("bb", data.Labels{"id": "1", "fish": "red snapper"}), + A: makeSeries("a", data.Labels{"id": "1"}), + B: makeSeries("bb", data.Labels{"id": "1", "fish": "red snapper"}), }, { Labels: data.Labels{"id": "1", "fish": "herring"}, - A: makeSeriesNullableTime("aa", data.Labels{"id": "1", "fish": "herring"}), - B: makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), + A: makeSeries("aa", data.Labels{"id": "1", "fish": "herring"}), + B: makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), }, }, }, @@ -205,32 +205,32 @@ func Test_union(t *testing.T) { // be uniquely identifiable. aResults: Results{ Values: Values{ - makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), - makeSeriesNullableTime("bb", data.Labels{"id": "1", "fish": "red snapper"}), + makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), + makeSeries("bb", data.Labels{"id": "1", "fish": "red snapper"}), }, }, bResults: Results{ Values: Values{ - makeSeriesNullableTime("a", data.Labels{"id": "1"}), - makeSeriesNullableTime("aa", data.Labels{"id": "1", "fish": "herring"}), + makeSeries("a", data.Labels{"id": "1"}), + makeSeries("aa", data.Labels{"id": "1", "fish": "herring"}), }, }, unionsAre: assert.EqualValues, unions: []*Union{ { Labels: data.Labels{"id": "1", "fish": "herring"}, - A: makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), - B: makeSeriesNullableTime("a", data.Labels{"id": "1"}), + A: makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), + B: makeSeries("a", data.Labels{"id": "1"}), }, { Labels: data.Labels{"id": "1", "fish": "herring"}, - A: makeSeriesNullableTime("b", data.Labels{"id": "1", "fish": "herring"}), - B: makeSeriesNullableTime("aa", data.Labels{"id": "1", "fish": "herring"}), + A: makeSeries("b", data.Labels{"id": "1", "fish": "herring"}), + B: makeSeries("aa", data.Labels{"id": "1", "fish": "herring"}), }, { Labels: data.Labels{"id": "1", "fish": "red snapper"}, - A: makeSeriesNullableTime("bb", data.Labels{"id": "1", "fish": "red snapper"}), - B: makeSeriesNullableTime("a", data.Labels{"id": "1"}), + A: makeSeries("bb", data.Labels{"id": "1", "fish": "red snapper"}), + B: makeSeries("a", data.Labels{"id": "1"}), }, }, }, diff --git a/pkg/expr/service_test.go b/pkg/expr/service_test.go index 6b11d35346d..cbf3076b9e6 100644 --- a/pkg/expr/service_test.go +++ b/pkg/expr/service_test.go @@ -22,7 +22,7 @@ import ( // nolint:staticcheck // plugins.DataPlugin deprecated func TestService(t *testing.T) { dsDF := data.NewFrame("test", - data.NewField("time", nil, []*time.Time{utp(1)}), + data.NewField("time", nil, []time.Time{time.Unix(1, 0)}), data.NewField("value", nil, []*float64{fp(2)})) dataSvc := tsdb.NewService() @@ -61,7 +61,7 @@ func TestService(t *testing.T) { require.NoError(t, err) bDF := data.NewFrame("", - data.NewField("Time", nil, []*time.Time{utp(1)}), + data.NewField("Time", nil, []time.Time{time.Unix(1, 0)}), data.NewField("B", nil, []*float64{fp(4)})) bDF.RefID = "B" @@ -90,11 +90,6 @@ func TestService(t *testing.T) { } } -func utp(sec int64) *time.Time { - t := time.Unix(sec, 0) - return &t -} - func fp(f float64) *float64 { return &f }