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:
co-authored by
Jev Forsberg
parent
3d696b3504
commit
b9fa9d4a11
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user