fix(chart-data-api): assert referenced columns are present in datasource (#10451)

* fix(chart-data-api): assert requested columns are present in datasource

* add filter tests

* add column_names to AnnotationDatasource

* add assertion for simple metrics

* lint
This commit is contained in:
Ville Brofeldt
2020-08-14 20:58:24 +03:00
committed by GitHub
parent 6c09b938fe
commit acb00f509c
7 changed files with 196 additions and 24 deletions

View File

@@ -42,6 +42,7 @@ from types import TracebackType
from typing import (
Any,
Callable,
cast,
Dict,
Iterable,
Iterator,
@@ -102,7 +103,6 @@ logging.getLogger("MARKDOWN").setLevel(logging.INFO)
logger = logging.getLogger(__name__)
DTTM_ALIAS = "__timestamp"
ADHOC_METRIC_EXPRESSION_TYPES = {"SIMPLE": "SIMPLE", "SQL": "SQL"}
JS_MAX_INTEGER = 9007199254740991 # Largest int Java Script can handle 2^53-1
@@ -1038,20 +1038,23 @@ def backend() -> str:
def is_adhoc_metric(metric: Metric) -> bool:
if not isinstance(metric, dict):
return False
metric = cast(Dict[str, Any], metric)
return bool(
isinstance(metric, dict)
and (
(
(
metric["expressionType"] == ADHOC_METRIC_EXPRESSION_TYPES["SIMPLE"]
and metric["column"]
and metric["aggregate"]
metric.get("expressionType") == AdhocMetricExpressionType.SIMPLE
and metric.get("column")
and cast(Dict[str, Any], metric["column"]).get("column_name")
and metric.get("aggregate")
)
or (
metric["expressionType"] == ADHOC_METRIC_EXPRESSION_TYPES["SQL"]
and metric["sqlExpression"]
metric.get("expressionType") == AdhocMetricExpressionType.SQL
and metric.get("sqlExpression")
)
)
and metric["label"]
and metric.get("label")
)
@@ -1398,6 +1401,37 @@ def get_form_data_token(form_data: Dict[str, Any]) -> str:
return form_data.get("token") or "token_" + uuid.uuid4().hex[:8]
def get_column_name_from_metric(metric: Metric) -> Optional[str]:
"""
Extract the column that a metric is referencing. If the metric isn't
a simple metric, always returns `None`.
:param metric: Ad-hoc metric
:return: column name if simple metric, otherwise None
"""
if is_adhoc_metric(metric):
metric = cast(Dict[str, Any], metric)
if metric["expressionType"] == AdhocMetricExpressionType.SIMPLE:
return cast(Dict[str, Any], metric["column"])["column_name"]
return None
def get_column_names_from_metrics(metrics: List[Metric]) -> List[str]:
"""
Extract the columns that a list of metrics are referencing. Expcludes all
SQL metrics.
:param metrics: Ad-hoc metric
:return: column name if simple metric, otherwise None
"""
columns: List[str] = []
for metric in metrics:
column_name = get_column_name_from_metric(metric)
if column_name:
columns.append(column_name)
return columns
class LenientEnum(Enum):
"""Enums that do not raise ValueError when value is invalid"""
@@ -1523,3 +1557,8 @@ class PostProcessingContributionOrientation(str, Enum):
ROW = "row"
COLUMN = "column"
class AdhocMetricExpressionType(str, Enum):
SIMPLE = "SIMPLE"
SQL = "SQL"