Visitar URL original
feat: dbt_sql_graph tool — a model's CTEs, joins and filters as a graph by hkaltai · Pull Request #1735 · AltimateAI/altimate-code · GitHub
Skip to content

feat: dbt_sql_graph tool — a model's CTEs, joins and filters as a graph - #1735

Draft
hkaltai wants to merge 5 commits into
mainfrom
feat/dbt-sql-graph-tool
Draft

hkaltai wants to merge 5 commits into
mainfrom
feat/dbt-sql-graph-tool

Conversation

@hkaltai

@hkaltai hkaltai commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

None

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds the dbt_sql_graph { model } tool. It compiles the model with the project's dbt integration, reads its non-ephemeral parents' columns from the warehouse's metadata, and sends the compiled SQL to the Altimate backend's dbt/v3/sql_lineage endpoint (api/sql-lineage.ts). The backend's __final_select__ is renamed after the model and each relation node is tied to its dbt unique id, as Power User does. The result is { nodes: [{ name, type, nodeId?, sql, columns }], edges: [[from, to]] } plus a one-line-per-node text list. It is adapter-backed, so it needs write permission and an Altimate key; read-only calls get the foundation's refusal.

This branch contains the Power User foundation commits (feat/pu-mods-foundation); this PR's own change is tools/dbt-sql-graph.ts, api/sql-lineage.ts and test/altimate/dbt-sql-graph.test.ts.

How did you verify your code works?

bun test test/altimate/dbt-sql-graph.test.ts (11 tests, mocked endpoint and adapter: the remap, source and model parents, column merge, failures, abort) and bun typecheck, both from packages/opencode.

Cost side effects

One backend call and one warehouse metadata read (getBulkSchemaFromDB, parents only) per dbt_sql_graph call. Nothing runs per edit. The model's compile can run SQL only as the dbt integration already does for any compile.

Screenshots / recordings

Demo video to follow.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR
  • I checked for cost side effects (model calls, queries or cloud resources that grow with user data) and described them, or wrote "none"

Changelog:

  • Added the dbt_sql_graph tool: a dbt model's CTEs, joins and filters as a graph.

🤖 Generated with Claude Code


Summary by cubic

Adds the dbt_sql_graph { model } tool, which compiles a model with the dbt adapter and returns its CTEs, joins, and filters as a graph of nodes and edges, and lays the shared foundation for adapter-backed Altimate tools.

  • The tool sends the compiled SQL to the Altimate backend's dbt/v3/sql_lineage endpoint, names the final select after the model (<model> (final select) when the SQL already has a node by that name), and ties each relation to its dbt unique id.
  • The graph merges each parent's manifest columns with the warehouse's reported columns, keyed by the adapter's folding case, so the backend sees complete schemas.
  • Only SQL models are accepted: seeds, snapshots, and Python models are refused before anything compiles.
  • dbtAdapterFor is the single gate for adapter-backed tools: it refuses read-only calls, sessions in a different dbt project, and an adapter that didn't start, with a bounded wait that follows call aborts.
  • AltimateApi.apiRequest posts to any backend endpoint with the stored credentials and a clear error naming the credentials file when missing.
  • Eight stubs (dbt_run_results, dbt_defer_state, dbt_map_relations, docs_share_comments, dbt_cost_estimate, dbt_health, dbt_docs_coverage, dbt_cte_profile) are exposed through the tool allow-list as not-yet-implemented placeholders.
  • The tool needs write permission and an Altimate key; each call costs one backend request and one warehouse metadata read of the model's parents only.

Written for commit f6aed61. Summary will update on new commits.

View guided diff Turn on auto-fix

hkaltai and others added 3 commits November 13, 2026 16:30
Nine tool stubs exposed through `altimate tool run` (dbt_run_results,
dbt_defer_state, dbt_map_relations, docs_share_comments, dbt_cost_estimate,
dbt_health, dbt_sql_graph, dbt_docs_coverage, dbt_cte_profile), an exported
`AltimateApi.apiRequest` that calls the backend with the stored credentials,
and `dbtAdapterFor`, the one gate every adapter-backed tool goes through:
it refuses read-only calls, other projects, and an adapter that did not start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compiles the model, reads its parents' columns from the warehouse's metadata, and asks the Altimate backend's sql_lineage endpoint; the graph's final select is named after the model and its relations are tied to their dbt nodes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 13, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

hkaltai and others added 2 commits November 13, 2026 17:09
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…fore compile, model-name collisions, models only

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@hkaltai

hkaltai commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

Review of this change (two independent reviewers, then a separate check of the fixes). Each finding and what happened to it, fixed in f6aed61:

Fixed

  • Column case — mergeColumns lower-cased everything unless it carried literal quote characters, so Postgres Foo/foo and Snowflake Foo/FOO merged into one column. It now follows dbt Power User's rule: a name the adapter would only keep when quoted keeps its case (adapter-aware, same regexes as isQuotedIdentifier).
  • Session id — session_id was only the SQL hash, so two sessions asking for the same SQL sent the same id. It is now <session id>-<md5 of the compiled SQL>, as Power User does.
  • Cancel before compile — an abort during parseManifest still compiled the model. The abort signal is now checked after the manifest and after the compile, before the warehouse read.
  • constructor / __proto__ columns — a warehouse column with an Object member's name hit the inherited property and wrote to Object.prototype. The merge now uses a Map.
  • Model name vs. CTE — a CTE or {{ this }} table named like the model (e.g. with customers as (...) in customers.sql) was overwritten by the model's own select and could form a cycle. The model's select is now <model> (final select) when the name is taken. Power User's remap has the same overwrite; this is a deliberate difference.
  • Seeds, snapshots, Python models — a name that resolved to one of those had its file compiled and sent. Only resource_type: model with a .sql path is accepted now.
  • Comment — formatSqlGraph no longer claims dependency order.
  • Tests — full model_info request with toEqual, both case families, the Object-member names, the name collision (CTE and source), refused node types, cancel during parse and compile, session id per session. dbt-adapter-access.test.ts now skips this tool in its placeholder loop.

Not changed, on purpose

  • Credentials are checked inside apiRequest, after the adapter has started and the model has compiled. Checking earlier is a cost nicety; left for a follow-up.
  • The backend fetch ignores the abort signal and has a fixed 15 s timeout. That is in the shared client (api/client.ts), not this change.
  • Node name vs. edge key, and two parents with the same alias: unconfirmed against the backend's real replies; left as is.
  • Column description/meta go to the backend with the compiled SQL: same as Power User.

Cost side effects are unchanged: one backend call and one warehouse metadata read per call.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant