|
6 | 6 | from copy import deepcopy |
7 | 7 | from dataclasses import dataclass, replace |
8 | 8 | from datetime import datetime, timedelta, timezone |
| 9 | +from re import Match |
9 | 10 | from typing import Any, TypedDict |
10 | 11 | from uuid import UUID, uuid4 |
11 | 12 |
|
|
24 | 25 | from sentry.db.models import Model |
25 | 26 | from sentry.db.models.manager.base_query_set import BaseQuerySet |
26 | 27 | from sentry.deletions.models.scheduleddeletion import CellScheduledDeletion |
| 28 | +from sentry.discover.arithmetic import is_equation, parse_arithmetic, strip_equation |
27 | 29 | from sentry.incidents import tasks |
28 | 30 | from sentry.incidents.events import IncidentCreatedEvent, IncidentStatusUpdatedEvent |
29 | 31 | from sentry.incidents.models.alert_rule import ( |
@@ -1848,12 +1850,15 @@ def get_opsgenie_teams(organization_id: int, integration_id: int) -> list[tuple[ |
1848 | 1850 |
|
1849 | 1851 |
|
1850 | 1852 | def get_column_from_aggregate( |
1851 | | - aggregate: str, allow_mri: bool, allow_eap: bool = False |
| 1853 | + aggregate: str, |
| 1854 | + allow_mri: bool, |
| 1855 | + allow_eap: bool = False, |
| 1856 | + match: Match[str] | None = None, |
1852 | 1857 | ) -> str | None: |
1853 | 1858 | # These functions exist as SnQLFunction definitions and are not supported in the older |
1854 | 1859 | # logic for resolving functions. We parse these using `fields.is_function`, otherwise |
1855 | 1860 | # they will fail using the old resolve_field logic. |
1856 | | - match = is_function(aggregate) |
| 1861 | + match = is_function(aggregate) if match is None else match |
1857 | 1862 | if match and ( |
1858 | 1863 | match.group("function") in SPANS_METRICS_FUNCTIONS |
1859 | 1864 | or match.group("function") in METRICS_LAYER_UNSUPPORTED_TRANSACTION_METRICS_FUNCTIONS |
@@ -1900,21 +1905,29 @@ def check_aggregate_column_support( |
1900 | 1905 | aggregate: str, allow_mri: bool = False, allow_eap: bool = False |
1901 | 1906 | ) -> bool: |
1902 | 1907 | # TODO(ddm): remove `allow_mri` once the experimental feature flag is removed. |
1903 | | - column = get_column_from_aggregate(aggregate, allow_mri, allow_eap) |
1904 | | - match = is_function(aggregate) |
1905 | | - function = match.group("function") if match else None |
1906 | | - return ( |
1907 | | - column is None |
1908 | | - or is_measurement(column) |
1909 | | - or column in SUPPORTED_COLUMNS |
1910 | | - or column in TRANSLATABLE_COLUMNS |
1911 | | - or (is_mri(column) and allow_mri) |
1912 | | - or ( |
1913 | | - isinstance(function, str) |
1914 | | - and column in INSIGHTS_FUNCTION_VALID_ARGS_MAP.get(function, []) |
1915 | | - ) |
1916 | | - or allow_eap |
1917 | | - ) |
| 1908 | + if is_equation(aggregate): |
| 1909 | + _, _, terms = parse_arithmetic(strip_equation(aggregate)) |
| 1910 | + else: |
| 1911 | + terms = [aggregate] |
| 1912 | + |
| 1913 | + for term in terms: |
| 1914 | + match = is_function(term) |
| 1915 | + column = get_column_from_aggregate(term, allow_mri, allow_eap, match) |
| 1916 | + function = match.group("function") if match else None |
| 1917 | + if not ( |
| 1918 | + column is None |
| 1919 | + or is_measurement(column) |
| 1920 | + or column in SUPPORTED_COLUMNS |
| 1921 | + or column in TRANSLATABLE_COLUMNS |
| 1922 | + or (is_mri(column) and allow_mri) |
| 1923 | + or ( |
| 1924 | + isinstance(function, str) |
| 1925 | + and column in INSIGHTS_FUNCTION_VALID_ARGS_MAP.get(function, []) |
| 1926 | + ) |
| 1927 | + or allow_eap |
| 1928 | + ): |
| 1929 | + return False |
| 1930 | + return True |
1918 | 1931 |
|
1919 | 1932 |
|
1920 | 1933 | def translate_aggregate_field( |
|
0 commit comments