feat(schema): drag a DB/table into the data pane for a lineage graph#41
Merged
Conversation
Drag a database or table row from the schema sidebar onto the results pane to render a graph of ClickHouse object relationships — not generic FKs, but engine-specific lineage: materialized views (feeds from sources, writes to target), views (reads sources), dictionaries (dict from source), and Distributed/Buffer/Merge engine refs. Drag a DB → whole-DB lineage (isolated tables pruned); drag a table → 1-hop neighbourhood; click a node to re-centre; Expand for fullscreen pan/zoom. Nodes are kind-coloured with a legend; edges coloured + labelled by relationship. Discovery is structured-first, parse-fallback: prefer dependencies_table / loading_dependencies_* / dictionaries.source when populated, else let ClickHouse parse the SQL via EXPLAIN AST (query sources) + light regex on create_table_query (TO target) and engine_full (Distributed/Buffer/Merge). This keeps it working on older deployed builds (verified live on otel CH 26.3.10, where target_* is absent and dependencies_* can be empty). - src/core/schema-graph.js (NEW, pure, 100%): objectKind, parseAstTables, parseMvTarget, parseDictSource, parseEngineRef, buildSchemaGraph - src/net/ch-client.js: loadSchemaLineage (scope query + EXPLAIN AST per view/MV) - src/core/dot-layout.js: pass node kind + edge label through dagre layout - src/ui/explain-graph.js: extract renderGraphSvg; buildSchemaSvg; generalize the fullscreen overlay; renderSchemaGraph + legend + click-to-expand - src/ui/results.js: render r.schemaGraph + toolbar (Schema · <focus> + Expand) - src/ui/schema.js + editor.js: second SCHEMA_GRAPH_MIME drag payload on rows - src/ui/app.js: results-region drop target + showSchemaGraph action - styles.css: kind-coloured nodes/edges + legend (scoped so kind fill wins) - tests: schema-graph unit + e2e harness/spec; results/app/schema/ch-client/ explain-graph specs; per-file coverage gate holds (852 tests) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
…regex Two findings from the code-review pass on src/core/schema-graph.js: - The addEdge dedup key joined fields with literal NUL bytes (`'\x00'`), which made git treat the whole file as binary (no diffs, breaks review tooling). Replaced with JSON.stringify([from,to,kind]) — collision-proof and text. - new RegExp(ref.regex) for a Merge engine could throw on a pathological pattern, violating the module's documented "never a throw" contract. Wrapped in try/catch (an invalid pattern just yields no merge edges) + a test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
… run showSchemaGraph now renders a spinner placeholder (reusing the query "starting" pattern) before awaiting the lineage queries — system.* plus an EXPLAIN AST per view/MV, which is noticeable on large databases — then swaps in the graph when they resolve. The Expand button is hidden until the graph has loaded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
Reworks the inline schema-graph interaction so clicking is the primary gesture: - Normal (default) cursor over the graph data area instead of the grab hand; nodes keep the pointer cursor. - Drag-to-pan now requires ⌘/Ctrl held (attachPanZoom gains a modifierPan option), so a plain click lands on a node rather than grabbing the canvas. The pipeline graph and the fullscreen overlay keep plain drag-to-pan. - Clicking an object runs SHOW CREATE for it and drops the formatted DDL into the editor (reuses the insertCreate action — same as a shift-click in the schema tree), replacing the previous click-to-expand. External dictionary-source leaves are inert. Verified live on otel: cursor default, plain drag no-ops, ⌘-drag pans, and clicking claude_otel.mv_api_latency_by_model wrote its CREATE DDL to the editor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
This was referenced Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Drag a database or table row from the schema sidebar onto the results pane to render a graph of ClickHouse object relationships — not generic foreign keys, but engine-specific lineage:
feedsfrom sources,writesto the targetreadstheir sourcesdictfrom a source table (or anexternalleaf for non-CH sources)Drag a DB → whole-DB lineage (isolated tables with no relationships are pruned so the lineage is the focus); drag a table → its 1-hop neighbourhood. Click any node to re-centre on it; Expand for a fullscreen pan/zoom view (same controls as the pipeline graph). Nodes are kind-coloured with a legend; edges are coloured + labelled by relationship.
How discovery works (structured-first, parse-fallback)
The helpful
system.tablescolumns are build-dependent, so the loader prefers structured columns (dependencies_table/loading_dependencies_*/system.dictionaries.source) when populated, and otherwise lets ClickHouse parse the SQL viaEXPLAIN AST(query sources) plus light regex oncreate_table_query(TOtarget) andengine_full(Distributed/Buffer/Merge args).EXPLAIN AST'sTableIdentifierlines are cross-checked against real objects, dropping CTE/alias false-positives.This was validated empirically: on otel (Altinity-antalya CH 26.3.10) a real MV has no
target_*column and emptydependencies_*— a pure-structured approach would render nothing there, so theEXPLAIN AST+ create-query parsing path is required for the builds we deploy to.Verified live
Deployed the branch build to otel and dragged
bentoclickonto the results pane:dashboards_raw —feeds→ dashboards_mv —writes→ dashboards_tok —reads→ dashboards(thewritestarget came from parsingTO, thefeeds/readsfromEXPLAIN AST— the parse-fallback path). Click-to-expand ondashboards_mvcorrectly re-focused to its 1-hop neighbourhood. Kind-colouring (purple MV, teal views, blue dictionaries) and the legend render correctly in both Chrome and Firefox (verifiedcolor-mixresolves, not the dark base).Layers / tests
src/core/schema-graph.js(NEW, pure, 100%-covered) — all parsers +buildSchemaGraphsrc/net/ch-client.js—loadSchemaLineage(scope query + per-view/MVEXPLAIN AST)src/core/dot-layout.js— pass nodekind+ edgelabelthrough the dagre seamsrc/ui/explain-graph.js— extractedrenderGraphSvg;buildSchemaSvg; generalized fullscreen overlay;renderSchemaGraph+ legend + click-to-expandsrc/ui/results.js,schema.js,editor.js,app.js— render dispatch, secondSCHEMA_GRAPH_MIMEdrag payload, results-region drop target +showSchemaGraphactionstyles.css— kind-coloured nodes/edges + legend (node-kind rules scoped under.explain-graphso the kind fill beats the base — this was a real bug caught in live testing)Notes for review
play.clickhouse.com/schema), an insert heat-map, and refreshable-MV badges are intentionally deferred to fast-follow (see the plan).tests/e2e/schema-graph.spec.js) runs in CI / locally — Playwright browsers can't launch in the dev sandbox (SIGTRAP), which also affects the pre-existing pipeline spec; the Firefox render path was instead verified against the live harness via the agent browser.🤖 Generated with Claude Code