Skip to content

feat(master-ui): add read-only SQL query tab for experiments - #177

Merged
beinan merged 2 commits into
lance-format:mainfrom
beinan:feat/master-ui-sql-tab
Jul 24, 2026
Merged

feat(master-ui): add read-only SQL query tab for experiments#177
beinan merged 2 commits into
lance-format:mainfrom
beinan:feat/master-ui-sql-tab

Conversation

@beinan

@beinan beinan commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a SQL tab to the master control-plane UI: pick an experiment and run ad-hoc read-only SELECT queries against its rollout records (exposed as a table named records). Covers aggregations / group-bys the fixed-filter record browser can't express.
  • Queries run over the merged base + pending-WAL view, matching the record browser's default.
  • Read-only: only a single SELECT/CTE is accepted; DML/DDL/multi-statement input is rejected as a 400.

Backend

  • RolloutStore::query_sql materializes the merged non-blob rows into an in-memory DataFusion MemTable and runs the validated query (binary_payload excluded).
  • SELECT-only enforcement via DataFusion's SQL parser (ensure_select_only).
  • Bounded by SQL_MAX_SCAN_ROWS (200k, hard error) and SQL_MAX_RESULT_ROWS (10k, sets truncated instead of silently dropping rows).
  • POST /api/v1/experiments/{name}/query; SqlQueryRequest/SqlQueryResponse DTOs; MasterError::from_lance_user maps user SQL errors to 400, others to 500.
  • Deps: datafusion 53 + arrow-json 58 — the exact versions lance 7 already resolves (both on arrow 58.3.0), so no duplicate arrow/datafusion is pulled in. Cargo.lock delta is just two lines.

Frontend

  • New SqlConsole component + /sql route and nav tab: experiment picker, monospace SQL editor (Cmd/Ctrl+Enter to run), results grid (reuses the horizontally-scrollable .table-wrap), error box, and row-count / truncation notes.

Test plan

  • cargo test -p lance-context-core — new unit tests: count, group-by over merged data, binary_payload rejected, DELETE rejected, empty-experiment column resolution. Full lib suite: 158 passed.
  • Route test (etcd-gated #[ignore], like the existing record-endpoint tests): 200 valid / 400 DROP / 404 unknown experiment.
  • lance-context-core + lance-context-master build warning-free; UI builds clean (tsc + vite).
  • Manual: open the SQL tab, run SELECT problem_id, count(*) FROM records GROUP BY problem_id ORDER BY 2 DESC; confirm a malformed query surfaces the SQL error; confirm a just-written (un-merged/WAL) row appears.

Note: the pre-existing serial_merge_deletes_merged_generation_dirs integration test fails on main independently of this change.

🤖 Generated with Claude Code

beinan and others added 2 commits July 24, 2026 01:19
Adds a SQL console to the master control-plane UI so operators can run
ad-hoc read-only SELECT queries against a chosen experiment's rollout
records (exposed as a table named `records`), covering aggregations and
group-bys the fixed-filter record browser cannot express.

Backend:
- RolloutStore::query_sql materializes the merged base+WAL view into an
  in-memory DataFusion table and runs the query; binary_payload excluded.
- SELECT-only enforcement via DataFusion's SQL parser; DML/DDL, multiple
  statements, and non-queries are rejected as InvalidInput (HTTP 400).
- Bounded by SQL_MAX_SCAN_ROWS (materialization) and SQL_MAX_RESULT_ROWS
  (result); the latter sets a `truncated` flag rather than dropping rows
  silently.
- POST /api/v1/experiments/{name}/query route; SqlQueryRequest/Response
  DTOs; MasterError::from_lance_user maps user SQL errors to 400.
- datafusion 53 + arrow-json 58 pinned to the versions lance 7 already
  resolves, so no duplicate arrow/datafusion is introduced.

Frontend:
- New SQL tab/route with an experiment picker, SQL editor (Cmd/Ctrl+Enter
  to run), results grid, error box, and row-count/truncation notes.

Tests: core unit tests (count, group-by over merged data, blob column
rejected, DELETE rejected, empty-experiment columns) and an (etcd-gated)
route test for 200/400/404.

Co-Authored-By: Claude <noreply@anthropic.com>
- rustfmt: collapse over-wrapped assert!/let statements in the SQL tests.
- clippy (redundant_clone/useless_conversion): drop the identity
  `ArrowError::from` around arrow-json writer errors, which already return
  `ArrowError`; map straight through `LanceError::from`.

Co-Authored-By: Claude <noreply@anthropic.com>
@beinan
beinan merged commit 0baca0c into lance-format:main Jul 24, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant