DataFrame: Deprecate MutableDataFrame (#67569)
This commit is contained in:
@@ -10,10 +10,16 @@ import { guessFieldTypeFromValue, guessFieldTypeForField, toDataFrameDTO } from
|
||||
/** @deprecated */
|
||||
export type MutableField<T = any> = Field<T>;
|
||||
|
||||
/** @deprecated */
|
||||
type MutableVectorCreator = (buffer?: any[]) => any[];
|
||||
|
||||
export const MISSING_VALUE = undefined; // Treated as connected in new graph panel
|
||||
|
||||
/**
|
||||
* MutableDataFrame is a complex wrapper around the DataFrame interface
|
||||
*
|
||||
* @deprecated use standard DataFrame, or create one with PartialDataFrame
|
||||
*/
|
||||
export class MutableDataFrame<T = any> extends FunctionalVector<T> implements DataFrame {
|
||||
name?: string;
|
||||
refId?: string;
|
||||
|
||||
@@ -2,8 +2,8 @@ import { dateTime } from '../datetime/moment_wrapper';
|
||||
import { DataFrameDTO, FieldType, TableData, TimeSeries } from '../types/index';
|
||||
|
||||
import { ArrayDataFrame } from './ArrayDataFrame';
|
||||
import { MutableDataFrame } from './MutableDataFrame';
|
||||
import {
|
||||
createDataFrame,
|
||||
guessFieldTypeFromValue,
|
||||
guessFieldTypes,
|
||||
isDataFrame,
|
||||
@@ -130,7 +130,7 @@ describe('toDataFrame', () => {
|
||||
});
|
||||
|
||||
it('Guess Column Types from series', () => {
|
||||
const series = new MutableDataFrame({
|
||||
const series = createDataFrame({
|
||||
fields: [
|
||||
{ name: 'A (number)', values: [123, null] },
|
||||
{ name: 'B (strings)', values: [null, 'Hello'] },
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
|
||||
import { arrayToDataFrame } from './ArrayDataFrame';
|
||||
import { dataFrameFromJSON } from './DataFrameJSON';
|
||||
import { MutableDataFrame } from './MutableDataFrame';
|
||||
|
||||
function convertTableToDataFrame(table: TableData): DataFrame {
|
||||
const fields = table.columns.map((c) => {
|
||||
@@ -315,7 +314,7 @@ export function toDataFrame(data: any): DataFrame {
|
||||
}
|
||||
|
||||
// This will convert the array values into Vectors
|
||||
return new MutableDataFrame(data as DataFrameDTO);
|
||||
return createDataFrame(data as DataFrameDTO);
|
||||
}
|
||||
|
||||
// Handle legacy docs/json type
|
||||
@@ -567,3 +566,35 @@ export function preProcessPanelData(data: PanelData, lastResult?: PanelData): Pa
|
||||
timings: { dataProcessingTime: STOPTIME - STARTTIME },
|
||||
};
|
||||
}
|
||||
|
||||
export interface PartialDataFrame extends Omit<DataFrame, 'fields' | 'length'> {
|
||||
fields: Array<Partial<Field>>;
|
||||
}
|
||||
|
||||
export function createDataFrame(input: PartialDataFrame): DataFrame {
|
||||
let length = 0;
|
||||
const fields = input.fields.map((p, idx) => {
|
||||
const { state, ...field } = p;
|
||||
if (!field.name) {
|
||||
field.name = `Field ${idx + 1}`;
|
||||
}
|
||||
if (!field.config) {
|
||||
field.config = {};
|
||||
}
|
||||
if (!field.values) {
|
||||
field.values = new Array(length);
|
||||
} else if (field.values.length > length) {
|
||||
length = field.values.length;
|
||||
}
|
||||
if (!field.type) {
|
||||
field.type = guessFieldTypeForField(field as Field) ?? FieldType.other;
|
||||
}
|
||||
return field as Field;
|
||||
});
|
||||
|
||||
return {
|
||||
...input,
|
||||
fields,
|
||||
length,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -508,8 +508,25 @@ function createEmptyDisplayOptions(extend = {}): GetFieldDisplayValuesOptions {
|
||||
}
|
||||
|
||||
function createDisplayOptions(extend: Partial<GetFieldDisplayValuesOptions> = {}): GetFieldDisplayValuesOptions {
|
||||
const options: GetFieldDisplayValuesOptions = {
|
||||
data: [
|
||||
const options = merge(
|
||||
{
|
||||
replaceVariables: (value: string) => {
|
||||
return value;
|
||||
},
|
||||
reduceOptions: {
|
||||
calcs: [],
|
||||
},
|
||||
fieldConfig: {
|
||||
overrides: [],
|
||||
defaults: {},
|
||||
},
|
||||
theme: createTheme(),
|
||||
},
|
||||
extend
|
||||
);
|
||||
|
||||
if (!options.data?.length) {
|
||||
options.data = [
|
||||
toDataFrame({
|
||||
name: 'Series Name',
|
||||
fields: [
|
||||
@@ -518,21 +535,9 @@ function createDisplayOptions(extend: Partial<GetFieldDisplayValuesOptions> = {}
|
||||
{ name: 'Field 3', values: [2, 4, 6] },
|
||||
],
|
||||
}),
|
||||
],
|
||||
replaceVariables: (value: string) => {
|
||||
return value;
|
||||
},
|
||||
reduceOptions: {
|
||||
calcs: [],
|
||||
},
|
||||
fieldConfig: {
|
||||
overrides: [],
|
||||
defaults: {},
|
||||
},
|
||||
theme: createTheme(),
|
||||
};
|
||||
|
||||
return merge(options, extend);
|
||||
];
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
describe('fixCellTemplateExpressions', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ArrayDataFrame, MutableDataFrame, toDataFrame } from '../dataframe';
|
||||
import { ArrayDataFrame, createDataFrame, toDataFrame } from '../dataframe';
|
||||
import { rangeUtil } from '../datetime';
|
||||
import { createTheme } from '../themes';
|
||||
import { FieldMatcherID } from '../transformations';
|
||||
@@ -177,11 +177,11 @@ describe('applyFieldOverrides', () => {
|
||||
};
|
||||
|
||||
describe('given multiple data frames', () => {
|
||||
const f0 = new MutableDataFrame({
|
||||
const f0 = createDataFrame({
|
||||
name: 'A',
|
||||
fields: [{ name: 'message', type: FieldType.string, values: [10, 20] }],
|
||||
});
|
||||
const f1 = new MutableDataFrame({
|
||||
const f1 = createDataFrame({
|
||||
name: 'B',
|
||||
fields: [{ name: 'info', type: FieldType.string, values: [10, 20] }],
|
||||
});
|
||||
@@ -676,7 +676,7 @@ describe('getLinksSupplier', () => {
|
||||
getTimeRangeForUrl: () => ({ from: 'now-7d', to: 'now' }),
|
||||
});
|
||||
|
||||
const f0 = new MutableDataFrame({
|
||||
const f0 = createDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
{
|
||||
@@ -712,7 +712,7 @@ describe('getLinksSupplier', () => {
|
||||
});
|
||||
|
||||
const datasourceUid = '1234';
|
||||
const f0 = new MutableDataFrame({
|
||||
const f0 = createDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
{
|
||||
@@ -766,7 +766,7 @@ describe('getLinksSupplier', () => {
|
||||
|
||||
const datasourceUid = '1234';
|
||||
const range = rangeUtil.relativeToTimeRange({ from: 600, to: 0 });
|
||||
const f0 = new MutableDataFrame({
|
||||
const f0 = createDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
{
|
||||
@@ -827,7 +827,7 @@ describe('getLinksSupplier', () => {
|
||||
it('handles link click handlers', () => {
|
||||
const onClickSpy = jest.fn();
|
||||
const replaceSpy = jest.fn();
|
||||
const f0 = new MutableDataFrame({
|
||||
const f0 = createDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
{
|
||||
@@ -867,7 +867,7 @@ describe('getLinksSupplier', () => {
|
||||
const replaceSpy = jest.fn().mockReturnValue('url interpolated 10');
|
||||
const onBuildUrlSpy = jest.fn();
|
||||
|
||||
const f0 = new MutableDataFrame({
|
||||
const f0 = createDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MutableDataFrame, toDataFrame } from '../dataframe';
|
||||
import { createDataFrame, toDataFrame } from '../dataframe';
|
||||
import { createTheme } from '../themes';
|
||||
|
||||
import { applyFieldOverrides } from './fieldOverrides';
|
||||
@@ -85,7 +85,7 @@ describe('getFieldDisplayValuesProxy', () => {
|
||||
|
||||
it('should use default display processor if display is not defined', () => {
|
||||
const p = getFieldDisplayValuesProxy({
|
||||
frame: new MutableDataFrame({ fields: [{ name: 'test', values: [1, 2] }] }),
|
||||
frame: createDataFrame({ fields: [{ name: 'test', values: [1, 2] }] }),
|
||||
rowIndex: 0,
|
||||
});
|
||||
expect(p.test.text).toBe('1');
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { difference } from 'lodash';
|
||||
|
||||
import { MutableDataFrame } from '../dataframe/MutableDataFrame';
|
||||
import { guessFieldTypeFromValue } from '../dataframe/processDataFrame';
|
||||
import { createDataFrame, guessFieldTypeFromValue } from '../dataframe/processDataFrame';
|
||||
import { Field, FieldType } from '../types/index';
|
||||
|
||||
import { fieldReducers, ReducerID, reduceField } from './fieldReducer';
|
||||
@@ -24,7 +23,7 @@ function createField<T>(name: string, values?: T[], type?: FieldType): Field<T>
|
||||
}
|
||||
|
||||
describe('Stats Calculators', () => {
|
||||
const basicTable = new MutableDataFrame({
|
||||
const basicTable = createDataFrame({
|
||||
fields: [
|
||||
{ name: 'a', values: [10, 20] },
|
||||
{ name: 'b', values: [20, 30] },
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { MutableDataFrame } from '../../dataframe';
|
||||
import { getFieldDisplayName } from '../../field/fieldState';
|
||||
import { DataFrame, DataTransformerInfo, Field, FieldType, SpecialValue } from '../../types';
|
||||
import { fieldMatchers } from '../matchers';
|
||||
@@ -75,13 +74,14 @@ export const groupingToMatrixTransformer: DataTransformerInfo<GroupingToMatrixTr
|
||||
matrixValues[columnName][rowName] = value;
|
||||
}
|
||||
|
||||
const resultFrame = new MutableDataFrame();
|
||||
|
||||
resultFrame.addField({
|
||||
name: rowColumnField,
|
||||
values: rowValues,
|
||||
type: FieldType.string,
|
||||
});
|
||||
const fields: Field[] = [
|
||||
{
|
||||
name: rowColumnField,
|
||||
values: rowValues,
|
||||
type: FieldType.string,
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
for (const columnName of columnValues) {
|
||||
let values = [];
|
||||
@@ -98,7 +98,7 @@ export const groupingToMatrixTransformer: DataTransformerInfo<GroupingToMatrixTr
|
||||
valueField.config = { ...valueField.config, displayNameFromDS: undefined };
|
||||
}
|
||||
|
||||
resultFrame.addField({
|
||||
fields.push({
|
||||
name: columnName.toString(),
|
||||
values: values,
|
||||
config: valueField.config,
|
||||
@@ -106,7 +106,12 @@ export const groupingToMatrixTransformer: DataTransformerInfo<GroupingToMatrixTr
|
||||
});
|
||||
}
|
||||
|
||||
return [resultFrame];
|
||||
return [
|
||||
{
|
||||
fields,
|
||||
length: rowValues.length,
|
||||
},
|
||||
];
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { MutableDataFrame } from '../dataframe/MutableDataFrame';
|
||||
import { createDataFrame } from '../dataframe';
|
||||
import { dateTime } from '../datetime/moment_wrapper';
|
||||
import { TimeRange } from '../types/time';
|
||||
|
||||
import { getFlotPairs, getFlotPairsConstant } from './flotPairs';
|
||||
|
||||
describe('getFlotPairs', () => {
|
||||
const series = new MutableDataFrame({
|
||||
const series = createDataFrame({
|
||||
fields: [
|
||||
{ name: 'a', values: [1, 2, 3] },
|
||||
{ name: 'b', values: [100, 200, 300] },
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
DataSourceInstanceSettings,
|
||||
DataSourceJsonData,
|
||||
DataSourceRef,
|
||||
MutableDataFrame,
|
||||
createDataFrame,
|
||||
} from '@grafana/data';
|
||||
|
||||
import {
|
||||
@@ -240,10 +240,12 @@ describe('DataSourceWithBackend', () => {
|
||||
let obs = toStreamingDataResponse(rsp, request, standardStreamOptionsProvider);
|
||||
expect(obs).toBeDefined();
|
||||
|
||||
let frame = new MutableDataFrame();
|
||||
frame.meta = {
|
||||
channel: 'a/b/c',
|
||||
};
|
||||
let frame = createDataFrame({
|
||||
meta: {
|
||||
channel: 'a/b/c',
|
||||
},
|
||||
fields: [],
|
||||
});
|
||||
rsp.data = [frame];
|
||||
obs = toStreamingDataResponse(rsp, request, standardStreamOptionsProvider);
|
||||
expect(obs).toBeDefined();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FieldType, MutableDataFrame } from '@grafana/data';
|
||||
import { FieldType, createDataFrame } from '@grafana/data';
|
||||
|
||||
import { applyNullInsertThreshold } from './nullInsertThreshold';
|
||||
|
||||
@@ -48,7 +48,7 @@ function genFrame() {
|
||||
|
||||
describe('nullInsertThreshold Transformer', () => {
|
||||
test('should insert nulls at +threshold between adjacent > threshold: 1', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, values: [1, 3, 10] },
|
||||
@@ -65,7 +65,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should insert nulls at +threshold between adjacent > threshold: 2', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, values: [5, 7, 11] },
|
||||
@@ -82,7 +82,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should insert nulls at +interval between adjacent > interval: 1', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1, 3, 10] },
|
||||
@@ -99,7 +99,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should insert leading null at beginning +interval when timeRange.from.valueOf() exceeds threshold', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [4, 6, 13] },
|
||||
@@ -154,7 +154,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
|
||||
// this tests that intervals at 24hr but starting not at 12am UTC are not always snapped to 12am UTC
|
||||
test('should insert leading null at beginning +interval when timeRange.from.valueOf() exceeds threshold 11PM UTC', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{
|
||||
@@ -181,7 +181,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should insert trailing null at end +interval when timeRange.to.valueOf() exceeds threshold', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1, 3, 10] },
|
||||
@@ -197,7 +197,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
expect(result.fields[2].values).toEqual(['a', null, 'b', null, null, null, null, null, null, 'c', null, null]);
|
||||
|
||||
// should work for frames with 1 datapoint
|
||||
const df2 = new MutableDataFrame({
|
||||
const df2 = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1] },
|
||||
@@ -216,7 +216,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should not insert trailing null at end +interval when timeRange.to.valueOf() equals threshold', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1] },
|
||||
@@ -234,7 +234,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
|
||||
// TODO: make this work
|
||||
test.skip('should insert nulls at +threshold (when defined) instead of +interval', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 2 }, values: [5, 7, 11] },
|
||||
@@ -251,7 +251,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should noop on 0 datapoints', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [] },
|
||||
@@ -265,7 +265,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should noop on invalid threshold', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, values: [1, 2, 4] },
|
||||
@@ -279,7 +279,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should noop on invalid interval', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: -1 }, values: [1, 2, 4] },
|
||||
@@ -293,7 +293,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should noop when no missing steps', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1, 2, 3] },
|
||||
@@ -307,7 +307,7 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
});
|
||||
|
||||
test('should noop when refFieldName not found', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1, 2, 5] },
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { FieldType, MutableDataFrame } from '@grafana/data';
|
||||
import { FieldType, createDataFrame } from '@grafana/data';
|
||||
|
||||
import { applyNullInsertThreshold } from './nullInsertThreshold';
|
||||
import { nullToValue } from './nullToValue';
|
||||
|
||||
describe('nullToValue Transformer', () => {
|
||||
test('should change all nulls to configured zero value', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, values: [1, 3, 10] },
|
||||
@@ -32,7 +32,7 @@ describe('nullToValue Transformer', () => {
|
||||
});
|
||||
|
||||
test('should change all nulls to configured positive value', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, values: [5, 7, 11] },
|
||||
@@ -59,7 +59,7 @@ describe('nullToValue Transformer', () => {
|
||||
});
|
||||
|
||||
test('should change all nulls to configured negative value', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1, 3, 10] },
|
||||
@@ -76,7 +76,7 @@ describe('nullToValue Transformer', () => {
|
||||
});
|
||||
|
||||
test('should have no effect without nulls', () => {
|
||||
const df = new MutableDataFrame({
|
||||
const df = createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1, 2, 3] },
|
||||
|
||||
Reference in New Issue
Block a user