async_bb8_diesel/
error.rs

1//! bb8-diesel allows the bb8 asynchronous connection pool
2//! to be used underneath Diesel.
3//!
4//! This is currently implemented against Diesel's synchronous
5//! API, with calls to [`tokio::task::spawn_blocking`] to safely
6//! perform synchronous operations from an asynchronous task.
7
8use diesel::result::Error as DieselError;
9use diesel::OptionalExtension as OtherOptionalExtension;
10use thiserror::Error;
11
12/// Syntactic sugar around a Result returning an [`ConnectionError`].
13pub type ConnectionResult<R> = Result<R, ConnectionError>;
14
15/// Errors returned directly from Connection.
16#[derive(Error, Debug)]
17pub enum ConnectionError {
18    #[error("Connection error: {0}")]
19    Connection(#[from] diesel::r2d2::Error),
20
21    #[error("Failed to issue a query: {0}")]
22    Query(#[from] DieselError),
23}
24
25/// Syntactic sugar around a Result returning an [`PoolError`].
26pub type PoolResult<R> = Result<R, PoolError>;
27
28/// Async variant of [diesel::prelude::OptionalExtension].
29pub trait OptionalExtension<T> {
30    fn optional(self) -> Result<Option<T>, ConnectionError>;
31}
32
33impl<T> OptionalExtension<T> for Result<T, ConnectionError> {
34    fn optional(self) -> Result<Option<T>, ConnectionError> {
35        let self_as_query_result: diesel::QueryResult<T> = match self {
36            Ok(value) => Ok(value),
37            Err(ConnectionError::Query(error_kind)) => Err(error_kind),
38            Err(e) => return Err(e),
39        };
40
41        self_as_query_result
42            .optional()
43            .map_err(ConnectionError::Query)
44    }
45}
46
47/// Describes an error performing an operation from a connection pool.
48///
49/// This is a superset of [`ConnectionError`] which also may
50/// propagate errors attempting to access the connection pool.
51#[derive(Error, Debug)]
52pub enum PoolError {
53    #[error("Failure accessing a connection: {0}")]
54    Connection(#[from] ConnectionError),
55
56    #[error("BB8 Timeout accessing connection")]
57    Timeout,
58}
59
60impl From<DieselError> for PoolError {
61    fn from(error: DieselError) -> Self {
62        PoolError::Connection(ConnectionError::Query(error))
63    }
64}
65
66impl From<bb8::RunError<ConnectionError>> for PoolError {
67    fn from(error: bb8::RunError<ConnectionError>) -> Self {
68        match error {
69            bb8::RunError::User(e) => PoolError::Connection(e),
70            bb8::RunError::TimedOut => PoolError::Timeout,
71        }
72    }
73}