use crate::error::Error;
impl From<tokio_postgres::error::Error> for Error {
fn from(e: tokio_postgres::error::Error) -> Error {
use tokio_postgres::error::DbError;
match e.code().map(|c| c.code()) {
Some("23505") => {
let error = e.into_source().unwrap(); let db_error = error.downcast_ref::<DbError>().unwrap(); let detail = db_error.detail().unwrap();
let splitted: Vec<&str> = detail.split(")=(").collect();
let splitted: Vec<&str> = splitted[0].split(" (").collect();
let field_name = splitted[1].replace("\"", "");
Error::UniqueConstraintViolation { field_name }
}
Some("23502") => {
let error = e.into_source().unwrap(); let db_error = error.downcast_ref::<DbError>().unwrap(); let detail = db_error.detail().unwrap();
let splitted: Vec<&str> = detail.split(")=(").collect();
let splitted: Vec<&str> = splitted[0].split(" (").collect();
let field_name = splitted[1].replace("\"", "");
Error::NullConstraintViolation { field_name }
}
Some("3D000") => {
let error = e.into_source().unwrap(); let db_error = error.downcast_ref::<DbError>().unwrap(); let message = db_error.message();
let splitted: Vec<&str> = message.split_whitespace().collect();
let splitted: Vec<&str> = splitted[1].split('"').collect();
let db_name = splitted[1].into();
Error::DatabaseDoesNotExist { db_name }
}
Some("28P01") => {
let error = e.into_source().unwrap(); let db_error = error.downcast_ref::<DbError>().unwrap(); let message = db_error.message();
let splitted: Vec<&str> = message.split_whitespace().collect();
let splitted: Vec<&str> = splitted.last().unwrap().split('"').collect();
let user = splitted[1].into();
Error::AuthenticationFailed { user }
}
Some("42P04") => {
let error = e.into_source().unwrap(); let db_error = error.downcast_ref::<DbError>().unwrap(); let message = db_error.message();
let splitted: Vec<&str> = message.split_whitespace().collect();
let splitted: Vec<&str> = splitted[1].split('"').collect();
let db_name = splitted[1].into();
Error::DatabaseAlreadyExists { db_name }
}
_ => {
if let Some(tls_error) = try_extracting_tls_error(&e) {
return tls_error;
}
if let Some(io_error) = try_extracting_io_error(&e) {
return io_error;
}
let reason = format!("{}", e);
match reason.as_str() {
"error connecting to server: timed out" => Error::ConnectTimeout, "error performing TLS handshake: server does not support TLS" => {
Error::TlsError { message: reason }
} _ => Error::QueryError(e.into()),
}
}
}
}
}
fn try_extracting_tls_error(err: &tokio_postgres::error::Error) -> Option<Error> {
use std::error::Error;
err.source()
.and_then(|err| err.downcast_ref::<native_tls::Error>())
.map(|err| err.into())
}
fn try_extracting_io_error(err: &tokio_postgres::error::Error) -> Option<Error> {
use std::error::Error as _;
err.source()
.and_then(|err| err.downcast_ref::<std::io::Error>())
.map(|err| Error::ConnectionError(Box::new(std::io::Error::new(
err.kind(),
format!("{}", err),
))))
}
impl From<native_tls::Error> for Error {
fn from(e: native_tls::Error) -> Error {
Error::from(&e)
}
}
impl From<&native_tls::Error> for Error {
fn from(e: &native_tls::Error) -> Error {
Error::TlsError {
message: format!("{}", e),
}
}
}