diesel_async/pg/
error_helper.rs1use std::error::Error;
2use std::sync::Arc;
3
4use diesel::ConnectionError;
5
6pub(super) struct ErrorHelper(pub(super) tokio_postgres::Error);
7
8impl From<ErrorHelper> for ConnectionError {
9 fn from(postgres_error: ErrorHelper) -> Self {
10 ConnectionError::CouldntSetupConfiguration(postgres_error.into())
11 }
12}
13
14impl From<ErrorHelper> for diesel::result::Error {
15 fn from(ErrorHelper(postgres_error): ErrorHelper) -> Self {
16 from_tokio_postgres_error(Arc::new(postgres_error))
17 }
18}
19
20pub(super) fn from_tokio_postgres_error(
21 postgres_error: Arc<tokio_postgres::Error>,
22) -> diesel::result::Error {
23 use diesel::result::DatabaseErrorKind::*;
24 use tokio_postgres::error::SqlState;
25
26 match postgres_error.code() {
27 Some(code) => {
28 let kind = match *code {
29 SqlState::UNIQUE_VIOLATION => UniqueViolation,
30 SqlState::FOREIGN_KEY_VIOLATION => ForeignKeyViolation,
31 SqlState::T_R_SERIALIZATION_FAILURE => SerializationFailure,
32 SqlState::READ_ONLY_SQL_TRANSACTION => ReadOnlyTransaction,
33 SqlState::NOT_NULL_VIOLATION => NotNullViolation,
34 SqlState::CHECK_VIOLATION => CheckViolation,
35 _ => Unknown,
36 };
37
38 diesel::result::Error::DatabaseError(
39 kind,
40 Box::new(PostgresDbErrorWrapper(
41 postgres_error
42 .source()
43 .and_then(|e| e.downcast_ref::<tokio_postgres::error::DbError>().cloned())
44 .expect("It's a db error, because we've got a SQLState code above"),
45 )) as _,
46 )
47 }
48 None => diesel::result::Error::DatabaseError(
49 UnableToSendCommand,
50 Box::new(postgres_error.to_string()),
51 ),
52 }
53}
54
55struct PostgresDbErrorWrapper(tokio_postgres::error::DbError);
56
57impl diesel::result::DatabaseErrorInformation for PostgresDbErrorWrapper {
58 fn message(&self) -> &str {
59 self.0.message()
60 }
61
62 fn details(&self) -> Option<&str> {
63 self.0.detail()
64 }
65
66 fn hint(&self) -> Option<&str> {
67 self.0.hint()
68 }
69
70 fn table_name(&self) -> Option<&str> {
71 self.0.table()
72 }
73
74 fn column_name(&self) -> Option<&str> {
75 self.0.column()
76 }
77
78 fn constraint_name(&self) -> Option<&str> {
79 self.0.constraint()
80 }
81
82 fn statement_position(&self) -> Option<i32> {
83 use tokio_postgres::error::ErrorPosition;
84 self.0.position().and_then(|e| match *e {
85 ErrorPosition::Original(position) | ErrorPosition::Internal { position, .. } => {
86 position.try_into().ok()
87 }
88 })
89 }
90}