How DrawDB Validates Relationships and Handles Cascade Deletes
DrawDB validates relationships using JSON Schema validators in src/utils/validateSchema.js and handles cascade deletes by parsing the cascade keyword into Constraint.CASCADE objects that SQL exporters convert into ON DELETE CASCADE clauses.
DrawDB is an open-source database diagramming tool that stores diagrams as JSON objects following the DBML (Database Markup Language) specification. When users define relationships between tables, the application enforces structural integrity through a multi-stage validation pipeline before generating SQL. Understanding how DrawDB validates relationships and handles cascade deletes reveals the safeguards that prevent malformed schemas from reaching production databases.
JSON Schema Validation for Diagram Integrity
DrawDB employs two distinct validation layers in src/utils/validateSchema.js to verify diagram correctness. Both functions instantiate new Validator() from the jsonschema package to check the diagram object against predefined schemas.
Generic DBML Schema Validation
The jsonDiagramIsValid(obj) function validates the diagram against the standard DBML JSON schema (jsonSchema). This ensures the overall structure conforms to the DBML specification before DrawDB-specific processing begins.
DrawDB-Specific Constraints
The ddbDiagramIsValid(obj) function applies the stricter ddbSchema, which adds extra constraints required by the DrawDB UI. This validation runs before saving or exporting to catch UI-specific errors that generic DBML validation might miss.
// Validate the whole diagram before saving
import { ddbDiagramIsValid } from '@/utils/validateSchema';
if (!ddbDiagramIsValid(diagram)) {
alert('Diagram contains errors – cannot save.');
}
Parsing Relationships and Cascade Constraints
When the DBML parser processes relationship definitions in src/utils/dbml/parse.js, it transforms syntax into internal constraint objects. If a relationship includes the optional cascade keyword, the parser sets the constraint type to Constraint.CASCADE.
For example, the DBML syntax TableA.id <|-- TableB.parentId [cascade] triggers the following logic:
// DBML parser extracts a cascade relationship
function parseRelationship(rel) {
const constraint = {
type: rel.cascade ? Constraint.CASCADE : Constraint.FOREIGN_KEY,
// … other fields (source, target, columns)
};
return constraint;
}
This constraint object travels through the application state until SQL generation, carrying the cascade delete semantics specified by the user.
SQL Generation with ON DELETE CASCADE
During export, SQL generators in src/utils/exportSQL/postgres.js and src/utils/exportSQL/sqlite.js iterate over table constraints. When encountering Constraint.CASCADE, they append the ON DELETE CASCADE clause to the foreign key definition.
The PostgreSQL exporter implements this logic to ensure referential integrity actions are preserved in the generated DDL:
// PostgreSQL exporter adds ON DELETE CASCADE
function renderConstraint(constraint) {
if (constraint.type === Constraint.CASCADE) {
return `FOREIGN KEY (${constraint.column}) REFERENCES ${constraint.refTable}(${constraint.refColumn}) ON DELETE CASCADE`;
}
// regular foreign‑key handling …
}
SQLite follows an identical pattern in src/utils/exportSQL/sqlite.js, ensuring consistent cascade behavior across database engines.
Summary
- Validation Entry Points:
jsonDiagramIsValid()andddbDiagramIsValid()insrc/utils/validateSchema.jsuse the jsonschema library to validate diagram structure before persistence. - Cascade Detection: The DBML parser in
src/utils/dbml/parse.jsconverts the[cascade]keyword intoConstraint.CASCADEtype constraints. - SQL Output: Exporters in
src/utils/exportSQL/postgres.jsandsqlite.jstranslateConstraint.CASCADEinto standardON DELETE CASCADESQL clauses. - Integrity Guarantee: Because validation runs before parsing and export, DrawDB ensures only well-formed relationships reach the generated SQL, preventing runtime database errors.
Frequently Asked Questions
How does DrawDB prevent invalid relationships from being exported?
DrawDB runs JSON Schema validation via ddbDiagramIsValid() before any export operation. This function checks the diagram against the ddbSchema, which enforces DrawDB-specific constraints. If validation fails, the UI blocks the export action, ensuring only structurally sound relationships proceed to SQL generation.
What database engines support DrawDB's cascade delete feature?
The SQL exporters for PostgreSQL (src/utils/exportSQL/postgres.js) and SQLite (src/utils/exportSQL/sqlite.js) both implement ON DELETE CASCADE generation. The constraint system is engine-agnostic at the parsing level, with each SQL dialect generator handling the specific syntax required for cascade operations.
Can I use cascade updates in addition to cascade deletes?
The current implementation focuses on ON DELETE CASCADE through the Constraint.CASCADE type. The DBML parser recognizes the cascade keyword primarily for delete operations. Update cascades would require extending the constraint types in src/utils/dbml/parse.js and updating the SQL generators to handle ON UPDATE CASCADE clauses.
Where does DrawDB store the cascade constraint information?
Cascade constraints exist as part of the diagram's JSON structure after parsing. The src/utils/dbml/parse.js parser stores them as constraint objects with type: Constraint.CASCADE, which persist in the application state until the SQL exporter serializes them into FOREIGN KEY definitions with ON DELETE CASCADE modifiers.
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 →