Compare commits

...

3 Commits

Author SHA1 Message Date
rusackas
d4e1238401 test(jinja): assert against the actual rendered subquery, not a re-derived one
The second assertion in the drill-to-detail regression test constructed
its own template processor (via get_template_processor(filter=...)) to
check that filter_values() rendered into the virtual dataset's SQL. That
bypassed get_sqla_query()'s own internal wiring: if get_sqla_query() ever
stopped forwarding `filter` to the template processor it builds
internally, this assertion would still pass, since it renders an
independently-constructed processor rather than the one actually used to
build the query. Pull the virtual dataset's rendered SQL directly out of
the compiled query's FROM clause instead, so the assertion exercises the
real code path.

Verified by temporarily removing the filter forwarding in
get_sqla_query() (simulating the exact regression) - the test failed as
expected with this change, and passed before it (masking the bug).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-31 16:10:35 -07:00
rusackas
90096274b8 test(jinja): assert filter_values() renders into the virtual dataset's own SQL
The existing assertion only checked the fully compiled outer query, but
get_sqla_query() independently applies native filters as an outer WHERE
predicate regardless of whether filter_values() picked them up inside the
virtual dataset's templated SQL. That let the regression test pass even
when filter_values() itself failed to resolve native drill-to-detail
filters. Add a second assertion against get_rendered_sql() output, which
isolates the virtual dataset's own rendered SQL before it's wrapped in the
outer query.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 11:57:13 -07:00
Claude Code
75800519e7 test(jinja): pin filter_values() drill-to-detail native-filter fallback for virtual datasets
Closes #35263

Regression test for issue #35263, which reports that Drill to
Detail/Drill by on Jinja-templated datasets returns zero rows even
though the parent chart shows data for the selected value.

Investigation found the reported gap already closed on master:
ExtraCache.get_filters()/filter_values() in superset/jinja_context.py
falls back to reading the native {col, op, val} filter format that
Drill to Detail/Drill by send (query_obj["filter"]), rather than only
the adhoc_filters format used by ordinary chart/explore requests. That
fallback is already unit-tested in isolation
(tests/unit_tests/jinja_context_test.py), but nothing exercised it
through a real virtual (Jinja-SQL) dataset end-to-end via
SqlaTable.get_sqla_query, which is the exact code path the reporter's
dataset goes through.

This adds that missing end-to-end regression test: a virtual dataset
whose own SQL calls filter_values() in a WHERE clause, queried with a
native-format filter (mirroring what a drill request sends), asserting
the rendered SQL contains the drilled-into value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 17:49:29 -07:00

View File

@@ -2405,6 +2405,76 @@ def test_get_sqla_query_allows_jinja_templated_custom_sql_metric_with_columns(
assert "{{" not in sql
def test_get_sqla_query_virtual_dataset_filter_values_drill_to_detail(
database: Database,
) -> None:
"""
Regression for #35263: a Jinja-templated virtual dataset that calls
``filter_values()`` in its own SQL must see filters sent in the native
``{col, op, val}`` format that Drill to Detail/Drill by use, not just
the ``adhoc_filters`` format used by ordinary chart/explore requests.
Without this, Jinja-based datasets return zero rows when drilled into,
even though the parent chart shows data for the selected value.
"""
from superset.connectors.sqla.models import SqlaTable, TableColumn
table = SqlaTable(
database=database,
schema=None,
table_name="t",
sql=(
"SELECT a, b FROM t WHERE 1=1 "
"{% if filter_values('b') %} "
"AND b IN {{ filter_values('b') | where_in }} "
"{% endif %}"
),
columns=[
TableColumn(column_name="a", type="INTEGER"),
TableColumn(column_name="b", type="TEXT"),
],
)
result = table.get_sqla_query(
columns=["a", "b"],
metrics=[],
extras={},
filter=[{"col": "b", "op": "IN", "val": ["Alice"]}],
granularity=None,
is_timeseries=False,
)
assert result is not None
with database.get_sqla_engine() as engine:
sql = str(
result.sqla_query.compile(
dialect=engine.dialect,
compile_kwargs={"literal_binds": True},
)
)
assert "'Alice'" in sql, (
"filter_values() should resolve native drill-to-detail-style "
f"filters inside a virtual dataset's own SQL. Generated SQL: {sql}"
)
# The assertion above can pass even when filter_values() itself is
# broken, because get_sqla_query() independently applies the native
# filter as an outer WHERE predicate on top of whatever the virtual
# dataset's own SQL renders to. Pull the virtual dataset's own rendered
# SQL directly out of the compiled query (rather than re-rendering it
# via a separately constructed template processor, which would not
# catch get_sqla_query() failing to forward the filter to the template
# processor it builds internally) to confirm filter_values() actually
# resolved the native filter *inside* the templated subquery.
virtual_table_from = result.sqla_query.get_final_froms()[0]
rendered_inner_sql = virtual_table_from.element.element.text
assert "'Alice'" in rendered_inner_sql, (
"filter_values() should render the native drill-to-detail-style "
"filter directly into the virtual dataset's own templated SQL, "
f"not just the outer query. Rendered SQL: {rendered_inner_sql}"
)
def test_extras_where_is_parenthesized(
database: Database,
) -> None: