use ruststream_sqlx_dialect::StatementError;
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum SqlxBrokerError {
#[error("the inbox broker could not take a connection from the pool: {source}")]
Connect {
#[source]
source: sqlx::Error,
},
#[error(
"no built-in dialect serves the `{backend}` backend of this `AnyPool`: enable its feature, \
or pass a dialect with `SqlxBroker::with_dialect`"
)]
Backend {
backend: String,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}): `{statement}` failed: {source}"
)]
Sqlx {
subscription: String,
table: String,
row: &'static str,
statement: &'static str,
#[source]
source: Box<sqlx::Error>,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}): the database refused \
`{statement}`: {source}"
)]
Schema {
subscription: String,
table: String,
row: &'static str,
statement: &'static str,
#[source]
source: Box<sqlx::Error>,
},
#[error("subscription `{subscription}` on table `{table}` ({row}): {source}")]
Dialect {
subscription: String,
table: String,
row: &'static str,
#[source]
source: StatementError,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}): the server reports \
`{server}`, and this form needs {required} or later"
)]
ServerTooOld {
subscription: String,
table: String,
row: &'static str,
server: String,
required: &'static str,
},
#[error("subscription `{subscription}` on table `{table}` ({row}): {reason}")]
Declaration {
subscription: String,
table: String,
row: &'static str,
reason: String,
},
#[error(
"subscription `{subscription}`: the pool's {pool} connections and the dedicated threads' \
{threads} pass the connection limit of {limit}; lower the threads' connections or raise \
the limit"
)]
ConnectionLimit {
subscription: String,
limit: u32,
pool: u64,
threads: u64,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}) is open already on this \
connection: one queue has one subscription per process; scale it with `workers(n)`"
)]
AlreadySubscribed {
subscription: String,
table: String,
row: &'static str,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}): an earlier settlement of this \
batch failed, so the batch rolls back and its rows return to the queue"
)]
BatchRolledBack {
subscription: String,
table: String,
row: &'static str,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}): the lease on row {id} ran out \
and another claim took it; this settlement did not take effect"
)]
LeaseLost {
subscription: String,
table: String,
row: &'static str,
id: String,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}): the handler still holds the \
transaction of row {id}, so its settlement took no effect; the transaction rolls back \
when the handler's `Tx` drops"
)]
TransactionHeld {
subscription: String,
table: String,
row: &'static str,
id: String,
},
#[error(
"subscription `{subscription}` on table `{table}` ({row}): the broker could not listen \
for the table's notifications: {source}"
)]
Listen {
subscription: String,
table: String,
row: &'static str,
#[source]
source: Box<sqlx::Error>,
},
#[error("publishing to `{name}` into table `{table}` ({row}) failed: {source}")]
Publish {
name: String,
table: String,
row: &'static str,
#[source]
source: Box<sqlx::Error>,
},
#[error(
"publishing to `{name}` into table `{table}` ({row}) was refused: the table cannot hold \
header `{header}` byte for byte"
)]
Header {
name: String,
table: String,
row: &'static str,
header: String,
},
#[error("no route leads `{name}` to a table: add `.route::<Row>(\"{name}\")` to the broker")]
NoRoute {
name: String,
},
#[error("the inbox broker is shut down")]
Closed,
}
#[cfg(test)]
mod tests {
use super::SqlxBrokerError;
#[test]
fn every_message_names_where_to_look() {
let error = SqlxBrokerError::AlreadySubscribed {
subscription: "emails".to_owned(),
table: "app.email_jobs".to_owned(),
row: "SendEmail",
};
assert_eq!(
error.to_string(),
"subscription `emails` on table `app.email_jobs` (SendEmail) is open already on this \
connection: one queue has one subscription per process; scale it with `workers(n)`"
);
assert_eq!(
SqlxBrokerError::Closed.to_string(),
"the inbox broker is shut down"
);
let backend = SqlxBrokerError::Backend {
backend: "MySQL".to_owned(),
};
assert_eq!(
backend.to_string(),
"no built-in dialect serves the `MySQL` backend of this `AnyPool`: enable its feature, \
or pass a dialect with `SqlxBroker::with_dialect`"
);
let lost = SqlxBrokerError::LeaseLost {
subscription: "emails".to_owned(),
table: "email_jobs".to_owned(),
row: "SendEmail",
id: "7".to_owned(),
};
assert_eq!(
lost.to_string(),
"subscription `emails` on table `email_jobs` (SendEmail): the lease on row 7 ran out \
and another claim took it; this settlement did not take effect"
);
let held = SqlxBrokerError::TransactionHeld {
subscription: "emails".to_owned(),
table: "email_jobs".to_owned(),
row: "SendEmail",
id: "7".to_owned(),
};
assert_eq!(
held.to_string(),
"subscription `emails` on table `email_jobs` (SendEmail): the handler still holds the \
transaction of row 7, so its settlement took no effect; the transaction rolls back \
when the handler's `Tx` drops"
);
let unheard = SqlxBrokerError::Listen {
subscription: "emails".to_owned(),
table: "email_jobs".to_owned(),
row: "SendEmail",
source: Box::new(sqlx::Error::PoolClosed),
};
assert_eq!(
unheard.to_string(),
"subscription `emails` on table `email_jobs` (SendEmail): the broker could not listen \
for the table's notifications: attempted to acquire a connection on a closed pool"
);
let old = SqlxBrokerError::ServerTooOld {
subscription: "emails".to_owned(),
table: "email_jobs".to_owned(),
row: "SendEmail",
server: "10.5.23-MariaDB".to_owned(),
required: "MariaDB 10.6",
};
assert_eq!(
old.to_string(),
"subscription `emails` on table `email_jobs` (SendEmail): the server reports \
`10.5.23-MariaDB`, and this form needs MariaDB 10.6 or later"
);
}
}