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
133
use std::ops::{Deref, DerefMut};

use async_trait::async_trait;
use diesel::{result::Error as DieselError, ConnectionError};
use diesel_async::{
    pooled_connection::{AsyncDieselConnectionManager, PoolError as DieselPoolError},
    AsyncConnection,
};
use mobc::{
    Builder, Connection as MobcConnection, Error as MobcError, Manager as MobcManager, Pool,
};

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

use super::r#trait::DieselPoolAssociation;

type DieselManager<Connection> = AsyncDieselConnectionManager<Connection>;

/// [`Diesel mobc`](https://docs.rs/diesel-async/0.4.1/diesel_async/pooled_connection/mobc/index.html) association
/// # Example
/// ```
/// use db_pool::{
///     r#async::{DieselAsyncPostgresBackend, DieselMobc},
///     PrivilegedPostgresConfig,
/// };
/// use diesel::sql_query;
/// use diesel_async::{pooled_connection::ManagerConfig, RunQueryDsl};
/// use dotenvy::dotenv;
/// use mobc::Pool;
///
/// async fn f() {
///     dotenv().ok();
///
///     let config = PrivilegedPostgresConfig::from_env().unwrap();
///
///     let backend = DieselAsyncPostgresBackend::<DieselMobc>::new(
///         config,
///         ManagerConfig::default(),
///         || Pool::builder().max_open(10),
///         || Pool::builder().max_open(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 DieselMobc;

#[async_trait]
impl<Connection> DieselPoolAssociation<Connection> for DieselMobc
where
    Connection: AsyncConnection + 'static,
    DieselManager<Connection>: MobcManager,
    for<'pool> MobcConnection<DieselManager<Connection>>: DerefMut<Target = Connection>,
    MobcError<<DieselManager<Connection> as MobcManager>::Error>: Into<MobcError<DieselPoolError>>,
{
    type PooledConnection<'pool> = MobcConnection<DieselManager<Connection>>;

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

    type BuildError = BuildError;
    type PoolError = PoolError;

    async fn build_pool(
        builder: Builder<DieselManager<Connection>>,
        manager: DieselManager<Connection>,
    ) -> Result<Self::Pool, Self::BuildError> {
        Ok(builder.build(manager))
    }

    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(MobcError<DieselPoolError>);

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

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

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

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

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

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

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

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

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