use sea_orm::DbErr;
const SERIALIZATION_FAILURE_SQLSTATE: &str = "40001";
const PG_SERIALIZATION_MSG: &str = "could not serialize access";
#[must_use]
pub fn is_deadlock(err: &DbErr) -> bool {
match err {
DbErr::Exec(runtime_err) | DbErr::Query(runtime_err) => {
let msg = runtime_err.to_string();
msg.contains(SERIALIZATION_FAILURE_SQLSTATE)
}
_ => false,
}
}
#[must_use]
pub fn is_serialization_failure(err: &DbErr) -> bool {
match err {
DbErr::Exec(runtime_err) | DbErr::Query(runtime_err) => {
let msg = runtime_err.to_string();
msg.contains(SERIALIZATION_FAILURE_SQLSTATE) || msg.contains(PG_SERIALIZATION_MSG)
}
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use sea_orm::RuntimeErr;
fn exec_err(msg: &str) -> DbErr {
DbErr::Exec(RuntimeErr::Internal(msg.to_owned()))
}
#[test]
fn deadlock_sqlstate_40001_detected() {
assert!(is_deadlock(&exec_err(
"error returned from database: 40001: Deadlock found"
)));
}
#[test]
fn deadlock_pg_serialization_failure_detected() {
assert!(is_deadlock(&exec_err(
"ERROR: 40001: could not serialize access"
)));
}
#[test]
fn non_deadlock_errors_return_false() {
assert!(!is_deadlock(&DbErr::Custom("something".into())));
assert!(!is_deadlock(&DbErr::RecordNotFound("x".into())));
assert!(!is_deadlock(&exec_err("duplicate key value")));
}
#[test]
fn serialization_failure_sqlstate_detected() {
assert!(is_serialization_failure(&exec_err(
"error returned from database: 40001"
)));
}
#[test]
fn serialization_failure_pg_message_detected() {
assert!(is_serialization_failure(&exec_err(
"ERROR: could not serialize access due to concurrent update"
)));
}
#[test]
fn non_serialization_errors_return_false() {
assert!(!is_serialization_failure(&DbErr::Custom(
"something".into()
)));
assert!(!is_serialization_failure(&exec_err("unique constraint")));
}
}