Skip to content

feat(common): canonical single-query serialization for async chart data - #43410

Merged
villebro merged 1 commit into
apache:gaq-to-gtffrom
villebro:villebro/query-object-serialization
Aug 22, 2026
Merged

feat(common): canonical single-query serialization for async chart data#43410
villebro merged 1 commit into
apache:gaq-to-gtffrom
villebro:villebro/query-object-serialization

Conversation

@villebro

Copy link
Copy Markdown
Member

Part of the GAQ→GTF epic — this is PR 2 (Canonical QueryObject serialization), targeting the gaq-to-gtf feature branch.

SUMMARY

Adds a canonical, JSON-safe, self-contained serialization for a single chart-data query — the atomic unit a later PR (PR 3) will run as its own async GTF task. Today the async path serializes the entire query context (the request dict misleadingly named form_data); PR 3 will instead fan out one task per QueryObject, and each task needs to reconstruct exactly its query so it caches under the same query_cache_key as the synchronous path. This PR provides that primitive (with tests); PR 3 consumes it.

API (superset/common/query_serialization.py):

  • serialize_query(query_context, query_index) -> SerializedQuery — a JSON-safe dict of the raw query (from QueryContext.cache_values["queries"]) plus the context-level inputs needed to rebuild it: datasource, form_data, result_type, result_format, force, custom_cache_timeout.
  • load_serialized_query(payload) -> QueryContext — rebuilds a single-query QueryContext via QueryContextFactory (the same path that produced the original), so query_cache_key matches.

Why the raw query, not QueryObject.to_dict(). Reconstructing from to_dict() would change the cache key: to_dict() emits from_dttm/to_dttm as raw datetimes, uses the key filter where the factory expects filters, and omits time_range/datasource/result_type. Serializing the raw schema-shaped query and rebuilding through the factory reuses the exact key-producing path (the same pattern Slice.query_context already relies on), giving a provably identical query_cache_key.

force/custom_cache_timeout survival. These live on QueryContext, not QueryObject, so a per-query payload must carry them explicitly — they're serialized and restored, and the integration test asserts it.

BEFORE / AFTER

No behavior change to the live async flow in this PR — it adds a foundation primitive. The misleading form_data rename and the duplicate _create_query_context_from_form dedup are intentionally deferred to PR 3, which rewrites tasks/async_queries.py and replaces create_async_job_command.py (doing the rename here would be throwaway).

TESTING INSTRUCTIONS

  • Unit (tests/unit_tests/common/test_query_serialization.py, green locally): payload extraction reads the raw query + context params; payload is JSON round-trippable; load_serialized_query reconstructs via QueryContextFactory with result_type/result_format back as enums.
  • Integration (tests/integration_tests/query_context_tests.py::test_serialize_query_round_trip_preserves_cache_key): builds a real birth_names query context, serializes + reloads query 0, and asserts the reconstructed query_cache_key equals the original and that force/custom_cache_timeout/result_type/result_format survive.

ADDITIONAL INFORMATION

  • Has associated issue
  • Changes UI
  • Includes DB Migration
  • Introduces new feature or API (serialize_query / load_serialized_query)
  • Removes existing feature or API

Note: the whole-project frontend type-check has pre-existing failures unrelated to this change.

Add a JSON-safe, self-contained serialization for one chart-data query, the unit
a later PR runs as its own async task. serialize_query() emits the *raw* query
dict (from QueryContext.cache_values) plus datasource/form_data/result_type/
result_format/force/custom_cache_timeout; load_serialized_query() rebuilds a
single-query QueryContext via QueryContextFactory — the same path that produced
the original — so the reconstructed query hashes to an identical query_cache_key
and reads/writes the same DATA-cache entry as the sync path.

Serializing the raw query (not the processed QueryObject.to_dict(), which emits
raw datetimes, renames filters->filter, and drops time_range/datasource) is what
makes the round trip cache-key-stable, and force/custom_cache_timeout (which live
on the context, not the query) are carried explicitly so they survive per query.

Unit tests (payload extraction, JSON-safety, factory reconstruction) plus an
integration round-trip test asserting identical query_cache_key + force/
custom_cache_timeout survival. The async-chain rename/dedup of the misleading
form_data param lands with PR 3, which rewrites those files.
@bito-code-review

bito-code-review Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped - Branch Excluded

Bito didn't auto-review because the source or target branch is excluded from automatic reviews.
No action is needed if you didn't intend for the agent to review it. Otherwise, to manually trigger a review, type /review in a comment and save.
You can change the branch exclusion settings here, or contact your Bito workspace admin at evan@preset.io.

@netlify

netlify Bot commented Aug 22, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 2e616d6
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a891ef8b1814f000859c990
😎 Deploy Preview https://deploy-preview-43410--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@villebro
villebro marked this pull request as ready for review August 22, 2026 04:07
@dosubot dosubot Bot added api Related to the REST API global:async-query Related to Async Queries feature labels Aug 22, 2026
@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.88%. Comparing base (c7fcebf) to head (2e616d6).

Additional details and impacted files
@@              Coverage Diff               @@
##           gaq-to-gtf   #43410      +/-   ##
==============================================
- Coverage       78.88%   78.88%   -0.01%     
==============================================
  Files            2882     2883       +1     
  Lines          164715   164715              
  Branches        38028    38027       -1     
==============================================
- Hits           129938   129937       -1     
- Misses          32331    32332       +1     
  Partials         2446     2446              
Flag Coverage Δ
hive 38.10% <0.00%> (-0.02%) ⬇️
mysql 57.80% <0.00%> (-0.02%) ⬇️
postgres 57.83% <0.00%> (-0.02%) ⬇️
presto 40.03% <0.00%> (-0.02%) ⬇️
python 83.58% <100.00%> (-0.01%) ⬇️
sqlite 57.53% <0.00%> (-0.02%) ⬇️
unit 73.60% <100.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@villebro

Copy link
Copy Markdown
Member Author

/review

@bito-code-review

bito-code-review Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #59350e

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset/common/query_serialization.py - 1
Review Details
  • Files reviewed - 3 · Commit Range: 2e616d6..2e616d6
    • superset/common/query_serialization.py
    • tests/integration_tests/query_context_tests.py
    • tests/unit_tests/common/test_query_serialization.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@villebro
villebro merged commit 4dea578 into apache:gaq-to-gtf Aug 22, 2026
109 of 120 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Related to the REST API global:async-query Related to Async Queries feature size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant