1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use std::ops::{Deref, DerefMut};

use async_trait::async_trait;
use bb8::{Builder, ManageConnection, Pool, PooledConnection, RunError};
use diesel::{result::Error, ConnectionError};
use diesel_async::{
    pooled_connection::{AsyncDieselConnectionManager as Manager, PoolError as DieselPoolError},
    AsyncConnection,
};

use crate::r#async::backend::error::Error as BackendError;

use super::r#trait::DieselPoolAssociation;

/// [`Diesel bb8`](https://docs.rs/diesel-async/0.4.1/diesel_async/pooled_connection/bb8/index.html) association
/// # Example
/// ```
/// use bb8::Pool;
/// use db_pool::{
///     r#async::{DieselAsyncPostgresBackend, DieselBb8},
///     PrivilegedPostgresConfig,
/// };
/// use diesel::sql_query;
/// use diesel_async::RunQueryDsl;
/// use dotenvy::dotenv;
///
/// async fn f() {
///     dotenv().ok();
///
///     let config = PrivilegedPostgresConfig::from_env().unwrap();
///
///     let backend = DieselAsyncPostgresBackend::<DieselBb8>::new(
///         config,
///         || Pool::builder().max_size(10),
///         || Pool::builder().max_size(2),
///         move |mut conn| {
///             Box::pin(async {
///                 sql_query("CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)")
///                     .execute(&mut conn)
///                     .await
///                     .unwrap();
///                 conn
///             })
///         },
///     )
///     .await
///     .unwrap();
/// }
///
/// tokio_test::block_on(f());
/// ```
pub struct DieselBb8;

#[async_trait]
impl<Connection> DieselPoolAssociation<Connection> for DieselBb8
where
    Connection: AsyncConnection + 'static,
    Manager<Connection>: ManageConnection,
    for<'pool> PooledConnection<'pool, Manager<Connection>>: DerefMut<Target = Connection>,
    <Manager<Connection> as ManageConnection>::Error: Into<RunError<DieselPoolError>>,
    RunError<<Manager<Connection> as ManageConnection>::Error>: Into<RunError<DieselPoolError>>,
{
    type PooledConnection<'pool> = PooledConnection<'pool, Manager<Connection>>;

    type Builder = Builder<Manager<Connection>>;
    type Pool = Pool<Manager<Connection>>;

    type BuildError = BuildError;
    type PoolError = PoolError;

    async fn build_pool(
        builder: Self::Builder,
        manager: Manager<Connection>,
    ) -> Result<Self::Pool, Self::BuildError> {
        builder
            .build(manager)
            .await
            .map_err(|err| err.into().into())
    }

    async fn get_connection<'pool>(
        pool: &'pool Self::Pool,
    ) -> Result<Self::PooledConnection<'pool>, Self::PoolError> {
        pool.get().await.map_err(|err| err.into().into())
    }
}

#[derive(Debug)]
pub struct BuildError(RunError<DieselPoolError>);

impl Deref for BuildError {
    type Target = RunError<DieselPoolError>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<RunError<DieselPoolError>> for BuildError {
    fn from(value: RunError<DieselPoolError>) -> Self {
        Self(value)
    }
}

#[derive(Debug)]
pub struct PoolError(RunError<DieselPoolError>);

impl Deref for PoolError {
    type Target = RunError<DieselPoolError>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<RunError<DieselPoolError>> for PoolError {
    fn from(value: RunError<DieselPoolError>) -> Self {
        Self(value)
    }
}

impl From<BuildError> for BackendError<BuildError, PoolError, ConnectionError, Error> {
    fn from(value: BuildError) -> Self {
        Self::Build(value)
    }
}

impl From<PoolError> for BackendError<BuildError, PoolError, ConnectionError, Error> {
    fn from(value: PoolError) -> Self {
        Self::Pool(value)
    }
}