Compare commits

...

2 Commits

Author SHA1 Message Date
Daniel Vaz Gaspar
5874b92977 fix(alerts): void query with numeric comparison (#13090)
* fix(alerts): void query with numeric comparison

* remove config changes

* fix tests

* better logic

* fix logic

* fix logic

* Improve test readability

(cherry picked from commit 2e6ea76631)
2021-02-15 14:14:31 -08:00
Ville Brofeldt
92e172ec8d fix: sorting by saved metric (#13059)
(cherry picked from commit c1e10c4627)
2021-02-15 14:14:07 -08:00
4 changed files with 34 additions and 9 deletions

View File

@@ -1150,6 +1150,8 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at
col = self.adhoc_metric_to_sqla(col, columns_by_name) col = self.adhoc_metric_to_sqla(col, columns_by_name)
elif col in columns_by_name: elif col in columns_by_name:
col = columns_by_name[col].get_sqla_col() col = columns_by_name[col].get_sqla_col()
elif col in metrics_by_name:
col = metrics_by_name[col].get_sqla_col()
if isinstance(col, Label): if isinstance(col, Label):
label = col._label # pylint: disable=protected-access label = col._label # pylint: disable=protected-access

View File

@@ -271,8 +271,8 @@ def create_slices(
groupby=["name"], groupby=["name"],
adhoc_filters=[gen_filter("gender", "girl")], adhoc_filters=[gen_filter("gender", "girl")],
row_limit=50, row_limit=50,
timeseries_limit_metric="sum__num", timeseries_limit_metric=metric,
metrics=metrics, metrics=[metric],
), ),
), ),
Slice( Slice(
@@ -300,7 +300,8 @@ def create_slices(
groupby=["name"], groupby=["name"],
adhoc_filters=[gen_filter("gender", "boy")], adhoc_filters=[gen_filter("gender", "boy")],
row_limit=50, row_limit=50,
metrics=metrics, timeseries_limit_metric=metric,
metrics=[metric],
), ),
), ),
Slice( Slice(

View File

@@ -47,15 +47,16 @@ class AlertCommand(BaseCommand):
def run(self) -> bool: def run(self) -> bool:
self.validate() self.validate()
if self._report_schedule.validator_type == ReportScheduleValidatorType.NOT_NULL: if self._is_validator_not_null:
self._report_schedule.last_value_row_json = str(self._result) self._report_schedule.last_value_row_json = str(self._result)
return self._result not in (0, None, np.nan) return self._result is not None
self._report_schedule.last_value = self._result self._report_schedule.last_value = self._result
try: try:
operator = json.loads(self._report_schedule.validator_config_json)["op"] operator = json.loads(self._report_schedule.validator_config_json)["op"]
threshold = json.loads(self._report_schedule.validator_config_json)[ threshold = json.loads(self._report_schedule.validator_config_json)[
"threshold" "threshold"
] ]
return OPERATOR_FUNCTIONS[operator](self._result, threshold) return OPERATOR_FUNCTIONS[operator](self._result, threshold)
except (KeyError, json.JSONDecodeError): except (KeyError, json.JSONDecodeError):
raise AlertValidatorConfigError() raise AlertValidatorConfigError()
@@ -95,6 +96,18 @@ class AlertCommand(BaseCommand):
except (AssertionError, TypeError, ValueError): except (AssertionError, TypeError, ValueError):
raise AlertQueryInvalidTypeError() raise AlertQueryInvalidTypeError()
@property
def _is_validator_not_null(self) -> bool:
return (
self._report_schedule.validator_type == ReportScheduleValidatorType.NOT_NULL
)
@property
def _is_validator_operator(self) -> bool:
return (
self._report_schedule.validator_type == ReportScheduleValidatorType.OPERATOR
)
def validate(self) -> None: def validate(self) -> None:
""" """
Validate the query result as a Pandas DataFrame Validate the query result as a Pandas DataFrame
@@ -108,10 +121,14 @@ class AlertCommand(BaseCommand):
except Exception as ex: except Exception as ex:
raise AlertQueryError(message=str(ex)) raise AlertQueryError(message=str(ex))
if df.empty: if df.empty and self._is_validator_not_null:
self._result = None
return
if df.empty and self._is_validator_operator:
self._result = 0.0
return return
rows = df.to_records() rows = df.to_records()
if self._report_schedule.validator_type == ReportScheduleValidatorType.NOT_NULL: if self._is_validator_not_null:
self._validate_not_null(rows) self._validate_not_null(rows)
return return
self._validate_operator(rows) self._validate_operator(rows)

View File

@@ -308,7 +308,7 @@ def create_test_table_context(database: Database):
@pytest.yield_fixture( @pytest.yield_fixture(
params=["alert1", "alert2", "alert3", "alert4", "alert5", "alert6"] params=["alert1", "alert2", "alert3", "alert4", "alert5", "alert6", "alert7"]
) )
def create_no_alert_email_chart(request): def create_no_alert_email_chart(request):
param_config = { param_config = {
@@ -338,10 +338,15 @@ def create_no_alert_email_chart(request):
"validator_config_json": '{"op": "!=", "threshold": 10}', "validator_config_json": '{"op": "!=", "threshold": 10}',
}, },
"alert6": { "alert6": {
"sql": "SELECT first from test_table where first=0", "sql": "SELECT first from test_table where 1=0",
"validator_type": ReportScheduleValidatorType.NOT_NULL, "validator_type": ReportScheduleValidatorType.NOT_NULL,
"validator_config_json": "{}", "validator_config_json": "{}",
}, },
"alert7": {
"sql": "SELECT first from test_table where 1=0",
"validator_type": ReportScheduleValidatorType.OPERATOR,
"validator_config_json": '{"op": ">", "threshold": 0}',
},
} }
with app.app_context(): with app.app_context():
chart = db.session.query(Slice).first() chart = db.session.query(Slice).first()