Skip to main content

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)

Source distribution for titto 0.4.0
File Size Uploaded
titto-0.4.0.tar.gz 11.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for titto 0.4.0
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2

3 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page