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