mcdview
Turn a SQL data model into one self-contained HTML page you can open, share
and explore: an overview of every table, click one to isolate it with its
relations, field-level detail, search. No server, no build step, no
dependencies — the page opens straight from file://.
Try it on mcdview.dev (drop a .sql/.dbm, get a
shareable link) · Live demo ·
Example diagrams
Overview → rearrange → click a table to isolate it with its related tables → search. Open the live, interactive version.
The same tool renders a model right here
mcdview model.sql --to-mermaid emits a Mermaid erDiagram that GitHub and
GitLab draw natively — no image, no hosting:
erDiagram
categorie {
serial id PK
text nom
text slug
}
produit {
serial id PK
text nom
bigint prix
integer categorie_id FK
text sku
}
client {
serial id PK
text nom
text email
text telephone
}
commande {
serial id PK
integer client_id FK
date passee_le
bigint total
text statut
}
ligne {
serial id PK
integer commande_id FK
integer produit_id FK
integer quantite
numeric remise
}
avis {
serial id PK
integer produit_id FK
integer client_id FK
integer note
text commentaire
}
categorie ||--o{ produit : ""
client ||--o{ commande : ""
commande ||--o{ ligne : ""
produit ||--o{ ligne : ""
produit ||--o{ avis : ""
client ||--o{ avis : ""
What you get
- Explore any model. Overview grouped by schema, click a table to isolate
it with its neighbours, field detail (types, NOT NULL, DEFAULT, PK 🔑,
clickable FK 🔗, indexes, comments), search by table or column, drag to
rearrange (links follow live, positions remembered), force-directed relayout,
a minimap and level-of-detail for big models, light/dark toggle, SVG export,
#schema.tablepermalinks, keyboard shortcuts (/search,rrearrange, Esc overview). One HTML file, works offline. - Eight input formats. PostgreSQL and ~15 dialects (MySQL/MariaDB, SQLite,
SQL Server, Oracle…) via sqlglot;
pgModeler
.dbm, dbdiagram.io.dbml, Prisma, MySQL Workbench.mwb, Railsdb/schema.rb, MermaiderDiagram, Drizzleschema.ts. - Diff two versions.
--diff oldcolors what was added, removed and changed (tables, columns, foreign keys, indexes), detects renames, and can write a JSON summary (see below). - Mermaid export.
--to-mermaidfor a diagram that renders in any Markdown file. - Live database.
--db postgresql://…/mysql://…reads a running schema (CLI only). - Zero dependency by default. Python stdlib in, vanilla JS out. Hostile input is HTML-escaped and DoS-budgeted; the upload surface is hardened (XML/zip caps, converter timeouts).
- Tested at scale. 839 real-world schemas, synthetic models to 5000 tables, zero crashes.
Compare two versions
mcdview new.sql --diff old.sql — added tables/columns/FKs in green, removed
in red (kept, struck through), changed in amber, with a legend and a "show
only what moved" filter:
Install
pipx install mcdview # the CLI, isolated
pipx install "mcdview[dialects]" # + sqlglot for MySQL/SQLite/… input
Or run the script straight from a checkout — it has no dependency of its own:
./mcdview.py model.sql. The .dbm/.dbml/.prisma inputs still need their
external converter in the PATH (see Dialects).
Usage
mcdview model.sql # (or ./mcdview.py from a checkout)
./mcdview.py model.sql
./mcdview.py model.sql -o explorer.html --titre "My project"
./mcdview.py model.dbm # pgModeler model (needs pgmodeler-cli)
./mcdview.py model.dbml # dbdiagram.io model (needs @dbml/cli)
./mcdview.py schema.prisma # Prisma schema (needs prisma)
./mcdview.py model.mwb # MySQL Workbench model (native, no tool)
./mcdview.py db/schema.rb # Rails schema (native, no tool)
./mcdview.py diagram.mmd # Mermaid erDiagram (native, .mmd/.md)
./mcdview.py schema.ts # Drizzle ORM schema (native, no tool)
./mcdview.py --db postgresql://user:pw@host/db # dump a live database (CLI only)
./mcdview.py new.sql --diff old.sql # compare two versions of a model
Then open the generated HTML file in a browser.
--diff BASELINE compares the main model against an older one (each may be
any supported format) and colors the result: tables, columns and foreign keys
that were added show green, removed ones red and struck through
(kept on the diagram so you can see what went), changed ones amber. A
legend appears at the bottom with per-category counts and a "N touched"
button that hides the unchanged tables to frame just what moved. Handy for
reviewing a migration before running it.
--db reads the schema straight from a running database instead of a file:
postgresql://… shells out to pg_dump -s, mysql://… to mysqldump --no-data. It is a command-line-only feature — never wire it behind a
public service, since it would let a caller point the process at any host it
can reach (SSRF).
A .dbm input needs pgmodeler-cli in the PATH: mcdview delegates the
SQL generation to it (pgModeler resolves its relationships at export time),
and reuses the table positions drawn in the model.
In the page:
- wheel: zoom, drag: pan;
- hover a table: lights up its foreign-key links;
- click a table: isolates it with its related tables (the others fade
out, the view re-frames) and shows its detail on the right — fields,
types, NOT NULL, DEFAULT, PK 🔑, clickable FK 🔗, table and column
comments, list of referencing tables; the URL gets a
#schema.tablepermalink that reopens straight on that table; - drag a table to rearrange the diagram, the links follow live;
- "rearrange" button: a force-directed relayout that spreads the tables to unclutter the links (disabled above 400 tables, where it would be slow);
- schema chips (bottom-left, when there are several schemas): click to frame that schema's zone;
- Escape or "overview": back to the full, re-framed overview;
- search with table name autocompletion.
Options
| Option | Effect |
|---|---|
-o, --sortie FILE |
Output HTML file (default: <sql>.html) |
--titre TEXT |
Title shown in the page (default: file name) |
--dbm FILE |
Reuse table positions from a pgModeler model instead of automatic layout |
--fk-audit REGEX |
Tag as "audit" the FKs whose constraint name matches: hidden by default, shown back with a checkbox |
--lang {fr,en} |
Language of the page UI (default: fr) |
--dialect NAME |
Input SQL dialect (default: auto); non-PostgreSQL needs sqlglot |
--home-url URL |
Wrap the header logo in a link to this URL |
--logo FILE |
Replace the header logo with this image (svg/png/jpg…, shown 22×22) |
--credit TEXT |
Discreet attribution badge, bottom-right (off by default) |
--credit-url URL |
Make the --credit badge a link to this URL |
--db URL |
Read a live database's schema instead of a file (postgresql://… via pg_dump, mysql://… via mysqldump); CLI only |
--diff BASELINE |
Compare against an older model (any supported format); added/removed/changed tables, columns and FKs are colored |
--summary FILE |
With --diff: also write a JSON summary of the changes (counts + change list) to FILE |
--to-mermaid |
Output a Mermaid erDiagram (paste in a .md; GitHub/GitLab render it) instead of the HTML page |
--watch |
Regenerate the page whenever the input file changes (Ctrl-C to stop); file input only |
--diagnose |
Print a JSON diagnosis of the input (status ok/no_table/anomaly/error, dialect, counts, anomalies) instead of a page; exits 0 even on failure |
Without --dbm, mcdview computes an automatic layout: one zone per schema,
tables arranged in balanced columns, related tables pulled together.
Dialects
PostgreSQL uses the built-in parser (no dependency). For any other dialect,
pip install sqlglot and mcdview reads it — MySQL/MariaDB, SQLite, SQL Server
(tsql), Oracle, DuckDB, Snowflake, BigQuery, Redshift, ClickHouse, Trino,
Spark, Hive. --dialect auto (the default) uses the PostgreSQL parser first
and, when it finds no table, tries several sqlglot dialects and keeps the one
that parses the most tables; pass --dialect mysql (etc.) to force one. Model files are read through an upstream converter (an optional dependency,
like the SQL dialects): pgModeler .dbm via pgmodeler-cli,
dbdiagram.io .dbml via @dbml/cli, and Prisma schema.prisma via the
prisma CLI. MySQL Workbench .mwb, Rails db/schema.rb, Mermaid erDiagram
(.mmd/.mermaid/.md) and Drizzle ORM schema.ts are read natively
(no external tool needed). Other proprietary formats (Navicat,
ERwin, Oracle SQL Developer Data Modeler…) have no reliable converter: export
their SQL instead (Workbench-style Forward Engineer), which mcdview reads.
--fk-audit is for models where every table carries audit columns
(created_by, modified_by...) pointing to a users table: those FKs turn
that table into a hub linked to everything and clutter the graph.
What mcdview reads from the DDL
CREATE TABLE [schema.]table (...): columns, types, NOT NULL, DEFAULT (tables without an explicit schema go topublic);- primary keys, inline (
CONSTRAINT ... PRIMARY KEY) or added afterwards (ALTER TABLE ... ADD CONSTRAINT ... PRIMARY KEY,pg_dump -sstyle); ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ... REFERENCES ..., including composite keys and targets without an explicit column list (resolved against the target's primary key);- partitions (
PARTITION OF,ATTACH PARTITION): hidden from the diagram, their constraints are carried back to the parent table; COMMENT ON TABLEandCOMMENT ON COLUMN.
A pg_dump -s dump works as is. Views, functions and data are ignored.
Examples
Each example ships as a .sql in exemples/; the browsable pages are
rebuilt by CI on every push:
| Model | Contents | Source | |
|---|---|---|---|
| Médiathèque — fictional French library, shows schemas zones, comments and audit FKs | open | 12 tables, 3 schemas, 21 FKs | mediatheque.sql |
Pagila — DVD rental store (the PostgreSQL classic), with a partitioned payment table |
open | 16 tables, 22 FKs | Pagila (BSD) |
| Northwind — trading company, the historic Microsoft sample | open | 14 tables, 13 FKs | northwind_psql |
| Chinook — digital music store | open | 11 tables, 11 FKs | chinook-database (MIT) |
The real-world schemas are trimmed to their DDL (no data); each file keeps its source and license in a header comment. To regenerate, e.g.:
./mcdview.py exemples/mediatheque.sql --titre "Médiathèque (démo)" --fk-audit '_idmodificateur_fk$' --lang en
./mcdview.py exemples/pagila.sql --titre "Pagila (DVD rental)" --lang en
Development
Plain Python 3, no dependency. All the rendering lives in
templates/explorateur.html (inline CSS/JS); the data is injected as JSON
in place of __DONNEES__.
Tested at scale
The harness under tests/ last ran mcdview over 839 schemas: 529
real-world .sql and 296 pgModeler .dbm harvested from public GitHub
repositories, plus synthetic models up to 5000 tables. Results: zero
crashes; every PostgreSQL schema produced a valid page (17,449 tables and
19,788 FKs in total, DOM-verified on a sample in headless Chrome); MySQL
and SQLite inputs are detected and get a clear hint; 99% of the loadable
.dbm models convert (a --fix-model repair pass catches models saved by
older pgModeler versions). Median page build: 4 ms; worst case (5000
tables, 3.2 MB of DDL): 0.6 s.
Model data (names, types, comments, defaults) is HTML-escaped and the JSON
data island escapes every <, so a hostile schema cannot inject markup or
script into the page — this matters when generating pages from files you did
not write. tests/test_securite.py checks the escaping and a ReDoS/DoS time
budget on hostile inputs (tests/malveillant/).
tests/tester.py runs mcdview end-to-end on every committed example and
every pgModeler sample model, checks pinned table/FK counts and times each
run; tests/grand_banc.py runs the whole local corpus (--strict fails on
any exception, --dbm adds the pgModeler models, --chrome N DOM-validates
N sampled pages); tests/rapatrier.sh, tests/moissonner.py and
tests/generer_synthetique.py fill the local, uncommitted corpus.
tests/test_dialectes.py parses committed non-PostgreSQL fixtures, including
tests/dialectes/boutique.mariadb.sql — a frozen mysqldump --no-data dump
(backtick quoting, named inline CONSTRAINT FKs, a composite primary key)
that pins the exact SQL a --db mysql://… run feeds the parser, so the
--db path stays covered without a live server. The pre-commit hook
(git config core.hooksPath .githooks) runs the pinned regression, the
security suite and the strict corpus campaign.
License
MIT. The example schemas keep their own licenses, noted in each file's header.
Changelog
v0.24.1 — Soft-faded diagram edges (2026-08-30)
- The viewport edges fade softly, so a foreign-key link to a table currently off-screen (after panning) fades out at the border instead of stopping hard in mid-air (it used to read as "a link leading to nothing").
v0.24.0 — Robustness, --diagnose, and a big corpus sweep (2026-08-30)
- Swept mcdview over ~15,000 real-world files across every format; fixed
every crash found: a phantom
REFERENCEScolumn from a wrapped FK, and several sqlglot AST edge cases (exotic defaults, constraint/comment/index nodes) — plus a safety net so no sqlglot AST shape can crash the tool. - The built-in PostgreSQL parser reads single-line
CREATE TABLE t (a int);. - Faster
--dialect autoon large non-PostgreSQL files (dialect picked on a prefix, ~4–6× less parse time). - Rails FK columns resolve against the real columns and handle irregular
plurals (people→person); Drizzle
pgTableCreatorfactories are supported. --diagnoseprints a JSON verdict (status, dialect, counts, anomalies) and never fails — for a hosting service to flag problematic uploads.
v0.23.3 — Single-line DDL, --version (2026-08-30)
- The built-in PostgreSQL parser now reads a single-line / compact
CREATE TABLE t (a int, b numeric(10,2));(no newline after the open paren), not only thepg_dump(\nlayout. Before, such DDL only parsed when sqlglot was installed. Body splitting is depth- and string-aware, so a comma or paren inside a type or a'literal'never splits a column; still linear, still within the DoS budget. --versionprints the installed version.--dbis now covered end-to-end in CI (against a throwaway PostgreSQL service), not only manually.
v0.23.2 — Index diff on the sqlglot path (2026-08-30)
- Indexes and unique constraints are now extracted on the sqlglot path too
(
CREATE [UNIQUE] INDEX,ALTER … ADD CONSTRAINT … UNIQUE, inlineUNIQUE). Previously only the built-in PostgreSQL parser read them, so a single-lineCREATE TABLE …(which routes to sqlglot) reported no index changes in a diff. MySQLUNIQUE KEYis picked up as a bonus.
v0.23.1 — Installable from PyPI (2026-08-30)
- Published to PyPI:
pipx install mcdview(extra[dialects]pulls in sqlglot). The HTML template and logo ride along as bundled data; running the script straight from a checkout keeps working unchanged. Releases publish automatically on a version tag via PyPI Trusted Publishing (no stored token). - Fixed a backslash inside an f-string expression that broke the Mermaid export on Python 3.9–3.11 (only 3.12+ tolerated it).
v0.23.0 — Big-model UX, SVG export, richer diff (2026-08-29)
- Big models: a level-of-detail mode (table names only when zoomed out), a clickable minimap, and header-only table nodes above 800 tables (≈20× fewer DOM nodes) make a 1000+ table schema usable.
- SVG export: a toolbar button downloads the diagram as a portable SVG for docs and slides.
- Diff: indexes and unique constraints are now diffed too (shown in the panel, counted in the JSON summary); renames are detected by column overlap, not just an exact match.
- Multiple input files are merged into one model (
mcdview a.sql b.sql), cross-file foreign keys resolved. - Quality of life: dragged/rearranged positions are remembered
(localStorage), a light/dark toggle, keyboard shortcuts (
/,r, Esc), and--watchto regenerate the page on every save. - Indexes and unique constraints (
CREATE [UNIQUE] INDEX,ADD CONSTRAINT … UNIQUE) are parsed and shown in the detail panel.
v0.22.2 — Security and correctness audit (2026-08-29)
- XSS fix: a schema fill-color from a
.dbmwas injected into the page unescaped — a hostile model could run script in a viewer's browser. The color is now escaped like all other model data (andech()now escapes single quotes too, closing attribute-breakout). - ReDoS fix: the Mermaid and Rails block extraction backtracked
catastrophically on crafted input (a ~20 KB
.mmdtook ~18 s); both now use a bounded string search, and the DoS-budget test covers every parser, not just PostgreSQL. - Phantom-PK fix: a
DEFAULT 'PRIMARY KEY', aCHECKor an inline comment mentioning the words no longer marks a column as a primary key (regression from the inline-PK support). - Hardening:
url_surenow strips tab/newline/control chars before the scheme check (java\tscript:is neutralized); the XML DTD guard scans the whole document; malformed.mwb/.dbminputs exit cleanly instead of dumping a traceback. - Perf: the primary-key regexes are precompiled and guarded (~130 ms off a 5000-table parse); the column search suggests columns only on models under 300 tables (avoids a ×10 datalist blow-up).
- Internals: a
nouvelle_fkfactory joinsnouvelle_table/nouvelle_colonne; newtests/test_parser.py; dead code removed.
v0.22.1 — Inline primary keys, revamped README (2026-08-29)
- The PostgreSQL parser now recognises a column-level primary key
(
id serial PRIMARY KEY), not only a separatePRIMARY KEY (...)line or anALTER TABLE. The column gets its 🔑 and the constraint no longer leaks into the displayed type. - README rebuilt around an animated demo, a live-rendered Mermaid diagram and a diff screenshot.
v0.22.0 — Mermaid export (2026-08-29)
--to-mermaidrenders the model as a MermaiderDiagram. Pasted into a Markdown file, GitHub and GitLab render it natively — a static diagram in the README, no hosting needed (the interactive page stays the way to explore a big model). See docs/diagrams.md for the four examples.
v0.21.0 — Diff polish, rename detection, column search (2026-08-29)
- The diff detail panel now shows a retyped column as
old → new(the old type struck through). - Small single-schema models lay out as a roughly square block instead of a tall vertical band.
- Rename detection: a table dropped and one added with the same set of column
names is shown as a rename ("renamed from X", amber) rather than a
remove+add pair, and a foreign key untouched apart from the rename stays
unchanged. The JSON summary carries
renamed_from. - Search now matches column names too (
table.columnor a bare column name): it isolates the table and highlights the row.
v0.20.2 — JSON diff summary (2026-08-29)
--summary FILE(with--diff) writes a machine-readable JSON summary of the changes: per-category counts (tables/columns/FKs added, removed, changed) and the change list, with the previous type kept for retyped columns ("was": "numeric(10,2)"). Lets a caller show change badges or a version timeline without parsing the HTML.
v0.20.1 — Diff legend counts and "touched only" filter (2026-08-29)
- The diff legend now shows how many tables were added, changed and removed, and a "N touched" button hides the unchanged tables to frame just the ones that moved. "Overview" / Escape brings everything back.
v0.20.0 — Schema diff (2026-08-29)
--diff BASELINEcompares the model against an older version (any supported format on either side) and colors the diagram: tables, columns and foreign keys that were added (green), removed (red, struck through, kept on the diagram), or changed (amber). A legend shows the key. Useful to review a migration visually before applying it.- Internals: the seven parsers now share a single
charger()dispatch and thenouvelle_table/nouvelle_colonnefactories, so every format flows through the same code — which is what makes the diff work across all of them.
v0.19.3 — Harden the untrusted-upload surface (2026-08-29)
- Model XML (
.mwb,.dbm) is refused if it declares a DTD or entities, the vector for entity-expansion ("billion laughs") and XXE attacks the stdlib XML parser does not block on its own. - The
.mwbarchive is read through a size cap, so a tiny file cannot decompress into gigabytes (zip bomb). - Every external converter (
pgmodeler-cli,dbml2sql,prisma,pg_dump/mysqldump) runs under a timeout and is killed if it hangs. tests/test_securite.pycovers all four (generated on the fly, like the ReDoS bombs). This matters for a service that renders files it did not write.
v0.19.2 — Fuller Mermaid erDiagram parsing (2026-08-29)
- A crow's-foot cardinality (
o{,}o) is no longer mistaken for an entity block, which previously invented a phantom one-letter table. - Attribute comments (
int id PK "SERIAL") become column comments, shown in the detail panel;%%comment lines and adirectiondirective inside an entity block are ignored instead of read as columns; comma-separated attribute keys (PK, FK) are accepted. - Validated on 113 real erDiagram files (raw
.mmdand inside Markdown fences): 918 tables, 1002 FKs, zero bogus columns.
v0.19.1 — Links follow tables during "rearrange" (2026-08-29)
- "Rearrange" now redraws the FK links on every frame while the tables glide to their new positions, instead of leaving them behind and snapping them into place once the CSS transition ends.
v0.19.0 — Read a live database via --db (2026-08-28)
--db postgresql://…/--db mysql://…: dump a running database's schema (pg_dump -sfor PostgreSQL,mysqldump --no-datafor MySQL/MariaDB) and render it, no intermediate file needed. The positional model argument becomes optional; the page title defaults to the database name.- MySQL passwords go through the
MYSQL_PWDenvironment variable, never on the process command line. - FK constraint names are now recovered on the MySQL/sqlglot path (they hang
off the wrapping
CONSTRAINTnode), so--fk-auditworks on MySQL and MariaDB models too. - Command-line only. This feature must not be exposed on a public service: it would let a caller make the process connect to any host it can reach (SSRF). The hosted site keeps taking uploaded files only.
v0.18.0 — Drizzle ORM schema.ts input (2026-08-28)
- Read Drizzle ORM
schema.tsnatively: eachpgTable/mysqlTable/sqliteTablebecomes a table, itstype("col")fields columns (with.primaryKey()/.notNull()), and.references(() => t.col)the foreign keys; commented-out definitions are ignored
v0.17.0 — Mermaid erDiagram input (2026-08-28)
- Read Mermaid
erDiagramnatively, raw.mmd/.mermaidor inside a```mermaidfence in a.md: entities become tables, attributes columns (PK marker → key), each relationship an FK from the crow's-foot ("many") side to the "one" side
v0.16.0 — Rails schema.rb input (2026-08-28)
- Read Rails
db/schema.rbnatively (thecreate_table/add_foreign_keyDSL is regular): the implicitidprimary key, column types, and foreign keys (default column resolved by singularizing the target table)
v0.15.0 — MySQL Workbench .mwb input (2026-08-28)
- Read MySQL Workbench
.mwbmodels natively — the file is a zip whosedocument.mwb.xml(GRT object tree) is parsed with the standard library, no external tool: schemas, tables, column types, primary and foreign keys
v0.14.0 — Prisma schema input (2026-08-28)
- Read Prisma
schema.prismamodels, converted to SQL byprisma migrate diff; the schema's provider (postgres/mysql/sqlite/sqlserver) is detected automatically, MongoDB schemas are reported as unsupported - The PK/FK parsers now accept double-quoted constraint names
(
CONSTRAINT "x_pkey" PRIMARY KEY ...), as emitted by Prisma and modern tools
v0.13.0 — DBML input (2026-08-28)
- Read dbdiagram.io
.dbmlmodels (converted to SQL by@dbml/cli), the same upstream-converter pattern as.dbm - The FK parser now also reads unnamed constraints (
ADD FOREIGN KEY ...withoutCONSTRAINT name), which dbml2sql and some dumps emit
v0.12.0 — Attribution badge, safer link URLs (2026-08-28)
--credit TEXT/--credit-url URL: a slanted rubber-stamp attribution badge (mcdview logo + text) in the bottom-right corner, off by default; text escaped, optional link--home-urland--credit-urlnow reject dangerous URL schemes (javascript:,data:…), keeping only http(s)/mailto/relative links
v0.11.0 — SQL Server routing and ALTER ADD COLUMN (2026-08-28)
- SQL Server DDL (
[bracket]identifiers) is routed to the sqlglot tsql parser instead of being mangled by the PostgreSQL parser ALTER TABLE ... ADD [COLUMN] name typecolumns are now read, not just the ones inside theCREATE TABLEbody- Both found by running the content-invariant test over a larger, more dialect-diverse harvested corpus
v0.10.1 — Case-insensitive key matching (2026-08-28)
- PK/FK column names are matched to columns case-insensitively (unquoted SQL
identifiers are case-insensitive), so a
PLAYERIDprimary key on aplayerIDcolumn shows its 🔑 instead of being dropped as a phantom — found by the content-invariant test on a wider harvested corpus
v0.10.0 — Header logo link and custom logo (2026-08-28)
--home-url URL: the header logo becomes a link (e.g. back to the hosting site); URL escaped, nothing changes when the option is absent--logo FILE: replace the header logo with your own image (svg/png/jpg…), embedded as an<img>data URI so a third-party SVG cannot run scripts
v0.9.5 — Parser fixes from content-invariant testing (2026-08-28)
- Strip quoting from column names in PK/FK lists, so a
`id`or"timestamp"primary key no longer becomes a phantom (unmatched) key - Read quoted table/schema names (
CREATE TABLE "accounts"), so double-quoted DDL (e.g. Drizzle output) is parsed instead of dropped entirely - Route obviously non-PostgreSQL files (backticks) to sqlglot rather than letting the regex parser mangle them
- New
tests/test_invariants.py: checks the parsed model is internally consistent (no empty types, no phantom PK columns, FK endpoints exist)
v0.9.4 — Auto-dialect tries several parsers (2026-08-28)
- When PostgreSQL yields no table,
--dialect autonow tries several sqlglot dialects and keeps the one parsing the most tables, instead of guessing a single one — recovers files that were mis-detected (a 28-table model was read as the wrong dialect and dropped entirely)
v0.9.3 — Square overview for huge schemas (2026-08-28)
- The automatic layout now sizes each schema's column height for a roughly square zone, so a large single-schema model no longer stretches into an unreadable horizontal band (a 1066-table model went from a 41:1 strip to 1.4:1); small models are unchanged
v0.9.2 — Dialect polish (2026-08-28)
- The detected dialect is shown in the toolbar counter for non-PostgreSQL
models (e.g.
12 tables · 21 FK · mysql) - sqlglot column types are lowercased to match the PostgreSQL parser
(
INT(11)→int(11)), keeping string literals intact
v0.9.1 — Isolated view no longer overlaps (2026-08-28)
- When isolating a table, the star of related tables now sizes its radius to the tables involved and runs a de-overlap pass (centre kept fixed), so a large neighbour (e.g. a 40-column table) no longer covers the isolated one
v0.9.0 — Multi-dialect input via sqlglot (2026-08-28)
- Read MySQL/MariaDB, SQLite and ~15 other dialects through the optional
sqlglotbackend (PostgreSQL stays dependency-free);--dialectflag,autosniffs and falls back. On the harvested corpus, files that produced no page dropped from 257 to 18 - Dialect fixtures and test (
tests/test_dialectes.py), sqlglot wired into CI and the pre-commit hook
v0.8.5 — Hosted at mcdview.dev (2026-08-28)
- Link to the hosted service at mcdview.dev: upload a
.sqlor.dbmand get a shareable link, no install needed - README badges (hosted, demo, CI, license), repository homepage and topics for discoverability
v0.8.4 — Rearrange no longer overlaps big tables (2026-08-28)
- The rearrange layout now sizes each edge to the two tables it links (a constant target was pulling wide tables into each other), reins in weakly linked tables with a gravity term and a bounded repulsion range, and ends with a de-overlap pass — a 69-table model went from 60 overlapping pairs to zero, in a compact frame
v0.8.3 — Own the pgmodeler-cli image, reliable .dbm CI (2026-08-28)
docker/pgmodeler-cli/+image.ymlbuild and publishghcr.io/gheop/pgmodeler-cli(Fedora 44 + pgModeler 1.2.2, plus a-nodevariant forcontainer:jobs); the tag is the pgModeler version baked in- The CI
.dbmjob now runs inside that pinned image (fixed version → stable counts) and is blocking instead of best-effort
v0.8.2 — Tolerate pgmodeler-cli fix-model segfault (2026-08-28)
--fix-modelon pgmodeler-cli 1.2.2 writes the repaired.dbmin full, then segfaults while freeing the model (memory-layout dependent, systematic in containers). mcdview now judges the repair by the output file, not the exit code, so old.dbmmodels convert inside a container
v0.8.1 — CI test pipeline (2026-08-28)
- CI now runs on every push and pull request: Python error linting
(
ruff --select F,E9,py_compile), the pinned regression, the security suite, the strict corpus campaign, HTML structure validation and a headless-Chrome DOM check on the generated example pages; deploy to Pages only runs onmainafter the tests pass tests/valider_html.pyvalidates a page's structure and data island- A best-effort
.dbmjob installs pgmodeler-cli on the runner (never blocks a PR)
v0.8.0 — Rearrange button (2026-08-28)
- "Rearrange" button: a dependency-free force-directed relayout (Fruchterman-Reingold) that spreads tables to reduce link crossings — on a 69-table model with its audit FKs hidden, crossings dropped from 662 to 217. Disabled above 400 tables (the O(n²) pass would freeze the tab)
v0.7.0 — Hover, permalinks, hardening (2026-08-28)
- Hover a table to light up its links;
#schema.tablepermalinks that reopen on the right table; DEFAULT values in the detail panel; table comments as tooltips; a table/FK counter in the toolbar - Security: all injected model data is HTML-escaped and the JSON island
escapes
<, closing an XSS vector; the CREATE TABLE body is now bounded by string search instead of a lazy regex, killing a ReDoS (a 830 KiB malformed file went from 13 s to 0.3 s) - Security test suite and a strict corpus campaign wired into the pre-commit hook
v0.6.1 — .dbm repair fallback (2026-08-28)
- When pgmodeler-cli refuses a
.dbm(saved by an older pgModeler), mcdview now retries through--fix-modelbefore giving up — on the harvested corpus this takes the refusal rate from 136/296 down to 2/296 - Campaign results published in the README ("Tested at scale")
v0.6.0 — Schema legend, large-scale campaign (2026-08-28)
- Schema legend: one colored chip per schema (name + table count) in the bottom-left corner, click to frame that schema's zone; hidden when the model has a single schema
- A clear hint when the input is MySQL or SQLite DDL instead of PostgreSQL
- Performance: pre-sorted BFS starts (layout of a 5000-table model drops from 894 ms to 56 ms), precompiled column regexes, tables built in one DocumentFragment and links redrawn in a single DOM write
- Large-scale harness (
tests/moissonner.py,tests/grand_banc.py): hundreds of real-world schemas harvested from GitHub plus synthetic models up to 5000 tables, per-phase timings and DOM validation
v0.5.0 — Draggable tables, test bench (2026-08-28)
- Tables can be dragged around the diagram, links redraw live; a table moved in the overview keeps its new home position
- Regression/benchmark runner (
tests/tester.py) over the examples, the pgModeler sample models and an optional local corpus of big real-world schemas (GitLab: 1066 tables parsed in ~0.7 s), plus a pre-commit hook
v0.4.0 — pgModeler .dbm input, CI-built pages (2026-08-28)
- A
.dbmpgModeler model can be passed directly as input: the SQL is produced bypgmodeler-cliand the table positions drawn in the model are reused - The example pages are rebuilt by GitHub Actions on every push instead of being committed
- Code comments, docstrings and CLI output translated to English
v0.3.0 — Wider DDL support, real-world examples (2026-08-28)
- The parser now accepts unqualified tables (defaulting to the
publicschema), an opening parenthesis on its own line, primary keys declared viaALTER TABLE(pg_dump -sstyle), composite foreign keys, FK targets without a column list, and partitioned tables (partitions are folded into their parent) - 3 real-world example models with browsable pages: Pagila, Northwind, Chinook
v0.2.0 — English UI (2026-08-28)
--lang {fr,en}option: language of the generated page's interface (search box, help text, detail panel labels)- The live demo now uses the English UI
v0.1.1 — Public release (2026-08-28)
- Fictional library demo (
exemples/mediatheque.sql) with a live version on GitHub Pages - README in English, screenshot
- Published on GitHub
v0.1.0 — First standalone version (2026-08-27)
- Automatic table layout (one zone per schema, balanced columns, related
tables pulled together) — the pgModeler
.dbmbecomes optional --titre,--fk-audit,--dbm,-ooptions- SVG logo, "audit FK" checkbox hidden when no FK matches
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcdview-0.24.1.tar.gz.
File metadata
- Download URL: mcdview-0.24.1.tar.gz
- Upload date:
- Size: 66.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62ee8418e79869d577d9bd766c388ef15b55adb11e268f853fcb62b44d27ce2d
|
|
| MD5 |
ca32143bb7102920e9dc95ef54914c25
|
|
| BLAKE2b-256 |
94d5f92f097ed71d5f4ed19a3c590d45fc46133f6500a98ddc8c2598db611f94
|
Provenance
The following attestation bundles were made for mcdview-0.24.1.tar.gz:
Publisher:
release.yml on Gheop/mcdview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcdview-0.24.1.tar.gz -
Subject digest:
62ee8418e79869d577d9bd766c388ef15b55adb11e268f853fcb62b44d27ce2d - Sigstore transparency entry: 2652647627
- Sigstore integration time:
-
Permalink:
Gheop/mcdview@0d0bd231f0c8b641794181cc01ffbe33c09e7d62 -
Branch / Tag:
refs/tags/v0.24.1 - Owner: https://github.com/Gheop
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0d0bd231f0c8b641794181cc01ffbe33c09e7d62 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcdview-0.24.1-py3-none-any.whl.
File metadata
- Download URL: mcdview-0.24.1-py3-none-any.whl
- Upload date:
- Size: 55.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8714cf0cb7659462f2a0695bd7ca5c2b72201606ac533ddc4b2f3f4c678006c2
|
|
| MD5 |
58470a46476fe1472d3d1fef574590b4
|
|
| BLAKE2b-256 |
04d39f0b5e9c504752a8a4db939c38788095308b47bc06055196705de0cf08f9
|
Provenance
The following attestation bundles were made for mcdview-0.24.1-py3-none-any.whl:
Publisher:
release.yml on Gheop/mcdview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcdview-0.24.1-py3-none-any.whl -
Subject digest:
8714cf0cb7659462f2a0695bd7ca5c2b72201606ac533ddc4b2f3f4c678006c2 - Sigstore transparency entry: 2652647691
- Sigstore integration time:
-
Permalink:
Gheop/mcdview@0d0bd231f0c8b641794181cc01ffbe33c09e7d62 -
Branch / Tag:
refs/tags/v0.24.1 - Owner: https://github.com/Gheop
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0d0bd231f0c8b641794181cc01ffbe33c09e7d62 -
Trigger Event:
push
-
Statement type: