Architecture¶
This page explains DBWarden internals for contributors and advanced debugging.
Layered architecture¶
CLI (Typer)
-> Commands layer
-> Engine layer (planning/parsing/version/checksum/model discovery)
-> Repository layer (migration + lock records)
-> Database layer (SQLAlchemy connection + SQL execution)
Responsibilities¶
- CLI: parse args, global flags (
--dev,--strict-translation,--help) - Commands: orchestrate workflows (
migrate,rollback,make-migrations,status,history,check,diff,generate-models,export-models,seed,lock-status,unlock,init,snapshot,settings,database,version) - Engine: parse files, resolve ordering, checksums, model discovery
- Repositories: read/write migration and lock metadata
- Database: execute SQL with backend-aware connections
Configuration resolution pipeline¶
When runtime config is requested:
- discover one config source (
dbwarden.pyor single callsite) - fallback to
DBWARDEN_CONFIG_MODULEwhen configured - import source and execute
database_config(...)calls - validate uniqueness/default/model-path rules
- resolve selected database and apply
--devswap when enabled
Ambiguous sources fail fast.
Migration execution lifecycle¶
For migrate:
- ensure migrations metadata table exists
- ensure lock table exists
- acquire lock
- build pending execution plan
- execute SQL statements
- record migration metadata/checksums
- release lock
Rollback lifecycle¶
Rollback uses the same lock discipline, selecting rollback SQL from applied files in reverse order.
Model-to-SQL generation lifecycle¶
make-migrations pipeline:
- discover model paths
- import model modules
- extract table/column metadata
- load latest schema snapshot (
.dbwarden/schemas/*.schema.json) if one exists - if snapshot exists: snapshot-diff path
- diff model tables against snapshot tables
- auto-detect table renames from dropped↔added table pairs (column overlap ≥ 0.6)
- apply user
--rename-tableflags and/or interactive prompts to confirm table renames - emit
ALTER TABLE ... RENAME TO(confirmed) orDROP TABLE+CREATE TABLE(not confirmed) - apply confirmed table renames to snapshot before column processing
- auto-detect column renames from dropped↔added pairs of the same type
- apply user
--renameflags and/or interactive prompts to confirm renames - detect column-level changes: type, nullability, default (same-name columns)
- emit
RENAME COLUMN(confirmed) orDROP+ADD(not confirmed) - emit
ALTER COLUMN TYPE/SET NOT NULL/DROP NOT NULL/SET DEFAULT/DROP DEFAULT - optionally use multi-step safe type change (
--safe-type-change) - order all operations by
StatementOrder(RENAME_TABLE first) and assemble upgrade/rollback - generate upgrade and rollback SQL from the ops
- if no snapshot: live-DB fallback path
- take a full schema snapshot from the live database via
extract_full_schema_snapshot() - run standard snapshot-diff pipeline against it (type, nullability, default, FK, index changes)
- only rename detection is unavailable without a cached snapshot
- take a full schema snapshot from the live database via
- deduplicate against existing migration statements
- write migration file
- write companion
.plan.jsonmetadata file (withresolved_fromon rename ops)
Snapshot write lifecycle (in migrate)¶
After applying versioned migrations, migrate calls _write_migration_snapshot():
- connect to database (respecting sandbox override)
- extract full schema: tables, columns, types, indexes, constraints, enums
- compute SHA-256 checksum
- write
<migration_id>.schema.jsonto.dbwarden/schemas/ - on failure: log warning (non-blocking)
Snapshots are not written during --dry-run, --sandbox, or for repeatable migrations.
Repeatable migration model¶
Supported classes:
- versioned (
NNNN_): run once in ordered sequence - runs always (
RA__): run each migrate execution - runs on change (
ROC__): run only when checksum changes
Integrity model¶
Checksums are recorded for migration content and used for:
- repeatable migration change detection
- migration consistency checks
- audit/debug confidence
Concurrency model¶
Migration-mutating commands are serialized by lock state stored in database tables.
Recovery commands:
dbwarden lock-statusdbwarden unlock
Dev translation path¶
With --dev and SQLite target:
- extract model types/defaults
- translate backend-specific constructs
- fallback behavior in non-strict mode
- fail-fast behavior with
--strict-translation
Translation happens during SQL generation, not by mutating existing migration files.
Error propagation strategy¶
- config/load validation errors fail early
- execution errors abort current run with context
- lock release is guarded in cleanup paths