From 3bd2bdcebbe50aec3cb7de69e3b3b2bce00ef4da Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Wed, 29 Jun 2022 18:08:42 -0500 Subject: [PATCH] DataFrame: more thorough detection of unsorted values (#51602) --- .betterer.results | 3 -- .../transformers/joinDataFrames.test.ts | 14 +++++ .../transformers/joinDataFrames.ts | 52 ++++++++++++------- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/.betterer.results b/.betterer.results index 91a50fdcaff..d5ce121e6fb 100644 --- a/.betterer.results +++ b/.betterer.results @@ -625,9 +625,6 @@ exports[`better eslint`] = { [315, 14, 3, "Unexpected any. Specify a different type.", "193409811"], [315, 22, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "packages/grafana-data/src/transformations/transformers/joinDataFrames.ts:1554585514": [ - [340, 13, 3, "Unexpected any. Specify a different type.", "193409811"] - ], "packages/grafana-data/src/transformations/transformers/labelsToFields.test.ts:1352052528": [ [393, 13, 3, "Unexpected any. Specify a different type.", "193409811"] ], diff --git a/packages/grafana-data/src/transformations/transformers/joinDataFrames.test.ts b/packages/grafana-data/src/transformations/transformers/joinDataFrames.test.ts index 2f78fa5c901..4fb552b0f26 100644 --- a/packages/grafana-data/src/transformations/transformers/joinDataFrames.test.ts +++ b/packages/grafana-data/src/transformations/transformers/joinDataFrames.test.ts @@ -294,5 +294,19 @@ describe('align frames', () => { expect(isLikelyAscendingVector(new ArrayVector([7, 6, null]))).toBeFalsy(); expect(isLikelyAscendingVector(new ArrayVector([7, 8, 6]))).toBeFalsy(); }); + + it('ascending first/last', () => { + expect(isLikelyAscendingVector(new ArrayVector([10, 20, 30, 5, 15, 7, 43, 29, 11]), 3)).toBeFalsy(); + expect( + isLikelyAscendingVector(new ArrayVector([null, 10, 20, 30, 5, null, 15, 7, 43, 29, 11, null]), 3) + ).toBeFalsy(); + }); + + it('null stuffs', () => { + expect(isLikelyAscendingVector(new ArrayVector([null, null, 1]), 3)).toBeTruthy(); + expect(isLikelyAscendingVector(new ArrayVector([1, null, null]), 3)).toBeTruthy(); + expect(isLikelyAscendingVector(new ArrayVector([null, null, null]), 3)).toBeTruthy(); + expect(isLikelyAscendingVector(new ArrayVector([null, 1, null]), 3)).toBeTruthy(); + }); }); }); diff --git a/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts b/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts index 977c6fb2bb8..18b569e0016 100644 --- a/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts +++ b/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts @@ -335,34 +335,46 @@ export function join(tables: AlignedData[], nullModes?: number[][]) { return data; } -// Quick test if the first and last points look to be ascending +// Test a few samples to see if the values are ascending // Only exported for tests -export function isLikelyAscendingVector(data: Vector): boolean { - let first: any = undefined; +export function isLikelyAscendingVector(data: Vector, samples = 50) { + const len = data.length; - for (let idx = 0; idx < data.length; idx++) { - const v = data.get(idx); - if (v != null) { - if (first != null) { - if (first > v) { - return false; // descending - } - break; - } - first = v; - } + // empty or single value + if (len <= 1) { + return true; + } + + // skip leading & trailing nullish + let firstIdx = 0; + let lastIdx = len - 1; + + while (firstIdx <= lastIdx && data.get(firstIdx) == null) { + firstIdx++; } - let idx = data.length - 1; - while (idx >= 0) { - const v = data.get(idx--); + while (lastIdx >= firstIdx && data.get(lastIdx) == null) { + lastIdx--; + } + + // all nullish or one value surrounded by nullish + if (lastIdx <= firstIdx) { + return true; + } + + const stride = Math.max(1, Math.floor((lastIdx - firstIdx + 1) / samples)); + + for (let prevVal = data.get(firstIdx), i = firstIdx + stride; i <= lastIdx; i += stride) { + const v = data.get(i); + if (v != null) { - if (first > v) { + if (v <= prevVal) { return false; } - return true; + + prevVal = v; } } - return true; // only one non-null point + return true; }