mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 03:31:50 +08:00
Transforms: Fix 'Filter data by values' removing rows in unrelated frames (#86087)
This commit is contained in:
@ -26,6 +26,25 @@ const seriesAWithSingleField = toDataFrame({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const multiSeriesWithSingleField = [
|
||||||
|
toDataFrame({
|
||||||
|
name: 'A',
|
||||||
|
length: 3,
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [1000, 2000, 3000] },
|
||||||
|
{ name: 'value', type: FieldType.number, values: [1, 0, 1] },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
toDataFrame({
|
||||||
|
name: 'B',
|
||||||
|
length: 3,
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [5000, 6000, 7000] },
|
||||||
|
{ name: 'value', type: FieldType.number, values: [0, 1, 1] },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
describe('FilterByValue transformer', () => {
|
describe('FilterByValue transformer', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockTransformationsRegistry([filterByValueTransformer]);
|
mockTransformationsRegistry([filterByValueTransformer]);
|
||||||
@ -72,6 +91,68 @@ describe('FilterByValue transformer', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not cross frame boundaries', async () => {
|
||||||
|
const cfg: DataTransformerConfig<FilterByValueTransformerOptions> = {
|
||||||
|
id: DataTransformerID.filterByValue,
|
||||||
|
options: {
|
||||||
|
type: FilterByValueType.exclude,
|
||||||
|
match: FilterByValueMatch.any,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
fieldName: 'A value',
|
||||||
|
config: {
|
||||||
|
id: ValueMatcherID.equal,
|
||||||
|
options: { value: 0 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'B value',
|
||||||
|
config: {
|
||||||
|
id: ValueMatcherID.equal,
|
||||||
|
options: { value: 0 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(transformDataFrame([cfg], multiSeriesWithSingleField)).toEmitValuesWith((received) => {
|
||||||
|
const processed = received[0];
|
||||||
|
|
||||||
|
expect(processed.length).toEqual(2);
|
||||||
|
|
||||||
|
expect(processed[0].fields).toEqual([
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
type: FieldType.time,
|
||||||
|
values: [1000, 3000],
|
||||||
|
state: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
type: FieldType.number,
|
||||||
|
values: [1, 1],
|
||||||
|
state: {},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(processed[1].fields).toEqual([
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
type: FieldType.time,
|
||||||
|
values: [6000, 7000],
|
||||||
|
state: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
type: FieldType.number,
|
||||||
|
values: [1, 1],
|
||||||
|
state: {},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should include values', async () => {
|
it('should include values', async () => {
|
||||||
const lowerOrEqual: MatcherConfig<BasicValueMatcherOptions<number>> = {
|
const lowerOrEqual: MatcherConfig<BasicValueMatcherOptions<number>> = {
|
||||||
id: ValueMatcherID.lowerOrEqual,
|
id: ValueMatcherID.lowerOrEqual,
|
||||||
|
@ -92,14 +92,16 @@ export const filterByValueTransformer: DataTransformerInfo<FilterByValueTransfor
|
|||||||
|
|
||||||
return source.pipe(
|
return source.pipe(
|
||||||
map((data) => {
|
map((data) => {
|
||||||
if (!Array.isArray(data) || data.length === 0) {
|
if (data.length === 0) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rows = new Set<number>();
|
const processed: DataFrame[] = [];
|
||||||
|
|
||||||
|
const fieldIndexByName = groupFieldIndexByName(data);
|
||||||
|
|
||||||
for (const frame of data) {
|
for (const frame of data) {
|
||||||
const fieldIndexByName = groupFieldIndexByName(frame, data);
|
const rows = new Set<number>();
|
||||||
|
|
||||||
let matchers;
|
let matchers;
|
||||||
if (transformationsVariableSupport()) {
|
if (transformationsVariableSupport()) {
|
||||||
@ -135,13 +137,9 @@ export const filterByValueTransformer: DataTransformerInfo<FilterByValueTransfor
|
|||||||
rows.add(index);
|
rows.add(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const processed: DataFrame[] = [];
|
|
||||||
const frameLength = include ? rows.size : data[0].length - rows.size;
|
|
||||||
|
|
||||||
for (const frame of data) {
|
|
||||||
const fields: Field[] = [];
|
const fields: Field[] = [];
|
||||||
|
const frameLength = include ? rows.size : data[0].length - rows.size;
|
||||||
|
|
||||||
for (const field of frame.fields) {
|
for (const field of frame.fields) {
|
||||||
const buffer = [];
|
const buffer = [];
|
||||||
@ -198,10 +196,15 @@ const createFilterValueMatchers = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupFieldIndexByName = (frame: DataFrame, data: DataFrame[]): Record<string, number> => {
|
const groupFieldIndexByName = (data: DataFrame[]) => {
|
||||||
return frame.fields.reduce((all: Record<string, number>, field, fieldIndex) => {
|
const lookup: Record<string, number> = {};
|
||||||
const fieldName = getFieldDisplayName(field, frame, data);
|
|
||||||
all[fieldName] = fieldIndex;
|
for (const frame of data) {
|
||||||
return all;
|
frame.fields.forEach((field, fieldIndex) => {
|
||||||
}, {});
|
const fieldName = getFieldDisplayName(field, frame, data);
|
||||||
|
lookup[fieldName] = fieldIndex;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return lookup;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user