How DBX's ER Diagram Visualizes Table Relationships: Chen-Style SVG Generation
DBX renders table relationships by scanning foreign key definitions to create DiagramRelationship records, positioning entities as SVG rectangles, and drawing Chen-style diamond connectors with cardinality markers (1/N) to represent referential integrity between tables.
The open-source DBX database tool (t8y2/dbx) automatically generates Entity-Relationship diagrams using Chen notation conventions. This article examines the TypeScript implementation that transforms database schema metadata into interactive SVG visualizations, detailing the three-stage pipeline that converts foreign keys into visual relationships.
Extracting Foreign Key Relationships
The visualization process begins in src/apps/desktop/src/lib/diagram/erDiagram.ts with the buildDiagramRelationships function. This utility scans the table list, filters for foreign keys referencing visible tables, and constructs standardized relationship objects.
The function uses flatMap to iterate through tables and their foreign key arrays, creating a DiagramRelationship for each valid reference:
// src/apps/desktop/src/lib/diagram/erDiagram.ts
const foreignKeyRelationships = tables.flatMap(t =>
t.foreignKeys
.filter(fk => visibleTableNames.has(fk.ref_table))
.map(fk => ({
id: relationshipId(t.name, fk),
name: fk.name,
kind: "foreign-key",
sourceTable: t.name,
sourceColumn: fk.column,
targetTable: fk.ref_table,
targetColumn: fk.ref_column,
sourceCardinality: "N",
targetCardinality: "1",
}))
);
This array combines with user-defined custom relationships before proceeding to the layout stage. Each relationship explicitly defines source cardinality as "N" and target cardinality as "1", following standard one-to-many relationship semantics.
Constructing Chen-Style Diagram Nodes
The buildEngineeringDiagram function in src/apps/desktop/src/lib/diagram/engineeringDiagram.ts transforms abstract relationships into concrete SVG node objects. The implementation creates three distinct node types to represent the Chen notation:
- EngineeringEntityNode: Centered rectangles (
<rect>) representing database tables - EngineeringAttributeNode: Small rectangles positioned around entities for columns (primary keys, foreign keys, etc.)
- EngineeringRelationshipNode: Diamond shapes (
<polygon>) placed midway between connected entities
The relationship node calculation positions the diamond at the midpoint between source and target entities:
// src/apps/desktop/src/lib/diagram/engineeringDiagram.ts
const relationshipNodes = relationships.map(rel => ({
id: rel.id,
label: relationshipLabel(rel),
sourceTable: rel.sourceTable,
targetTable: rel.targetTable,
sourceCardinality: rel.sourceCardinality,
targetCardinality: rel.targetCardinality,
x: (sourceCenter.x + targetCenter.x) / 2 - ENGINEERING_RELATIONSHIP_WIDTH / 2,
y: (sourceCenter.y + targetCenter.y) / 2 - ENGINEERING_RELATIONSHIP_HEIGHT / 2,
width: ENGINEERING_RELATIONSHIP_WIDTH,
height: ENGINEERING_RELATIONSHIP_HEIGHT,
}));
The diamond configuration includes the relationship name (or source column label) and maintains references to both cardinalities for rendering the "1" and "N" markers.
Rendering SVG Output
The final stage occurs in apps/desktop/src/lib/export/diagramSvgExport.ts where buildEngineeringDiagramSvg converts the node objects into standard SVG markup. The generated diagram contains specific geometric primitives:
<rect>elements for table entities<ellipse>elements for "1" cardinality markers<polygon>elements for "N" cardinality markers<text>elements labeling tables, columns, and cardinalities
The unit test suite in packages/app-tests/diagramSvgExport.test.ts validates the presence of these Chen notation markers:
test("exports the engineering ER diagram with Chen-style shapes and cardinalities", () => {
const diagram = buildEngineeringDiagram(tables, relationships, positions);
const svg = buildEngineeringDiagramSvg(diagram);
assert.match(svg, /<ellipse /); // "1" marker
assert.match(svg, /<polygon /); // "N" marker
assert.match(svg, /<rect /); // table entity
});
Complete Implementation Workflow
The following workflow demonstrates the end-to-end process from schema extraction to SVG download:
import {
buildDiagramRelationships,
layoutDiagramTables,
} from "@/lib/diagram/erDiagram";
import { buildEngineeringDiagram, ENGINEERING_ENTITY_WIDTH } from "@/lib/diagram/engineeringDiagram";
import { buildEngineeringDiagramSvg } from "@/lib/export/diagramSvgExport";
// 1️⃣ Gather tables (fetched from DBX schema API)
const tables = await getTablesFromBackend(); // DiagramTable[]
// 2️⃣ Build relationships (FK + custom)
const relationships = buildDiagramRelationships(tables);
// 3️⃣ Compute a simple layout (optional, DBX remembers user‑dragged positions)
const positions = layoutDiagramTables(tables.map(t => ({ name: t.name, columns: t.columns })));
// 4️⃣ Build the full diagram model
const diagram = buildEngineeringDiagram(tables, relationships, positions);
// 5️⃣ Export SVG – ready for download, copy‑paste or embedding in docs
const svg = buildEngineeringDiagramSvg(diagram);
downloadFile(svg, "my‑er‑diagram.svg");
Key Source Files
| File | Purpose |
|---|---|
apps/desktop/src/lib/diagram/erDiagram.ts |
Detects foreign‑key and custom links; creates DiagramRelationship objects. |
apps/desktop/src/lib/diagram/engineeringDiagram.ts |
Converts tables & relationships into Chen‑style SVG node objects (entities, attributes, diamonds). |
apps/desktop/src/lib/export/diagramSvgExport.ts |
Renders the diagram model as an SVG string and handles safe file naming. |
packages/app-tests/diagramSvgExport.test.ts |
Test suite confirming the presence of <ellipse>, <polygon>, and <rect> in the exported SVG. |
Summary
- Foreign key detection occurs in
buildDiagramRelationships, which filters visible tables and creates standardized relationship records with N:1 cardinality. - Chen notation rendering uses diamond-shaped
EngineeringRelationshipNodeobjects positioned between entity rectangles, with ellipse and polygon markers indicating cardinality. - SVG generation produces standards-compliant markup using
<rect>,<ellipse>, and<polygon>elements, validated by the test suite to ensure correct shape representation. - Implementation requires three main phases: relationship extraction, node construction with midpoint calculations, and SVG string conversion.
Frequently Asked Questions
What notation style does DBX use for ER diagrams?
DBX implements Chen notation for its engineering diagrams. This style represents entities as rectangles, relationships as diamonds, and uses explicit cardinality markers (1 and N) to indicate relationship multiplicity, as opposed to Crow's Foot or UML notation styles.
How does DBX determine cardinality between tables?
The system automatically assigns "N" cardinality to the source table and "1" cardinality to the target table (the referenced table) for all foreign key relationships. This convention follows standard relational database design where foreign keys create many-to-one relationships between tables.
Can DBX visualize relationships beyond foreign keys?
Yes. The buildDiagramRelationships function combines foreign key relationships with user-defined custom relationships. These custom links allow visualization of logical connections that may not exist as formal foreign key constraints in the database schema.
What SVG elements represent relationships in the exported diagram?
According to the source code in diagramSvgExport.ts, relationships use <polygon> elements for the diamond shape and <ellipse> elements for the "1" cardinality markers. The connecting entities use <rect> elements, while all labels use <text> elements.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →