This is an automated email from the ASF dual-hosted git repository. villebro pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push: new 0472c11 fix: Add deprecated fields to QueryObject schema (#9579) 0472c11 is described below commit 0472c11157450de50cd97e36e4459bb2c9c4e5e4 Author: Ville Brofeldt <33317356+ville...@users.noreply.github.com> AuthorDate: Sat Apr 18 20:28:57 2020 +0300 fix: Add deprecated fields to QueryObject schema (#9579) * fix: Add deprecated fields to QueryObject schema * linting --- superset/charts/schemas.py | 34 ++++++++++++++++++++++++++++++++++ superset/common/query_object.py | 26 +++++++++++++++++++++++++- superset/connectors/druid/models.py | 4 ++-- tests/charts/api_tests.py | 15 ++++++++++++--- 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/superset/charts/schemas.py b/superset/charts/schemas.py index 0a7035c..49d0480 100644 --- a/superset/charts/schemas.py +++ b/superset/charts/schemas.py @@ -393,6 +393,19 @@ class ChartDataExtrasSchema(Schema): enum=["today", "now"], required=False, ) + where = fields.String( + description="WHERE clause to be added to queries using AND operator.", + required=False, + ) + having = fields.String( + description="HAVING clause to be added to aggregate queries using " + "AND operator.", + required=False, + ) + having_druid = fields.String( + description="HAVING filters to be added to legacy Druid datasource queries.", + required=False, + ) class ChartDataQueryObjectSchema(Schema): @@ -484,6 +497,27 @@ class ChartDataQueryObjectSchema(Schema): required=False, example=[["my_col_1", False], ["my_col_2", True]], ) + where = fields.String( + description="WHERE clause to be added to queries using AND operator." + "This field is deprecated, and should be passed to `extras`.", + required=False, + deprecated=True, + ) + having = fields.String( + description="HAVING clause to be added to aggregate queries using " + "AND operator. This field is deprecated, and should be passed " + "to `extras`.", + required=False, + deprecated=True, + ) + having_filters = fields.List( + fields.Dict(), + description="HAVING filters to be added to legacy Druid datasource queries. " + "This field is deprecated, and should be passed to `extras` " + "as `filters_druid`.", + required=False, + deprecated=True, + ) class ChartDataDatasourceSchema(Schema): diff --git a/superset/common/query_object.py b/superset/common/query_object.py index 31a6241..0a83ef7 100644 --- a/superset/common/query_object.py +++ b/superset/common/query_object.py @@ -18,7 +18,7 @@ import hashlib import logging from datetime import datetime, timedelta -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, NamedTuple, Optional, Union import simplejson as json from flask_babel import gettext as _ @@ -35,6 +35,18 @@ logger = logging.getLogger(__name__) # https://github.com/python/mypy/issues/5288 +class DeprecatedExtrasField(NamedTuple): + name: str + extras_name: str + + +DEPRECATED_EXTRAS_FIELDS = ( + DeprecatedExtrasField(name="where", extras_name="where"), + DeprecatedExtrasField(name="having", extras_name="having"), + DeprecatedExtrasField(name="having_filters", extras_name="having_druid"), +) + + class QueryObject: """ The query object's schema matches the interfaces of DB connectors like sqla @@ -75,6 +87,7 @@ class QueryObject: columns: Optional[List[str]] = None, orderby: Optional[List[List]] = None, post_processing: Optional[List[Dict[str, Any]]] = None, + **kwargs: Any, ): extras = extras or {} is_sip_38 = is_feature_enabled("SIP_38_VIZ_REARCHITECTURE") @@ -124,6 +137,17 @@ class QueryObject: self.orderby = orderby or [] + # move deprecated fields to extras + for field in DEPRECATED_EXTRAS_FIELDS: + if field.name in kwargs: + logger.warning( + f"The field `{field.name} is deprecated, and should be " + f"passed to `extras` via the `{field.extras_name}` property" + ) + value = kwargs[field.name] + if value: + self.extras[field.extras_name] = value + def to_dict(self) -> Dict[str, Any]: query_object_dict = { "granularity": self.granularity, diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py index 20dd732..8d4aeb1 100644 --- a/superset/connectors/druid/models.py +++ b/superset/connectors/druid/models.py @@ -24,7 +24,7 @@ from copy import deepcopy from datetime import datetime, timedelta from distutils.version import LooseVersion from multiprocessing.pool import ThreadPool -from typing import cast, Dict, Iterable, List, Optional, Set, Tuple, Union +from typing import Any, cast, Dict, Iterable, List, Optional, Set, Tuple, Union import pandas as pd import sqlalchemy as sa @@ -1639,7 +1639,7 @@ class DruidDatasource(Model, BaseDatasource): return cond - def get_having_filters(self, raw_filters: List[Dict]) -> "Having": + def get_having_filters(self, raw_filters: List[Dict[str, Any]]) -> "Having": filters = None reversed_op_map = { FilterOperationType.NOT_EQUALS.value: FilterOperationType.EQUALS.value, diff --git a/tests/charts/api_tests.py b/tests/charts/api_tests.py index 1f64bae..6a78f30 100644 --- a/tests/charts/api_tests.py +++ b/tests/charts/api_tests.py @@ -76,11 +76,21 @@ class ChartApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): "datasource": {"id": slc.datasource_id, "type": slc.datasource_type}, "queries": [ { + "extras": {"where": ""}, "granularity": "ds", "groupby": ["name"], + "is_timeseries": False, "metrics": [{"label": "sum__num"}], - "filters": [], + "order_desc": True, + "orderby": [], "row_limit": 100, + "time_range": "100 years ago : now", + "timeseries_limit": 0, + "timeseries_limit_metric": None, + "filters": [{"col": "gender", "op": "==", "val": "boy"}], + "having": "", + "having_filters": [], + "where": "", } ], } @@ -660,8 +670,7 @@ class ChartApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): self.assertEqual(data["result"][0]["rowcount"], 100) def test_invalid_chart_data(self): - """ - Query API: Test chart data query + """Query API: Test chart data query with invalid schema """ self.login(username="admin") query_context = self._get_query_context()