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 <[email protected]>
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()