Skip to content

SQL DDL → ER: a CREATE TABLE front-end with PK/FK/UK badges - #12

Merged
clintecker merged 1 commit into
mainfrom
feature/sql-ddl-frontend
Jul 17, 2026
Merged

SQL DDL → ER: a CREATE TABLE front-end with PK/FK/UK badges#12
clintecker merged 1 commit into
mainfrom
feature/sql-ddl-frontend

Conversation

@clintecker

@clintecker clintecker commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

A third front-end (after DOT and Dippin): point a SQL schema dump at MermaidKit and get an ER diagram. SQLDDLParser.parse(_:) turns CREATE TABLE … into the ERDiagram IR, rendered through the same layered layout as a Mermaid erDiagram.

What it parses

  • Tables & typed columnsCREATE TABLE t (col TYPE, …), including size clauses (VARCHAR(100), DECIMAL(10,2)).
  • KeysPRIMARY KEY / UNIQUE / FOREIGN KEY, both inline and table-level (incl. CONSTRAINT name …), shown as compact PK / FK / UK badges.
  • Relationships — each REFERENCES / FOREIGN KEY maps to a one-to-many crow's-foot relation (parent ||--o{ child).
  • Dialect quoting"x", `x`, [x]; -- and /* */ comments; unknown clauses (CHECK, INDEX, DEFAULT, engine options) ignored, never fatal.
  • Degrades gracefully — malformed/huge/hostile input returns nil under the shared maxTextSize/maxEdges caps; forward-progress guards throughout.

Example

CREATE TABLE customer (id INT PRIMARY KEY, email VARCHAR(255) UNIQUE, name VARCHAR(100));
CREATE TABLE orders (id INT PRIMARY KEY, customer_id INT REFERENCES customer(id), total DECIMAL(10,2));

→ two entity boxes with PK/UK/FK badges and a customer ||--o{ orders relationship (rendered image in the thread).

IR change

ERDiagram.Attribute gains keys: [Key] (PK/FK/UK), drawn as a right-aligned badge. The badge/width code is a strict no-op when keys is empty, and the Mermaid erDiagram parser still leaves it empty — so existing ER output is byte-identical (no gallery/perf regen). keys has a defaulted initializer, so no existing Attribute(type:name:) call site changes.

311 tests, 0 failures (12 new). Platform-free parser in MermaidLayout, beside DOTParser/DippinParser.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Adds SQLDDLParser.parse(_:), a Swift front-end that turns a SQL schema dump into
the ERDiagram IR, so it renders through the same layered layout as a Mermaid
erDiagram. Parses the structural core — CREATE TABLE, typed columns, PRIMARY /
FOREIGN / UNIQUE keys (inline and table-level), and REFERENCES — mapping each
foreign key to a one-to-many crow's-foot relationship. Dialect quoting ("x",
`x`, [x]), comments, and unknown clauses (CHECK/INDEX/DEFAULT/engine options) are
handled or ignored, never fatal; malformed/huge/hostile input returns nil under
the shared maxTextSize/maxEdges caps.

IR + render: ERDiagram.Attribute gains a `keys: [Key]` field (PK/FK/UK), rendered
as a compact right-aligned badge in the entity box. The badge/width code is a
strict no-op when keys is empty, so Mermaid erDiagram output is unchanged (its
parser still leaves keys empty) — no gallery/perf regen triggered.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JoLDcosyaHg3tAKhU5SQaw
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8f42940b-30f0-464c-aae3-be317be2597b

📥 Commits

Reviewing files that changed from the base of the PR and between c450e90 and 5285112.

📒 Files selected for processing (6)
  • Sources/MermaidLayout/DiagramLayoutBoxDiagrams.swift
  • Sources/MermaidLayout/MermaidModels.swift
  • Sources/MermaidLayout/SQLDDLParser.swift
  • Sources/MermaidRender/DiagramRenderer+ER.swift
  • Tests/MermaidLayoutTests/SQLDDLParserTests.swift
  • Tests/MermaidRenderTests/SQLRenderTests.swift
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/sql-ddl-frontend

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 528511290a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +137 to +138
let table = t[i].text; i += 1
guard isPunct("(", at: i) else { skipStatement(); return } // e.g. CREATE TABLE x AS SELECT …

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse qualified table names before requiring the body

For schema-qualified DDL such as CREATE TABLE public.customer (...), the lexer drops the dot and produces two word tokens; this line records public as the table name, and the next line then sees customer instead of ( and skips the whole statement. That means common pg_dump/MySQL dump inputs with qualified names parse as nil or miss most tables instead of producing an ER diagram.

Useful? React with 👍 / 👎.

Comment on lines +241 to +243
case "unique":
p += 1
for col in parenCols(item, &p) { addKey(.unique, to: col, in: &attrs, indexOf: indexOf) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle named UNIQUE table constraints

When a dump uses MySQL-style table constraints like UNIQUE KEY email_idx (email) or UNIQUE INDEX ..., p points at KEY/INDEX rather than (, so parenCols returns an empty list and the column never gets a UK badge. This misses a common form of table-level unique constraint even though the parser advertises table-level UNIQUE support.

Useful? React with 👍 / 👎.

Comment on lines +188 to +189
if p < item.count, item[p].word {
type = item[p].text; p += 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve multi-word SQL column types

This only captures the first word of a type and only attaches a size clause when it immediately follows that word, so valid dump output like character varying(255), double precision, or timestamp without time zone is rendered as just character, double, or timestamp. For schemas using these common PostgreSQL types, the generated ER attributes show incorrect type information.

Useful? React with 👍 / 👎.

@clintecker
clintecker merged commit 30ef18e into main Jul 17, 2026
2 of 3 checks passed
@clintecker
clintecker deleted the feature/sql-ddl-frontend branch July 17, 2026 01:54
clintecker added a commit that referenced this pull request Jul 17, 2026
…n bad fixture

- SQLDDLParserTests imported CoreGraphics unconditionally (landed in #12, macOS-
  only gating missed it) → Linux CI red since. Guard it like DOTParserTests
  (#if canImport(CoreGraphics) … #else import Foundation). Restores Linux green.
- DeterminismSignatureTests: XCTUnwrap parse + rasterize instead of skip/nil, so
  a fixture that silently fails can't make the determinism diff pass vacuously
  (CodeRabbit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JoLDcosyaHg3tAKhU5SQaw
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