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