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() and ddbDiagramIsValid() in src/utils/validateSchema.js use the jsonschema library to validate diagram structure before persistence.
  • Cascade Detection: The DBML parser in src/utils/dbml/parse.js converts the [cascade] keyword into Constraint.CASCADE type constraints.
  • SQL Output: Exporters in src/utils/exportSQL/postgres.js and sqlite.js translate Constraint.CASCADE into standard ON DELETE CASCADE SQL 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →