The mabat CLI
A DBA does not need Rust to work on overrides. The application writes a manifest of its views — their queries,
aliases and accepted column types — and the mabat tool (crate mabat-cli) works from it
(MPA-OVR-8).
#[test]fn views_manifest_is_up_to_date() { let manifest = Mabat::<sqlx::Postgres>::builder().register::<TaskView>().manifest().unwrap(); assert!(!manifest.write("mabat/views.json").unwrap(), "mabat/views.json was out of date");}# check every query, generated and overridden, against a databasemabat check --manifest mabat/views.json --overrides mabat/overrides --database-url postgres://...
# or against a schema file in any scratch database: created in a transaction that is rolled back# (a temporary database on MySQL, an in-memory database on SQLite)mabat check --manifest mabat/views.json --overrides mabat/overrides --schema schema.sql
mabat explain --manifest mabat/views.json --overrides mabat/overrides # the SQL each query runsmabat scaffold --manifest mabat/views.json --view TaskView --format sql # every query's generated SQLTo tune a query, start from the SQL Mabat generates for it. explain lists the queries of a view by name;
scaffold --query writes the generated SQL of the ones you name into the view’s override file, ready to edit:
change the joins, add hints, use another index. Every query in the file replaces the generated one, so scaffold
only the queries you are tuning, and the others keep following the view as it changes.
mabat scaffold --manifest mabat/views.json --view TaskView --format sql \ --query children.notes --out mabat/overrides# wrote mabat/overrides/TaskView.sql; run it again with another --query to add that query to the fileAn existing file is added to, never overwritten: scaffolding a query the file already overrides is an error.
A snapshot of the database’s schema, committed next to the manifest, lets views be checked against the schema
without a database (MPA-SCH-1). mabat schema writes it, mabat schema --check tells CI when the database has moved
on (MPA-SCH-2), and mabat check --snapshot checks the views against it (MPA-SCH-4):
mabat schema --database-url postgres://... --out mabat/schema.json # tables, columns, keys, as JSONmabat schema --check mabat/schema.json --database-url postgres://... # exit status 1 if they differmabat check --manifest mabat/views.json --snapshot mabat/schema.json # no database neededAgainst a snapshot, check finds the tables and columns the views read that are missing (M0201, M0202), columns
of types the fields cannot be decoded from (M0203), nullable columns under fields that are not Option (M0204, a
warning), foreign keys and link tables holding another kind of key than the key they match (M0205), keys that are
not their table’s primary key (M0206, a warning), and #[view(generated)] keys the database does not generate
(M0207). Override files are checked for their names only: their SQL needs a database to prepare it.
error[M0202]: TaskView.$root: column `task.due` is not in the schema --> mabat/schema.json | did you mean `due_on`?In a build script, the same check makes cargo build fail when the views no longer match the schema (MPA-SCH-7). The
mabat-check crate needs no database driver:
[build-dependencies]mabat-check = "0.1"fn main() { mabat_check::build("mabat/views.json", "mabat/schema.json").overrides("mabat/overrides").run();}error: app@0.1.0: mabat error[M0202]: ProjectView.tasks: column `task.title` is not in the schema; did you mean `titel`? (mabat/schema.json)error: build script logged errorsThe build script checks the committed files: the manifest test keeps mabat/views.json current, and
mabat schema --check in CI keeps mabat/schema.json current. Warnings show as Cargo warnings. Before the
manifest exists, or with MABAT_SKIP_CHECK=1, the check is skipped with a warning.
crates/mabat-example-build is a complete example.
check prints the same report as the application’s startup check. It exits with 0 when there are no errors, 1
when there are, and 2 for any other problem, so it can gate a DBA’s CI.