mirror of
https://github.com/apache/superset.git
synced 2026-07-26 00:22:31 +00:00
Compare commits
4 Commits
6.0-bug-fi
...
fix/backpo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ee8fd1d3b | ||
|
|
b7765ca291 | ||
|
|
d96cacfb63 | ||
|
|
0877e66610 |
@@ -1380,6 +1380,22 @@ class ChartDataQueryObjectSchema(Schema):
|
||||
allow_none=True,
|
||||
)
|
||||
|
||||
@post_load
|
||||
def rename_deprecated_fields(
|
||||
self, data: dict[str, Any], **kwargs: Any
|
||||
) -> dict[str, Any]:
|
||||
_renames = (
|
||||
("groupby", "columns"),
|
||||
("granularity_sqla", "granularity"),
|
||||
("timeseries_limit", "series_limit"),
|
||||
("timeseries_limit_metric", "series_limit_metric"),
|
||||
)
|
||||
for old, new in _renames:
|
||||
value = data.pop(old, None)
|
||||
if value or value == 0:
|
||||
data[new] = value
|
||||
return data
|
||||
|
||||
|
||||
class ChartDataQueryContextSchema(Schema):
|
||||
query_context_factory: QueryContextFactory | None = None
|
||||
|
||||
@@ -19,7 +19,7 @@ from __future__ import annotations
|
||||
from typing import Any, cast, TYPE_CHECKING
|
||||
|
||||
from superset.common.chart_data import ChartDataResultType
|
||||
from superset.common.query_object import QueryObject
|
||||
from superset.common.query_object import DEPRECATED_FIELDS, QueryObject
|
||||
from superset.common.utils.time_range_utils import get_since_until_from_time_range
|
||||
from superset.constants import NO_TIME_RANGE
|
||||
from superset.superset_typing import Column
|
||||
@@ -66,6 +66,14 @@ class QueryObjectFactory: # pylint: disable=too-few-public-methods
|
||||
processed_extras = self._process_extras(extras)
|
||||
result_type = kwargs.setdefault("result_type", parent_result_type)
|
||||
|
||||
# Rename deprecated kwargs before any processing so that downstream code
|
||||
# (time-range resolution, QueryObject) only ever sees the canonical names.
|
||||
# A truthy deprecated value always overrides the canonical field, matching
|
||||
# the historical QueryObject._rename_deprecated_fields precedence.
|
||||
for field in DEPRECATED_FIELDS:
|
||||
if old_val := kwargs.pop(field.old_name, None):
|
||||
kwargs[field.new_name] = old_val
|
||||
|
||||
# Process row limit taking server pagination into account
|
||||
row_limit = self._process_row_limit(
|
||||
row_limit, result_type, server_pagination=server_pagination
|
||||
|
||||
@@ -135,6 +135,53 @@ def test_chart_data_query_object_schema_time_grain_sqla_validation(
|
||||
assert result["extras"]["time_grain_sqla"] is None
|
||||
|
||||
|
||||
def test_chart_data_query_object_schema_deprecated_fields_renamed(
|
||||
app_context: None,
|
||||
) -> None:
|
||||
"""Deprecated query object fields are renamed to their canonical names."""
|
||||
schema = ChartDataQueryObjectSchema()
|
||||
|
||||
# groupby alone → becomes columns
|
||||
result = schema.load({"groupby": ["country_name"]})
|
||||
assert result.get("columns") == ["country_name"]
|
||||
assert "groupby" not in result
|
||||
|
||||
# groupby overwrites columns when both are provided
|
||||
result = schema.load({"groupby": ["region"], "columns": ["country_name"]})
|
||||
assert result.get("columns") == ["region"]
|
||||
assert "groupby" not in result
|
||||
|
||||
# empty groupby is discarded; existing columns is preserved
|
||||
result = schema.load({"groupby": [], "columns": ["country_name"]})
|
||||
assert result.get("columns") == ["country_name"]
|
||||
assert "groupby" not in result
|
||||
|
||||
# null groupby is discarded; existing columns is preserved (allow_none=True)
|
||||
result = schema.load({"groupby": None, "columns": ["country_name"]})
|
||||
assert result.get("columns") == ["country_name"]
|
||||
assert "groupby" not in result
|
||||
|
||||
# no groupby → columns passes through unchanged
|
||||
result = schema.load({"columns": ["country_name"]})
|
||||
assert result.get("columns") == ["country_name"]
|
||||
assert "groupby" not in result
|
||||
|
||||
# granularity_sqla → granularity
|
||||
result = schema.load({"granularity_sqla": "ds"})
|
||||
assert result.get("granularity") == "ds"
|
||||
assert "granularity_sqla" not in result
|
||||
|
||||
# timeseries_limit → series_limit
|
||||
result = schema.load({"timeseries_limit": 5})
|
||||
assert result.get("series_limit") == 5
|
||||
assert "timeseries_limit" not in result
|
||||
|
||||
# timeseries_limit_metric → series_limit_metric
|
||||
result = schema.load({"timeseries_limit_metric": "count"})
|
||||
assert result.get("series_limit_metric") == "count"
|
||||
assert "timeseries_limit_metric" not in result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"app",
|
||||
[{"TIME_GRAIN_ADDONS": {"PT10M": "10 minutes"}}],
|
||||
|
||||
@@ -138,3 +138,91 @@ class TestQueryObjectFactory:
|
||||
**raw_query_object,
|
||||
)
|
||||
assert query_object.metric_names == ["SUM", "num_girls", "num_boys"]
|
||||
|
||||
def test_deprecated_groupby_renamed_to_columns(
|
||||
self,
|
||||
query_object_factory: QueryObjectFactory,
|
||||
raw_query_context: dict[str, Any],
|
||||
):
|
||||
"""groupby in stored query_context should be silently renamed to columns."""
|
||||
raw_query_object = raw_query_context["queries"][0]
|
||||
raw_query_object.pop("columns", None)
|
||||
raw_query_object["groupby"] = ["name", "gender"]
|
||||
query_object = query_object_factory.create(
|
||||
raw_query_context["result_type"], **raw_query_object
|
||||
)
|
||||
assert query_object.columns == ["name", "gender"]
|
||||
assert not hasattr(query_object, "groupby")
|
||||
|
||||
def test_deprecated_groupby_overwrites_columns(
|
||||
self,
|
||||
query_object_factory: QueryObjectFactory,
|
||||
raw_query_context: dict[str, Any],
|
||||
):
|
||||
"""A truthy deprecated groupby overrides an already-present columns,
|
||||
matching the historical QueryObject._rename_deprecated_fields precedence."""
|
||||
raw_query_object = raw_query_context["queries"][0]
|
||||
raw_query_object["columns"] = ["state"]
|
||||
raw_query_object["groupby"] = ["name", "gender"]
|
||||
query_object = query_object_factory.create(
|
||||
raw_query_context["result_type"], **raw_query_object
|
||||
)
|
||||
assert query_object.columns == ["name", "gender"]
|
||||
|
||||
def test_deprecated_groupby_empty_list_is_ignored(
|
||||
self,
|
||||
query_object_factory: QueryObjectFactory,
|
||||
raw_query_context: dict[str, Any],
|
||||
):
|
||||
"""groupby=[] is falsy — popped but columns should default to []."""
|
||||
raw_query_object = raw_query_context["queries"][0]
|
||||
raw_query_object.pop("columns", None)
|
||||
raw_query_object["groupby"] = []
|
||||
query_object = query_object_factory.create(
|
||||
raw_query_context["result_type"], **raw_query_object
|
||||
)
|
||||
assert query_object.columns == []
|
||||
assert not hasattr(query_object, "groupby")
|
||||
|
||||
def test_deprecated_granularity_sqla_renamed_to_granularity(
|
||||
self,
|
||||
query_object_factory: QueryObjectFactory,
|
||||
raw_query_context: dict[str, Any],
|
||||
):
|
||||
"""granularity_sqla in stored query_context should be renamed to granularity."""
|
||||
raw_query_object = raw_query_context["queries"][0]
|
||||
raw_query_object.pop("granularity", None)
|
||||
raw_query_object["granularity_sqla"] = "ds"
|
||||
query_object = query_object_factory.create(
|
||||
raw_query_context["result_type"], **raw_query_object
|
||||
)
|
||||
assert query_object.granularity == "ds"
|
||||
|
||||
def test_deprecated_timeseries_limit_renamed_to_series_limit(
|
||||
self,
|
||||
query_object_factory: QueryObjectFactory,
|
||||
raw_query_context: dict[str, Any],
|
||||
):
|
||||
"""timeseries_limit should be renamed to series_limit."""
|
||||
raw_query_object = raw_query_context["queries"][0]
|
||||
raw_query_object.pop("series_limit", None)
|
||||
raw_query_object["timeseries_limit"] = 5
|
||||
query_object = query_object_factory.create(
|
||||
raw_query_context["result_type"], **raw_query_object
|
||||
)
|
||||
assert query_object.series_limit == 5
|
||||
|
||||
def test_deprecated_timeseries_limit_zero_is_not_renamed(
|
||||
self,
|
||||
query_object_factory: QueryObjectFactory,
|
||||
raw_query_context: dict[str, Any],
|
||||
):
|
||||
"""timeseries_limit=0 is falsy — popped; series_limit defaults to 0."""
|
||||
raw_query_object = raw_query_context["queries"][0]
|
||||
raw_query_object.pop("series_limit", None)
|
||||
raw_query_object["timeseries_limit"] = 0
|
||||
query_object = query_object_factory.create(
|
||||
raw_query_context["result_type"], **raw_query_object
|
||||
)
|
||||
# 0 is falsy so it does not propagate — QueryObject default is also 0
|
||||
assert query_object.series_limit == 0
|
||||
|
||||
Reference in New Issue
Block a user