order_by_cols is a raw-mode-only control (resetOnHide: false), so an
aggregate chart can carry a stale value. The form-data query-context
rebuild read it in every mode, which could order an aggregate export by
stale columns and return a different top-N than the chart shows. Gate it
behind is_raw_query_mode so aggregate mode falls back to the metric-based
ordering, mirroring the frontend Table buildQuery.
Also add frontend-drift pointers naming the mirrored buildQuery /
extractQueryFields / processFilters sources, and a regression test for an
aggregate table with a stale order_by_cols.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Further review of the form-data query-context rebuild:
- Raw-mode tables: ignore stale metrics/groupby (their controls aren't
reset when hidden) and use only the selected columns, mirroring the
frontend's getQueryMode (explicit query_mode, else all_columns).
- Ordering: default order_desc to False (ascending) for Table sort
metrics and True for Pie, matching the plugins — so a row limit keeps
the chart's top/bottom-N instead of flipping it.
- percent_metrics: skip the chart (re-save) rather than silently omitting
the "% of total" columns the user sees, alongside the other
unsupported-processing markers.
Adds regression tests for each; extracts a helper to keep the builder
under the complexity limit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address further review of the form-data query-context rebuild:
- Skip the rebuild when the form data relies on processing the single
query can't reproduce: time_compare, rolling_type, resample_rule, or
aggregation=raw. Even allowlisted viz types would otherwise export
values that differ from the chart.
- Big Number trendline: set granularity (so time_grain_sqla buckets the
promoted time column) even with no active time_range.
- Export applies only WHERE-clause SIMPLE filters (via a new where_only
arg), matching the chart, while the shared helper still converts all
SIMPLE filters for the MCP path.
Adds regression tests for each case.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Exclude percent_metrics from the rebuild: the chart shows them as a
"% of total" via contribution post-processing the rebuild can't apply,
so adding them as plain metrics would export raw aggregates that don't
match the chart.
- Restore converting all SIMPLE adhoc filters (not just WHERE-clause) so
SIMPLE HAVING filters the MCP compile/preview path relied on are not
silently dropped.
- Fall back to legacy since/until when time_range is absent, so older
charts export their configured range instead of the full history.
- Add an MCP-path test pinning that an explicitly empty `columns: []` no
longer shadows `groupby` (intentional behavior change), plus tests for
the since/until fallback and SIMPLE HAVING conversion.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address EnxDev review — the generic rebuild silently dropped several
query aspects, so allowlisted charts could export a different dataset
than they show:
- Ordering: derive `orderby` from order_by_cols (raw) or the sort metric
/ first-metric-descending (aggregate), so a `row_limit` returns the
chart's top-N instead of an arbitrary N.
- Time range: set `granularity` (from granularity/granularity_sqla) so
`time_range` is actually applied — but only when there is an active
range, so a numeric column saved as granularity_sqla with no range
isn't forced through date bucketing (verified against a real export).
- Custom SQL filters: map `SQL` adhoc filters + legacy top-level `where`
into `extras.where`/`extras.having` by clause instead of dropping them.
- Table specifics: carry `percent_metrics` into metrics and pass
`time_grain_sqla` through `extras`.
- Big Number: only promote granularity_sqla to a grouping column for the
trendline viz (`big_number`), never `big_number_total`.
Also point the MCP chart compile/preview helpers
(adhoc_filters_to_query_filters, _build_query_columns) at this shared
module so they stop diverging (preview_utils still had the pre-fix
`columns` bug), and address nits: drop the `-O`-stripped assert by
restructuring the loop, parse the saved query_context once, and correct
the shallow-copy comment.
Adds unit tests for every derived field plus an export test asserting the
full query body reaches ChartDataQueryContextSchema().load.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review of the empty query-context rebuild:
- columns_from_form_data no longer lets a stale, explicitly-present-but-
empty `columns: []` key shadow the group-by dimensions (which silently
dropped grouping and changed the aggregation). Prefer raw columns only
when non-empty, else fall back to groupby.
- build_query_context_from_form_data now also honors legacy simple
`filters` (already in QueryObject {col, op, val} shape) in addition to
`adhoc_filters`, so legacy charts export the same filtered data they
show; malformed entries are dropped.
- _rebuild_viz_types checks the config for None explicitly instead of
using `or`, so an operator can disable the rebuild with an empty set
instead of it silently falling back to the default allowlist.
Adds unit tests for each case.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Charts persist a query_context only once (re-)saved in Explore, so older
charts have params (form data) but no context and were skipped entirely
by the data export. When the saved context is empty, synthesize one from
the chart's form data (columns, metrics, adhoc filters, time range) and
run that instead.
The rebuild is a generic single-query mapping — it does not reproduce
plugin post-processing (pivot, rolling, forecast) or multi-query charts —
so it is gated to a conservative viz-type allowlist
(EXCEL_EXPORT_REBUILD_VIZ_TYPES: table, big_number_total, big_number,
pie). Charts of any other type without a saved context are still skipped
and listed for re-save, so no chart exports silently wrong or incomplete
data.
The form-data -> query-context logic lives in a new shared module
(superset.common.form_data_query_context), mirroring the approach the MCP
chart compile/preview path already uses. Adds unit tests for the builder
and export integration tests for the eligible-rebuild and
ineligible-skip paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>