db_pool/sync/
db_pool.rs

1use std::sync::Arc;
2
3use super::{
4    backend::{r#trait::Backend, Error},
5    conn_pool::{ReusableConnectionPool as ReusableConnectionPoolInner, SingleUseConnectionPool},
6    object_pool::{ObjectPool, Reusable},
7};
8
9/// Wrapper for a reusable connection pool wrapped in a reusable object wrapper
10pub type ReusableConnectionPool<'a, B> = Reusable<'a, ReusableConnectionPoolInner<B>>;
11
12/// Database pool
13pub struct DatabasePool<B: Backend> {
14    backend: Arc<B>,
15    object_pool: ObjectPool<ReusableConnectionPoolInner<B>>,
16}
17
18impl<B: Backend> DatabasePool<B> {
19    /// Pulls a reusable connection pool
20    ///
21    /// Privileges are granted only for ``SELECT``, ``INSERT``, ``UPDATE``, and ``DELETE`` operations.
22    /// # Example
23    /// ```
24    /// use db_pool::{
25    ///     sync::{DatabasePoolBuilderTrait, DieselPostgresBackend},
26    ///     PrivilegedPostgresConfig,
27    /// };
28    /// use diesel::{sql_query, RunQueryDsl};
29    /// use dotenvy::dotenv;
30    /// use r2d2::Pool;
31    ///
32    /// dotenv().ok();
33    ///
34    /// let config = PrivilegedPostgresConfig::from_env().unwrap();
35    ///
36    /// let backend = DieselPostgresBackend::new(
37    ///     config,
38    ///     || Pool::builder().max_size(10),
39    ///     || Pool::builder().max_size(2),
40    ///     move |conn| {
41    ///         sql_query("CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)")
42    ///             .execute(conn)
43    ///             .unwrap();
44    ///     },
45    /// )
46    /// .unwrap();
47    ///
48    /// let db_pool = backend.create_database_pool().unwrap();
49    /// let conn_pool = db_pool.pull_immutable();
50    /// ```
51    #[must_use]
52    pub fn pull_immutable(&self) -> Reusable<ReusableConnectionPoolInner<B>> {
53        self.object_pool.pull()
54    }
55
56    /// Creates a single-use connection pool
57    ///
58    /// All privileges are granted.
59    /// # Example
60    /// ```
61    /// use db_pool::{
62    ///     sync::{DatabasePoolBuilderTrait, DieselPostgresBackend},
63    ///     PrivilegedPostgresConfig,
64    /// };
65    /// use diesel::{sql_query, RunQueryDsl};
66    /// use dotenvy::dotenv;
67    /// use r2d2::Pool;
68    ///
69    /// dotenv().ok();
70    ///
71    /// let config = PrivilegedPostgresConfig::from_env().unwrap();
72    ///
73    /// let backend = DieselPostgresBackend::new(
74    ///     config,
75    ///     || Pool::builder().max_size(10),
76    ///     || Pool::builder().max_size(2),
77    ///     move |conn| {
78    ///         sql_query("CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)")
79    ///             .execute(conn)
80    ///             .unwrap();
81    ///     },
82    /// )
83    /// .unwrap();
84    ///
85    /// let db_pool = backend.create_database_pool().unwrap();
86    /// let conn_pool = db_pool.create_mutable();
87    /// ```
88    pub fn create_mutable(
89        &self,
90    ) -> Result<SingleUseConnectionPool<B>, Error<B::ConnectionError, B::QueryError>> {
91        SingleUseConnectionPool::new(self.backend.clone())
92    }
93}
94
95/// Database pool builder trait implemented for all sync backends
96pub trait DatabasePoolBuilder: Backend {
97    /// Creates a database pool
98    /// # Example
99    /// ```
100    /// use db_pool::{
101    ///     sync::{DatabasePoolBuilderTrait, DieselPostgresBackend},
102    ///     PrivilegedPostgresConfig,
103    /// };
104    /// use diesel::{sql_query, RunQueryDsl};
105    /// use dotenvy::dotenv;
106    /// use r2d2::Pool;
107    ///
108    /// dotenv().ok();
109    ///
110    /// let config = PrivilegedPostgresConfig::from_env().unwrap();
111    ///
112    /// let backend = DieselPostgresBackend::new(
113    ///     config,
114    ///     || Pool::builder().max_size(10),
115    ///     || Pool::builder().max_size(2),
116    ///     move |conn| {
117    ///         sql_query("CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)")
118    ///             .execute(conn)
119    ///             .unwrap();
120    ///     },
121    /// )
122    /// .unwrap();
123    ///
124    /// let db_pool = backend.create_database_pool().unwrap();
125    /// ```
126    fn create_database_pool(
127        self,
128    ) -> Result<DatabasePool<Self>, Error<Self::ConnectionError, Self::QueryError>> {
129        self.init()?;
130        let backend = Arc::new(self);
131        let object_pool = {
132            let backend = backend.clone();
133            ObjectPool::new(
134                move || {
135                    let backend = backend.clone();
136                    ReusableConnectionPoolInner::new(backend)
137                        .expect("connection pool creation must succeed")
138                },
139                |conn_pool| {
140                    conn_pool
141                        .clean()
142                        .expect("connection pool cleaning must succeed");
143                },
144            )
145        };
146        Ok(DatabasePool {
147            backend,
148            object_pool,
149        })
150    }
151}
152
153impl<B> DatabasePoolBuilder for B where B: Backend + Sized {}