use std::fmt::Display;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SubscriptionErrorKind {
Transient,
Permanent,
Unknown,
}
impl Display for SubscriptionErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Transient => write!(f, "transient"),
Self::Permanent => write!(f, "permanent"),
Self::Unknown => write!(f, "unknown"),
}
}
}
pub fn classify_error(error: &dyn std::error::Error) -> SubscriptionErrorKind {
let error_str = error.to_string().to_lowercase();
if error_str.contains("lock") || error_str.contains("timeout") {
return SubscriptionErrorKind::Transient;
}
if error_str.contains("connection") || error_str.contains("reset") {
return SubscriptionErrorKind::Transient;
}
if error_str.contains("unavailable") || error_str.contains("busy") {
return SubscriptionErrorKind::Transient;
}
if error_str.contains("temporarily") || error_str.contains("temporary") {
return SubscriptionErrorKind::Transient;
}
if error_str.contains("table") && error_str.contains("not found")
|| error_str.contains("table") && error_str.contains("doesn't exist")
|| error_str.contains("table") && error_str.contains("does not exist")
{
return SubscriptionErrorKind::Permanent;
}
if error_str.contains("column") && error_str.contains("not found")
|| error_str.contains("column") && error_str.contains("doesn't exist")
|| error_str.contains("column") && error_str.contains("does not exist")
{
return SubscriptionErrorKind::Permanent;
}
if error_str.contains("syntax") || error_str.contains("parse") {
return SubscriptionErrorKind::Permanent;
}
if error_str.contains("permission") || error_str.contains("denied") {
return SubscriptionErrorKind::Permanent;
}
if error_str.contains("invalid") {
return SubscriptionErrorKind::Permanent;
}
SubscriptionErrorKind::Unknown
}
pub fn classify_error_str(error_msg: &str) -> SubscriptionErrorKind {
let error_str = error_msg.to_lowercase();
if error_str.contains("lock") || error_str.contains("timeout") {
return SubscriptionErrorKind::Transient;
}
if error_str.contains("connection") || error_str.contains("reset") {
return SubscriptionErrorKind::Transient;
}
if error_str.contains("unavailable") || error_str.contains("busy") {
return SubscriptionErrorKind::Transient;
}
if error_str.contains("temporarily") || error_str.contains("temporary") {
return SubscriptionErrorKind::Transient;
}
if (error_str.contains("table") && error_str.contains("not found"))
|| (error_str.contains("table") && error_str.contains("doesn't exist"))
|| (error_str.contains("table") && error_str.contains("does not exist"))
{
return SubscriptionErrorKind::Permanent;
}
if (error_str.contains("column") && error_str.contains("not found"))
|| (error_str.contains("column") && error_str.contains("doesn't exist"))
|| (error_str.contains("column") && error_str.contains("does not exist"))
{
return SubscriptionErrorKind::Permanent;
}
if error_str.contains("syntax") || error_str.contains("parse") {
return SubscriptionErrorKind::Permanent;
}
if error_str.contains("permission") || error_str.contains("denied") {
return SubscriptionErrorKind::Permanent;
}
if error_str.contains("invalid") {
return SubscriptionErrorKind::Permanent;
}
SubscriptionErrorKind::Unknown
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_classify_transient_timeout() {
let kind = classify_error_str("Query timeout");
assert_eq!(kind, SubscriptionErrorKind::Transient);
}
#[test]
fn test_classify_transient_lock() {
let kind = classify_error_str("Database lock timeout");
assert_eq!(kind, SubscriptionErrorKind::Transient);
}
#[test]
fn test_classify_transient_connection() {
let kind = classify_error_str("Connection reset by peer");
assert_eq!(kind, SubscriptionErrorKind::Transient);
}
#[test]
fn test_classify_permanent_table_not_found() {
let kind = classify_error_str("Table 'users' not found");
assert_eq!(kind, SubscriptionErrorKind::Permanent);
}
#[test]
fn test_classify_permanent_column_not_found() {
let kind = classify_error_str("Column 'name' doesn't exist");
assert_eq!(kind, SubscriptionErrorKind::Permanent);
}
#[test]
fn test_classify_permanent_syntax() {
let kind = classify_error_str("Syntax error in SELECT");
assert_eq!(kind, SubscriptionErrorKind::Permanent);
}
#[test]
fn test_classify_permanent_permission() {
let kind = classify_error_str("Permission denied");
assert_eq!(kind, SubscriptionErrorKind::Permanent);
}
#[test]
fn test_classify_unknown() {
let kind = classify_error_str("Some other error");
assert_eq!(kind, SubscriptionErrorKind::Unknown);
}
#[test]
fn test_error_kind_display() {
assert_eq!(format!("{}", SubscriptionErrorKind::Transient), "transient");
assert_eq!(format!("{}", SubscriptionErrorKind::Permanent), "permanent");
assert_eq!(format!("{}", SubscriptionErrorKind::Unknown), "unknown");
}
}