#[derive(Debug)]
pub enum PgError {
Postgres(tokio_postgres::Error),
TypeConversion(String),
Tls(String),
ConstraintViolation {
constraint: String,
detail: String,
},
Timeout(String),
PoolExhausted(String),
Copy(String),
Notify(String),
Connection(String),
Replication(String),
Protocol(String),
}
impl std::fmt::Display for PgError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PgError::Postgres(e) => write!(f, "postgres error: {e}"),
PgError::TypeConversion(msg) => write!(f, "type conversion error: {msg}"),
PgError::Tls(msg) => write!(f, "TLS error: {msg}"),
PgError::ConstraintViolation { constraint, detail } => {
write!(f, "constraint violation on '{constraint}': {detail}")
}
PgError::Timeout(msg) => write!(f, "postgres timeout: {msg}"),
PgError::PoolExhausted(msg) => write!(f, "postgres pool exhausted: {msg}"),
PgError::Copy(msg) => write!(f, "postgres COPY error: {msg}"),
PgError::Notify(msg) => write!(f, "postgres NOTIFY error: {msg}"),
PgError::Connection(msg) => write!(f, "postgres connection error: {msg}"),
PgError::Replication(msg) => write!(f, "postgres replication error: {msg}"),
PgError::Protocol(msg) => write!(f, "postgres protocol error: {msg}"),
}
}
}
impl std::error::Error for PgError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
PgError::Postgres(e) => Some(e),
PgError::TypeConversion(_)
| PgError::Tls(_)
| PgError::ConstraintViolation { .. }
| PgError::Timeout(_)
| PgError::PoolExhausted(_)
| PgError::Copy(_)
| PgError::Notify(_)
| PgError::Connection(_)
| PgError::Replication(_)
| PgError::Protocol(_) => None,
}
}
}
impl From<tokio_postgres::Error> for PgError {
fn from(e: tokio_postgres::Error) -> Self {
use tokio_postgres::error::SqlState;
if let Some(db_err) = e.as_db_error() {
let code = db_err.code();
if code == &SqlState::UNIQUE_VIOLATION
|| code == &SqlState::FOREIGN_KEY_VIOLATION
|| code == &SqlState::CHECK_VIOLATION
{
return PgError::ConstraintViolation {
constraint: db_err.constraint().unwrap_or("unknown").to_string(),
detail: db_err.detail().unwrap_or("").to_string(),
};
}
}
PgError::Postgres(e)
}
}
impl From<std::io::Error> for PgError {
fn from(e: std::io::Error) -> Self {
PgError::Connection(e.to_string())
}
}
impl From<PgError> for oxisql_core::OxiSqlError {
fn from(e: PgError) -> Self {
match e {
PgError::ConstraintViolation {
ref constraint,
ref detail,
} => oxisql_core::OxiSqlError::ConstraintViolation(format!("'{constraint}': {detail}")),
PgError::Timeout(msg) => oxisql_core::OxiSqlError::Timeout(msg),
PgError::PoolExhausted(msg) => oxisql_core::OxiSqlError::ConnectionPool(msg),
PgError::Postgres(ref inner) if inner.code().is_some() => {
oxisql_core::OxiSqlError::Execution(e.to_string())
}
PgError::Postgres(_) => oxisql_core::OxiSqlError::Other(e.to_string()),
PgError::TypeConversion(msg) => {
oxisql_core::OxiSqlError::Other(format!("type conversion error: {msg}"))
}
PgError::Tls(msg) => oxisql_core::OxiSqlError::Other(msg),
PgError::Copy(msg) => oxisql_core::OxiSqlError::Other(format!("COPY error: {msg}")),
PgError::Notify(msg) => oxisql_core::OxiSqlError::Other(format!("NOTIFY error: {msg}")),
PgError::Connection(msg) => {
oxisql_core::OxiSqlError::Other(format!("connection error: {msg}"))
}
PgError::Replication(msg) => {
oxisql_core::OxiSqlError::Other(format!("replication error: {msg}"))
}
PgError::Protocol(msg) => {
oxisql_core::OxiSqlError::Other(format!("protocol error: {msg}"))
}
}
}
}