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 {}