mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Transformations: Add field from calc - avoid frame joining in some cases (#93602)
* Transformations: Add field from calc - avoid frame joining in some cases * Add test for multiple query, 1 field, replace all * omit frames that had no binary ops performed on them --------- Co-authored-by: drew08t <drew08@gmail.com>
This commit is contained in:
parent
2ffb88b0ee
commit
f7fcc14f69
@ -41,6 +41,15 @@ describe('calculateField transformer w/ timeseries', () => {
|
|||||||
mockTransformationsRegistry([calculateFieldTransformer]);
|
mockTransformationsRegistry([calculateFieldTransformer]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
seriesA.fields.forEach((f) => {
|
||||||
|
delete f.state;
|
||||||
|
});
|
||||||
|
seriesBC.fields.forEach((f) => {
|
||||||
|
delete f.state;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('will filter and alias', async () => {
|
it('will filter and alias', async () => {
|
||||||
const cfg = {
|
const cfg = {
|
||||||
id: DataTransformerID.calculateField,
|
id: DataTransformerID.calculateField,
|
||||||
@ -198,6 +207,56 @@ describe('calculateField transformer w/ timeseries', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('multiple queries + field + static number', async () => {
|
||||||
|
const cfg = {
|
||||||
|
id: DataTransformerID.calculateField,
|
||||||
|
options: {
|
||||||
|
mode: CalculateFieldMode.BinaryOperation,
|
||||||
|
binary: {
|
||||||
|
left: 'B',
|
||||||
|
operator: BinaryOperationID.Add,
|
||||||
|
right: '2',
|
||||||
|
},
|
||||||
|
replaceFields: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith((received) => {
|
||||||
|
const data = received[0];
|
||||||
|
expect(data).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"name": "TheTime",
|
||||||
|
"state": {
|
||||||
|
"displayName": "TheTime",
|
||||||
|
"multipleFrames": true,
|
||||||
|
},
|
||||||
|
"type": "time",
|
||||||
|
"values": [
|
||||||
|
1000,
|
||||||
|
2000,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"name": "B + 2",
|
||||||
|
"type": "number",
|
||||||
|
"values": [
|
||||||
|
4,
|
||||||
|
202,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"length": 2,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('all numbers + static number', async () => {
|
it('all numbers + static number', async () => {
|
||||||
const cfg = {
|
const cfg = {
|
||||||
id: DataTransformerID.calculateField,
|
id: DataTransformerID.calculateField,
|
||||||
@ -231,6 +290,85 @@ describe('calculateField transformer w/ timeseries', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('all numbers + static number (multi-frame, avoids join)', async () => {
|
||||||
|
const cfg = {
|
||||||
|
id: DataTransformerID.calculateField,
|
||||||
|
options: {
|
||||||
|
mode: CalculateFieldMode.BinaryOperation,
|
||||||
|
binary: {
|
||||||
|
left: { matcher: { id: FieldMatcherID.byType, options: FieldType.number } },
|
||||||
|
operator: BinaryOperationID.Add,
|
||||||
|
right: '2',
|
||||||
|
},
|
||||||
|
replaceFields: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith((received) => {
|
||||||
|
const data = received[0];
|
||||||
|
|
||||||
|
expect(data).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"name": "TheTime",
|
||||||
|
"type": "time",
|
||||||
|
"values": [
|
||||||
|
1000,
|
||||||
|
2000,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"name": "A + 2",
|
||||||
|
"type": "number",
|
||||||
|
"values": [
|
||||||
|
3,
|
||||||
|
102,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"length": 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"name": "TheTime",
|
||||||
|
"type": "time",
|
||||||
|
"values": [
|
||||||
|
1000,
|
||||||
|
2000,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"name": "B + 2",
|
||||||
|
"type": "number",
|
||||||
|
"values": [
|
||||||
|
4,
|
||||||
|
202,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"name": "C + 2",
|
||||||
|
"type": "number",
|
||||||
|
"values": [
|
||||||
|
5,
|
||||||
|
302,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"length": 2,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('all numbers + field number', async () => {
|
it('all numbers + field number', async () => {
|
||||||
const cfg = {
|
const cfg = {
|
||||||
id: DataTransformerID.calculateField,
|
id: DataTransformerID.calculateField,
|
||||||
|
@ -128,10 +128,16 @@ export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransf
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
operator: (options, ctx) => (outerSource) => {
|
operator: (options, ctx) => (outerSource) => {
|
||||||
const operator =
|
const mode = options.mode ?? CalculateFieldMode.ReduceRow;
|
||||||
options && options.timeSeries !== false
|
|
||||||
? ensureColumnsTransformer.operator(null, ctx)
|
const asTimeSeries = options.timeSeries !== false;
|
||||||
: noopTransformer.operator({}, ctx);
|
const isBinaryFixed = mode === CalculateFieldMode.BinaryOperation && options.binary?.right.fixed != null;
|
||||||
|
|
||||||
|
const needsSingleFrame = asTimeSeries && !isBinaryFixed;
|
||||||
|
|
||||||
|
const operator = needsSingleFrame
|
||||||
|
? ensureColumnsTransformer.operator(null, ctx)
|
||||||
|
: noopTransformer.operator({}, ctx);
|
||||||
|
|
||||||
if (options.alias != null) {
|
if (options.alias != null) {
|
||||||
options.alias = ctx.interpolate(options.alias);
|
options.alias = ctx.interpolate(options.alias);
|
||||||
@ -140,7 +146,6 @@ export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransf
|
|||||||
return outerSource.pipe(
|
return outerSource.pipe(
|
||||||
operator,
|
operator,
|
||||||
map((data) => {
|
map((data) => {
|
||||||
const mode = options.mode ?? CalculateFieldMode.ReduceRow;
|
|
||||||
let creator: ValuesCreator | undefined = undefined;
|
let creator: ValuesCreator | undefined = undefined;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -172,9 +177,10 @@ export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransf
|
|||||||
if (binaryOptions.left?.matcher?.id && binaryOptions.left?.matcher.id === FieldMatcherID.byType) {
|
if (binaryOptions.left?.matcher?.id && binaryOptions.left?.matcher.id === FieldMatcherID.byType) {
|
||||||
const fieldType = binaryOptions.left.matcher.options;
|
const fieldType = binaryOptions.left.matcher.options;
|
||||||
const operator = binaryOperators.getIfExists(binaryOptions.operator);
|
const operator = binaryOperators.getIfExists(binaryOptions.operator);
|
||||||
return data.map((frame) => {
|
const outFrames = data.map((frame) => {
|
||||||
const { timeField } = getTimeField(frame);
|
const { timeField } = getTimeField(frame);
|
||||||
const newFields: Field[] = [];
|
const newFields: Field[] = [];
|
||||||
|
let didAddNewFields = false;
|
||||||
if (timeField && options.timeSeries !== false) {
|
if (timeField && options.timeSeries !== false) {
|
||||||
newFields.push(timeField);
|
newFields.push(timeField);
|
||||||
}
|
}
|
||||||
@ -206,10 +212,18 @@ export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransf
|
|||||||
values: arr,
|
values: arr,
|
||||||
};
|
};
|
||||||
newFields.push(newField);
|
newFields.push(newField);
|
||||||
|
didAddNewFields = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (options.replaceFields && !didAddNewFields) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return { ...frame, fields: newFields };
|
return { ...frame, fields: newFields };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return outFrames.filter((frame) => frame != null);
|
||||||
} else {
|
} else {
|
||||||
creator = getBinaryCreator(defaults(binaryOptions, defaultBinaryOptions), data, ctx);
|
creator = getBinaryCreator(defaults(binaryOptions, defaultBinaryOptions), data, ctx);
|
||||||
}
|
}
|
||||||
@ -242,10 +256,14 @@ export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransf
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.map((frame) => {
|
const outFrames = data.map((frame) => {
|
||||||
// delegate field creation to the specific function
|
// delegate field creation to the specific function
|
||||||
const values = creator!(frame);
|
const values = creator!(frame);
|
||||||
if (!values) {
|
if (!values) {
|
||||||
|
// if nothing was done to frame, omit it when replacing fields
|
||||||
|
if (options.replaceFields) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +291,7 @@ export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransf
|
|||||||
fields,
|
fields,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
return outFrames.filter((frame) => frame != null);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user