1use thiserror::Error;
5
6use std::error::Error as StdError;
7
8#[derive(Debug, Error)]
9pub enum ConnError {
10 #[error("no connection source resolved")]
11 NoSource,
12
13 #[error("profile not found: {0}")]
14 ProfileNotFound(String),
15
16 #[error("invalid connection URL: {0}")]
17 InvalidUrl(String),
18
19 #[error("config error: {0}")]
20 Config(String),
21
22 #[error("password_command failed: {0}")]
23 PasswordCommand(String),
24
25 #[error("password_command produced empty stdout")]
26 EmptyPasswordCommand,
27
28 #[error("env-file error: {0}")]
29 EnvFile(String),
30
31 #[error("pgpass error: {0}")]
32 PgPass(String),
33
34 #[error("pool error: {0}")]
35 Pool(String),
36
37 #[error("postgres error: {}", format_postgres_error(.0))]
38 Postgres(#[from] tokio_postgres::Error),
39
40 #[error("io error: {0}")]
41 Io(#[from] std::io::Error),
42}
43
44pub fn format_postgres_error(e: &tokio_postgres::Error) -> String {
46 if let Some(db_err) = e.as_db_error() {
47 let mut msg = db_err.message().to_string();
48 if let Some(detail) = db_err.detail() {
49 msg.push_str(&format!(" ({detail})"));
50 }
51 if let Some(hint) = db_err.hint() {
52 msg.push_str(&format!(" [hint: {hint}]"));
53 }
54 msg
55 } else {
56 let mut msg = e.to_string();
57 if let Some(source) = StdError::source(e) {
58 let detail = source.to_string();
59 if !detail.is_empty() && detail != msg {
60 msg.push_str(&format!(" ({detail})"));
61 }
62 }
63 msg
64 }
65}