Transformation: Add missing binary operator (#109695)

* fix(transformation): add binary operator
This commit is contained in:
Ihor Yeromin
2025-08-20 17:13:36 +00:00
committed by GitHub
parent 6085bbf820
commit f7d39204cd
2 changed files with 147 additions and 4 deletions
@@ -31,6 +31,7 @@ import {
ReduceOptions,
WindowSizeMode,
WindowAlignment,
getNameFromOptions,
} from './calculateField';
import { DataTransformerID } from './ids';
@@ -1459,6 +1460,144 @@ describe('calculateField transformer w/ timeseries', () => {
});
});
describe('getNameFromOptions', () => {
it('returns alias when provided', () => {
const options = {
mode: CalculateFieldMode.ReduceRow,
alias: 'My Custom Name',
reduce: { reducer: ReducerID.sum },
};
expect(getNameFromOptions(options)).toBe('My Custom Name');
});
it('returns cumulative function name', () => {
const options = {
mode: CalculateFieldMode.CumulativeFunctions,
cumulative: { reducer: ReducerID.sum, field: 'Value' },
};
expect(getNameFromOptions(options)).toBe('cumulative sum(Value)');
});
it('returns cumulative function name without field', () => {
const options = {
mode: CalculateFieldMode.CumulativeFunctions,
cumulative: { reducer: ReducerID.mean },
};
expect(getNameFromOptions(options)).toBe('cumulative mean');
});
it('returns window function name', () => {
const options = {
mode: CalculateFieldMode.WindowFunctions,
window: {
windowAlignment: WindowAlignment.Trailing,
reducer: ReducerID.mean,
field: 'Temperature',
},
};
expect(getNameFromOptions(options)).toBe('trailing moving mean(Temperature)');
});
it('returns window function name without field', () => {
const options = {
mode: CalculateFieldMode.WindowFunctions,
window: {
windowAlignment: WindowAlignment.Centered,
reducer: ReducerID.sum,
},
};
expect(getNameFromOptions(options)).toBe('centered moving sum');
});
it('returns unary operation name', () => {
const options = {
mode: CalculateFieldMode.UnaryOperation,
unary: {
operator: UnaryOperationID.Abs,
fieldName: 'Value',
},
};
expect(getNameFromOptions(options)).toBe('abs(Value)');
});
it('returns unary operation name without field', () => {
const options = {
mode: CalculateFieldMode.UnaryOperation,
unary: {
operator: UnaryOperationID.Abs,
fieldName: '',
},
};
expect(getNameFromOptions(options)).toBe('abs');
});
it('returns binary operation name with field matcher', () => {
const options = {
mode: CalculateFieldMode.BinaryOperation,
binary: {
left: { matcher: { id: FieldMatcherID.byName, options: 'FieldA' } },
operator: BinaryOperationID.Add,
right: { matcher: { id: FieldMatcherID.byName, options: 'FieldB' } },
},
};
expect(getNameFromOptions(options)).toBe('FieldA + FieldB');
});
it('returns binary operation name with fixed values', () => {
const options = {
mode: CalculateFieldMode.BinaryOperation,
binary: {
left: { fixed: '10' },
operator: BinaryOperationID.Multiply,
right: { fixed: '5' },
},
};
expect(getNameFromOptions(options)).toBe('10 * 5');
});
it('returns empty string for binary operation with variables', () => {
const options = {
mode: CalculateFieldMode.BinaryOperation,
binary: {
left: { fixed: '$variable1' },
operator: BinaryOperationID.Add,
right: { fixed: '10' },
},
};
expect(getNameFromOptions(options)).toBe('');
});
it('returns empty string when binary field is not provided', () => {
const options = {
mode: CalculateFieldMode.BinaryOperation,
// No binary field provided at all
};
expect(getNameFromOptions(options)).toBe('');
});
it('returns reducer name for reduce row mode', () => {
const options = {
mode: CalculateFieldMode.ReduceRow,
reduce: { reducer: ReducerID.mean },
};
expect(getNameFromOptions(options)).toBe('Mean');
});
it('returns "Row" for index mode', () => {
const options = {
mode: CalculateFieldMode.Index,
};
expect(getNameFromOptions(options)).toBe('Row');
});
it('returns "math" as default', () => {
const options = {
mode: 'invalid-mode' as CalculateFieldMode,
};
expect(getNameFromOptions(options)).toBe('math');
});
});
function activateFullSceneTree(scene: SceneObject): SceneDeactivationHandler {
const deactivationHandlers: SceneDeactivationHandler[] = [];
@@ -693,11 +693,15 @@ export function getNameFromOptions(options: CalculateFieldTransformerOptions) {
}
case CalculateFieldMode.BinaryOperation: {
const { binary } = options;
const alias = `${binary?.left?.matcher?.options ?? binary?.left?.fixed ?? ''} ${binary?.operator ?? ''} ${binary?.right?.matcher?.options ?? binary?.right?.fixed ?? ''}`;
const left = binary?.left?.matcher?.options ?? binary?.left?.fixed ?? '';
const right = binary?.right?.matcher?.options ?? binary?.right?.fixed ?? '';
// binary calculations with variables will be interpolated on the visualization but we don't want to do that here, so just give a blank placeholder
const variableFound = /\$/g.test(alias);
return variableFound ? '' : alias;
if (/\$/.test(left) || /\$/.test(right)) {
return '';
}
const operator = binary?.operator ?? BinaryOperationID.Add;
return left && right ? `${left} ${operator} ${right}` : '';
}
case CalculateFieldMode.ReduceRow:
{