Titto
Titto deletes tenant-scoped rows from a MySQL schema by reading table metadata, following foreign-key paths back to a tenant table, nulling optional references, and deleting rows in dependency order.
Warnings
This is a destructive database tool. Run it against production only after testing the exact command against a restored copy or staging database.
--commit permanently commits the deletes. Without --commit, Titto still runs
the UPDATE and DELETE statements inside a transaction, then rolls them back.
That dry run can still take locks, fire triggers, and affect non-transactional
tables.
Take a backup before any committed run. Prefer a database snapshot or logical dump that you have already tested restoring. Keep the backup until the tenant removal has been verified.
Usage
Show commands:
uv run titto --help
Dry-run a single-column tenant key and cache table metadata as JSON:
uv run titto delete "$DB_URL" tenant 42 --cache .tables.json
Commit the delete:
uv run titto delete "$DB_URL" tenant 42 --cache .tables.json --commit
Use a composite tenant key by passing each primary-key part as its own token:
uv run titto delete "$DB_URL" tenant 42 eu --cache .tables.json
Require selected tables to be empty for the tenant before deleting anything:
uv run titto delete "$DB_URL" tenant 42 --skip invoice --skip payment
Clean up unreferenced rows in tables that are not directly tenant-scoped:
uv run titto cleanup "$DB_URL" tenant --cache .tables.json
The automatic cleanup selection also skips tables with a UNIQUE constraint.
Clean up unreferenced rows in explicitly selected tables:
uv run titto cleanup-tables "$DB_URL" tag category --cache .tables.json
Find rows whose outgoing foreign keys resolve to different tenants:
uv run titto check-cross-tenant "$DB_URL" tenant --limit 100 --cache .tables.json
For each table, Titto finds outgoing foreign keys that point to tenant-scoped
tables, then compares the first candidate with each later candidate. Each
referenced table is resolved through its shortest foreign-key path to the tenant
table. The limit is applied per table. By default, results are human-readable
and progress logs are hidden. Use --json to print one JSON object per mismatch,
and --verbose to show progress logs on stderr.
DB_URL is a MySQL URL such as:
mysql://user:password@localhost:3306/app_schema
Avoid putting real passwords directly in shell history. Use an environment variable, secret manager, or another shell-safe mechanism appropriate for your environment.
Cache Notes
--cache stores parsed table metadata as JSON. The recommended local cache path
is .tables.json; it is ignored by Git.
The cache is tied to the host, port, schema name, and cache format version. Titto
rejects mismatched cache metadata and reparses the database schema. If the schema
changes on the same host and schema name, delete .tables.json so Titto can
refresh it.
Development
Run the test suite:
uv run python -m unittest
Metadata
Release files for titto 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| titto-0.4.0.tar.gz | 11.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| titto-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.1 kB
Release files / titto-0.4.0.tar.gz
| Download URL | titto-0.4.0.tar.gz |
|---|---|
| Size | 11.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
496b121437df4cd331a683161d8f357f4095dd6e9ad51f3adeabe09aea2bb02e
|
|
BLAKE2b-256 checksum How to use checksums |
2ade7e2e84519be13522805d4318b2b6e57ce0e9aba3cda1578b98710cf05dbf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.23.4","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / titto-0.4.0-py3-none-any.whl
| Download URL | titto-0.4.0-py3-none-any.whl |
|---|---|
| Size | 11.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb9a03ff62287f639e0369323709a3b9ac09857c101208bb3d2150bb26b6da9b
|
|
BLAKE2b-256 checksum How to use checksums |
87e7f37425afe9447840450be439f90cf700b866dc1cdfa716eefce6a3f74d1c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.23.4","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|