useFormulaDependencies.tsx 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import {useCallback, useMemo} from 'react';
  2. import {unescapeMetricsFormula} from 'sentry/utils/metrics';
  3. import {MetricQueryType, type MetricQueryWidgetParams} from 'sentry/utils/metrics/types';
  4. import {useDDMContext} from 'sentry/views/ddm/context';
  5. import {parseFormula} from 'sentry/views/ddm/formulaParser/parser';
  6. import {type TokenList, TokenType} from 'sentry/views/ddm/formulaParser/types';
  7. import {getQuerySymbol} from 'sentry/views/ddm/querySymbol';
  8. interface FormulaDependencies {
  9. dependencies: MetricQueryWidgetParams[];
  10. isError: boolean;
  11. }
  12. export function useFormulaDependencies() {
  13. const {widgets} = useDDMContext();
  14. const queriesLookup = useMemo(() => {
  15. const lookup = new Map<string, MetricQueryWidgetParams>();
  16. widgets.forEach(widget => {
  17. if (widget.type === MetricQueryType.QUERY) {
  18. lookup.set(getQuerySymbol(widget.id), widget);
  19. }
  20. });
  21. return lookup;
  22. }, [widgets]);
  23. const getFormulaQueryDependencies = useCallback(
  24. (formula: string): FormulaDependencies => {
  25. let tokens: TokenList = [];
  26. try {
  27. tokens = parseFormula(unescapeMetricsFormula(formula));
  28. } catch {
  29. // We should not end up here, but if we do, we should not crash the UI
  30. return {dependencies: [], isError: true};
  31. }
  32. const dependencies: MetricQueryWidgetParams[] = [];
  33. let isError = false;
  34. tokens.forEach(token => {
  35. if (token.type === TokenType.VARIABLE) {
  36. const widget = queriesLookup.get(token.content);
  37. if (widget) {
  38. dependencies.push(widget);
  39. } else {
  40. isError = true;
  41. }
  42. }
  43. });
  44. return {dependencies, isError};
  45. },
  46. [queriesLookup]
  47. );
  48. const formulaDependencies = useMemo(() => {
  49. return widgets.reduce((acc: Record<number, FormulaDependencies>, widget) => {
  50. if (widget.type === MetricQueryType.FORMULA) {
  51. acc[widget.id] = getFormulaQueryDependencies(widget.formula);
  52. }
  53. return acc;
  54. }, {});
  55. }, [getFormulaQueryDependencies, widgets]);
  56. return formulaDependencies;
  57. }