Transforms: Fix 'Filter data by values' removing rows in unrelated frames (#86087)

This commit is contained in:
Leon Sorokin 2024-04-17 09:07:23 -05:00 committed by GitHub
parent d409d8e860
commit 9682022b1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 98 additions and 14 deletions

View File

@ -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', () => {
beforeAll(() => {
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 () => {
const lowerOrEqual: MatcherConfig<BasicValueMatcherOptions<number>> = {
id: ValueMatcherID.lowerOrEqual,

View File

@ -92,14 +92,16 @@ export const filterByValueTransformer: DataTransformerInfo<FilterByValueTransfor
return source.pipe(
map((data) => {
if (!Array.isArray(data) || data.length === 0) {
if (data.length === 0) {
return data;
}
const rows = new Set<number>();
const processed: DataFrame[] = [];
const fieldIndexByName = groupFieldIndexByName(data);
for (const frame of data) {
const fieldIndexByName = groupFieldIndexByName(frame, data);
const rows = new Set<number>();
let matchers;
if (transformationsVariableSupport()) {
@ -135,13 +137,9 @@ export const filterByValueTransformer: DataTransformerInfo<FilterByValueTransfor
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 frameLength = include ? rows.size : data[0].length - rows.size;
for (const field of frame.fields) {
const buffer = [];
@ -198,10 +196,15 @@ const createFilterValueMatchers = (
});
};
const groupFieldIndexByName = (frame: DataFrame, data: DataFrame[]): Record<string, number> => {
return frame.fields.reduce((all: Record<string, number>, field, fieldIndex) => {
const fieldName = getFieldDisplayName(field, frame, data);
all[fieldName] = fieldIndex;
return all;
}, {});
const groupFieldIndexByName = (data: DataFrame[]) => {
const lookup: Record<string, number> = {};
for (const frame of data) {
frame.fields.forEach((field, fieldIndex) => {
const fieldName = getFieldDisplayName(field, frame, data);
lookup[fieldName] = fieldIndex;
});
}
return lookup;
};