Timeseries to table transformation: Improve time series detection (#77841)

* Improve time series detection

* Prettier

* Add test

* Update packages/grafana-data/src/dataframe/utils.ts

Co-authored-by: Jev Forsberg <46619047+baldm0mma@users.noreply.github.com>

* Ensure correct time field support and set maximum size

* Look at each field to see if they are time series

* Add further tests

* Prettier

---------

Co-authored-by: Jev Forsberg <46619047+baldm0mma@users.noreply.github.com>
This commit is contained in:
Kyle Cunningham
2023-11-17 14:52:26 -06:00
committed by GitHub
co-authored by Jev Forsberg
parent 3d696b3504
commit b9fa9d4a11
5 changed files with 180 additions and 36 deletions
+1 -1
View File
@@ -7,5 +7,5 @@ export * from './dimensions';
export * from './ArrayDataFrame';
export * from './DataFrameJSON';
export * from './frameComparisons';
export { anySeriesWithTimeField, isTimeSeriesFrame, isTimeSeriesFrames } from './utils';
export { anySeriesWithTimeField, isTimeSeriesFrame, isTimeSeriesFrames, isTimeSeriesField } from './utils';
export { StreamingDataFrame, StreamingFrameAction, type StreamingFrameOptions, closestIdx } from './StreamingDataFrame';
+51 -5
View File
@@ -1,24 +1,70 @@
import { DataFrame, FieldType } from '../types/dataFrame';
import { DataFrame, Field, FieldType } from '../types/dataFrame';
import { getTimeField } from './processDataFrame';
const MAX_TIME_COMPARISONS = 100;
export function isTimeSeriesFrame(frame: DataFrame) {
// If we have less than two frames we can't have a timeseries
if (frame.fields.length < 2) {
return false;
}
// In order to have a time series we need a time field
// and at least one number field
const timeField = frame.fields.find((field) => field.type === FieldType.time);
// Find a number field, as long as we have any number field this should work
const numberField = frame.fields.find((field) => field.type === FieldType.number);
return timeField !== undefined && numberField !== undefined;
// There are certain query types in which we will
// get times but they will be the same or not be
// in increasing order. To have a time-series the
// times need to be ordered from past to present
let timeFieldFound = false;
for (const field of frame.fields) {
if (isTimeSeriesField(field)) {
timeFieldFound = true;
break;
}
}
return timeFieldFound && numberField !== undefined;
}
export function isTimeSeriesFrames(data: DataFrame[]) {
return !data.find((frame) => !isTimeSeriesFrame(frame));
}
/**
* Determines if a field is a time field in ascending
* order within the sampling range specified by
* MAX_TIME_COMPARISONS
*
* @param field
* @returns boolean
*/
export function isTimeSeriesField(field: Field) {
if (field.type !== FieldType.time) {
return false;
}
let greatestTime: number | null = null;
let testWindow = field.values.length > MAX_TIME_COMPARISONS ? MAX_TIME_COMPARISONS : field.values.length;
// Test up to the test window number of values
for (let i = 0; i < testWindow; i++) {
const time = field.values[i];
// Check to see if the current time is greater than
// the last time. If we get to the end then we
// have a time series otherwise we return false
if (greatestTime === null || (time !== null && time > greatestTime)) {
greatestTime = time;
} else {
return false;
}
}
return true;
}
/**
* Indicates if there is any time field in the array of data frames
* @param data