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
use std::ops::Deref;

use async_trait::async_trait;
use mobc::{Builder, Connection, Error as MobcError, Pool};
use mobc_postgres::PgConnectionManager;
use tokio_postgres::{Config, Error, NoTls};

use crate::r#async::backend::{
    common::error::tokio_postgres::{ConnectionError, QueryError},
    error::Error as BackendError,
};

use super::r#trait::TokioPostgresPoolAssociation;

type Manager = PgConnectionManager<NoTls>;

/// [`tokio-postgres mobc`](https://docs.rs/mobc-postgres/latest/mobc_postgres/) association
/// # Example
/// ```
/// use db_pool::r#async::{TokioPostgresBackend, TokioPostgresMobc};
/// use mobc::Pool;
/// use tokio_postgres::Config;
///
/// async fn f() {
///     let backend = TokioPostgresBackend::<TokioPostgresMobc>::new(
///         "host=localhost user=postgres password=postgres"
///             .parse::<Config>()
///             .unwrap(),
///         || Pool::builder().max_open(10),
///         || Pool::builder().max_open(2),
///         move |conn| {
///             Box::pin(async move {
///                 conn.execute(
///                     "CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)",
///                     &[],
///                 )
///                 .await
///                 .unwrap();
///                 conn
///             })
///         },
///     )
///     .await
///     .unwrap();
/// }
///
/// tokio_test::block_on(f());
/// ```
pub struct TokioPostgresMobc;

#[async_trait]
impl TokioPostgresPoolAssociation for TokioPostgresMobc {
    type PooledConnection<'pool> = Connection<Manager>;

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

    type BuildError = BuildError;
    type PoolError = PoolError;

    async fn build_pool(
        builder: Builder<Manager>,
        config: Config,
    ) -> Result<Self::Pool, Self::BuildError> {
        let manager = Manager::new(config, NoTls);
        Ok(builder.build(manager))
    }

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

#[derive(Debug)]
pub struct BuildError(MobcError<Error>);

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

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

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

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

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

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

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

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

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