checked
#[inbox(checked, db = ..)] puts the statements a struct determines into sqlx's compile-time check against DATABASE_URL or the .sqlx offline data.
db names the built-in dialect the statements are built with: postgres, mysql or sqlite.
The derive builds them with the code the broker runs when a subscription opens, and wraps each in sqlx::query! inside a function nothing calls.
The service's build then checks each statement against its database: a column the struct names and the table lacks fails the build.
The subscription runs the statements it runs without checked, so a message costs the same.
checked needs three things of the service:
- its own sqlx under the name
sqlx, with themacrosfeature and the database's driver; DATABASE_URLat build time, or the.sqlxdata thatcargo sqlx preparewrites, committed beside the crate;SQLX_OFFLINE=truemakes a build read that data even whereDATABASE_URLis set, andcargo sqlx prepare --checkfails a CI run whose data is stale;- the feature of the dialect
dbnames, onruststream-sqlx.
Each statement meets sqlx's own rules: with both chrono and time on, sqlx.toml names the preferred crate for time columns (sqlx's compile-time macros).
The check covers every statement the struct determines: the claims, the guard of a FIFO group, the fetch after a claim of the service's own, the settlements, the dead letter of a group, the lease's extension and stamp, the advisory lock form's lock, unlock and take, and the generated insert.
The startup check still runs, and still holds the move into a dead-letter table, which the mount names.
In the headers layout checked goes on the headers struct, and the message reads its rows in a Fetch of its own, checked with sqlx::query!.
A struct checked cannot cover does not compile, and the error points at the attribute or the field: checked without db or the reverse, a db whose feature is off, a #[sqlx(flatten)] field, a clock that is a parameter of the struct, the row lock form on SQLite, and checked on a message assembled from a headers struct.
A dialect of the service's own keeps the startup check, because a procedural macro cannot run it.
Example
The email queue of a Postgres service, its statements checked against the offline data in .sqlx.
Its test runs on the Postgres stand that POSTGRES_TEST_URL names, and skips without it.
/// Every statement this struct determines goes through sqlx's compile-time check.
#[derive(Inbox, sqlx::FromRow)]
#[inbox(table = "email_jobs", checked, db = postgres)]
struct SendEmail {
#[field(id, generated)]
job_id: i64,
#[field(group)]
name: String,
#[field(attempt, generated)]
attempt: i16,
#[field(payload)]
payload: Vec<u8>,
}