1#[derive(Debug)]
6pub enum PgError {
7 Postgres(tokio_postgres::Error),
9 TypeConversion(String),
11 Tls(String),
13 ConstraintViolation {
15 constraint: String,
17 detail: String,
19 },
20 Timeout(String),
22 PoolExhausted(String),
24 Copy(String),
26 Notify(String),
28}
29
30impl std::fmt::Display for PgError {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 PgError::Postgres(e) => write!(f, "postgres error: {e}"),
34 PgError::TypeConversion(msg) => write!(f, "type conversion error: {msg}"),
35 PgError::Tls(msg) => write!(f, "TLS error: {msg}"),
36 PgError::ConstraintViolation { constraint, detail } => {
37 write!(f, "constraint violation on '{constraint}': {detail}")
38 }
39 PgError::Timeout(msg) => write!(f, "postgres timeout: {msg}"),
40 PgError::PoolExhausted(msg) => write!(f, "postgres pool exhausted: {msg}"),
41 PgError::Copy(msg) => write!(f, "postgres COPY error: {msg}"),
42 PgError::Notify(msg) => write!(f, "postgres NOTIFY error: {msg}"),
43 }
44 }
45}
46
47impl std::error::Error for PgError {
48 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
49 match self {
50 PgError::Postgres(e) => Some(e),
51 PgError::TypeConversion(_)
52 | PgError::Tls(_)
53 | PgError::ConstraintViolation { .. }
54 | PgError::Timeout(_)
55 | PgError::PoolExhausted(_)
56 | PgError::Copy(_)
57 | PgError::Notify(_) => None,
58 }
59 }
60}
61
62impl From<tokio_postgres::Error> for PgError {
63 fn from(e: tokio_postgres::Error) -> Self {
64 use tokio_postgres::error::SqlState;
65 if let Some(db_err) = e.as_db_error() {
66 let code = db_err.code();
67 if code == &SqlState::UNIQUE_VIOLATION
68 || code == &SqlState::FOREIGN_KEY_VIOLATION
69 || code == &SqlState::CHECK_VIOLATION
70 {
71 return PgError::ConstraintViolation {
72 constraint: db_err.constraint().unwrap_or("unknown").to_string(),
73 detail: db_err.detail().unwrap_or("").to_string(),
74 };
75 }
76 }
77 PgError::Postgres(e)
78 }
79}
80
81impl From<PgError> for oxisql_core::OxiSqlError {
82 fn from(e: PgError) -> Self {
83 match e {
84 PgError::ConstraintViolation {
85 ref constraint,
86 ref detail,
87 } => oxisql_core::OxiSqlError::ConstraintViolation(format!("'{constraint}': {detail}")),
88 PgError::Timeout(msg) => oxisql_core::OxiSqlError::Timeout(msg),
89 PgError::PoolExhausted(msg) => oxisql_core::OxiSqlError::ConnectionPool(msg),
90 PgError::Postgres(ref inner) if inner.code().is_some() => {
91 oxisql_core::OxiSqlError::Execution(e.to_string())
92 }
93 PgError::Postgres(_) => oxisql_core::OxiSqlError::Other(e.to_string()),
94 PgError::TypeConversion(msg) => {
97 oxisql_core::OxiSqlError::Other(format!("type conversion error: {msg}"))
98 }
99 PgError::Tls(msg) => oxisql_core::OxiSqlError::Other(msg),
100 PgError::Copy(msg) => oxisql_core::OxiSqlError::Other(format!("COPY error: {msg}")),
101 PgError::Notify(msg) => oxisql_core::OxiSqlError::Other(format!("NOTIFY error: {msg}")),
102 }
103 }
104}