db_pool/async/db_pool.rs
1use std::sync::Arc;
2
3use async_trait::async_trait;
4
5use super::{
6 backend::{Error, r#trait::Backend},
7 conn_pool::{ReusableConnectionPool as ReusableConnectionPoolInner, SingleUseConnectionPool},
8 object_pool::{ObjectPool, Reusable},
9};
10
11/// Wrapper for a reusable connection pool wrapped in a reusable object wrapper
12pub type ReusableConnectionPool<'a, B> = Reusable<'a, ReusableConnectionPoolInner<B>>;
13
14/// Database pool
15pub struct DatabasePool<B: Backend> {
16 backend: Arc<B>,
17 object_pool: ObjectPool<ReusableConnectionPoolInner<B>>,
18}
19
20impl<B: Backend> DatabasePool<B> {
21 /// Pulls a reusable connection pool
22 ///
23 /// Privileges are granted only for ``SELECT``, ``INSERT``, ``UPDATE``, and ``DELETE`` operations.
24 /// # Example
25 /// ```
26 /// use bb8::Pool;
27 /// use db_pool::{
28 /// r#async::{DatabasePoolBuilderTrait, DieselAsyncPostgresBackend, DieselBb8},
29 /// PrivilegedPostgresConfig,
30 /// };
31 /// use diesel::sql_query;
32 /// use diesel_async::RunQueryDsl;
33 /// use dotenvy::dotenv;
34 ///
35 /// async fn f() {
36 /// dotenv().ok();
37 ///
38 /// let config = PrivilegedPostgresConfig::from_env().unwrap();
39 ///
40 /// let backend = DieselAsyncPostgresBackend::<DieselBb8>::new(
41 /// config,
42 /// |_| Pool::builder().max_size(10),
43 /// |_| Pool::builder().max_size(2),
44 /// None,
45 /// move |mut conn| {
46 /// Box::pin(async {
47 /// sql_query("CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)")
48 /// .execute(&mut conn)
49 /// .await
50 /// .unwrap();
51 /// Some(conn)
52 /// })
53 /// },
54 /// )
55 /// .await
56 /// .unwrap();
57 ///
58 /// let db_pool = backend.create_database_pool().await.unwrap();
59 /// let conn_pool = db_pool.pull_immutable();
60 /// }
61 ///
62 /// tokio_test::block_on(f());
63 /// ```
64 #[must_use]
65 pub async fn pull_immutable(&self) -> ReusableConnectionPool<B> {
66 self.object_pool.pull().await
67 }
68
69 /// Creates a single-use connection pool
70 ///
71 /// All privileges are granted.
72 /// # Example
73 /// ```
74 /// use bb8::Pool;
75 /// use db_pool::{
76 /// r#async::{DatabasePoolBuilderTrait, DieselAsyncPostgresBackend, DieselBb8},
77 /// PrivilegedPostgresConfig,
78 /// };
79 /// use diesel::sql_query;
80 /// use diesel_async::RunQueryDsl;
81 /// use dotenvy::dotenv;
82 ///
83 /// async fn f() {
84 /// dotenv().ok();
85 ///
86 /// let config = PrivilegedPostgresConfig::from_env().unwrap();
87 ///
88 /// let backend = DieselAsyncPostgresBackend::<DieselBb8>::new(
89 /// config,
90 /// |_| Pool::builder().max_size(10),
91 /// |_| Pool::builder().max_size(2),
92 /// None,
93 /// move |mut conn| {
94 /// Box::pin(async {
95 /// sql_query("CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)")
96 /// .execute(&mut conn)
97 /// .await
98 /// .unwrap();
99 /// Some(conn)
100 /// })
101 /// },
102 /// )
103 /// .await
104 /// .unwrap();
105 ///
106 /// let db_pool = backend.create_database_pool().await.unwrap();
107 /// let conn_pool = db_pool.create_mutable();
108 /// }
109 ///
110 /// tokio_test::block_on(f());
111 /// ```
112 pub async fn create_mutable(
113 &self,
114 ) -> Result<
115 SingleUseConnectionPool<B>,
116 Error<B::BuildError, B::PoolError, B::ConnectionError, B::QueryError>,
117 > {
118 SingleUseConnectionPool::new(self.backend.clone()).await
119 }
120}
121
122/// Database pool builder trait implemented for all async backends
123#[async_trait]
124pub trait DatabasePoolBuilder: Backend {
125 /// Creates a database pool
126 /// # Example
127 /// ```
128 /// use bb8::Pool;
129 /// use db_pool::{
130 /// r#async::{DatabasePoolBuilderTrait, DieselAsyncPostgresBackend, DieselBb8},
131 /// PrivilegedPostgresConfig,
132 /// };
133 /// use diesel::sql_query;
134 /// use diesel_async::RunQueryDsl;
135 /// use dotenvy::dotenv;
136 ///
137 /// async fn f() {
138 /// dotenv().ok();
139 ///
140 /// let config = PrivilegedPostgresConfig::from_env().unwrap();
141 ///
142 /// let backend = DieselAsyncPostgresBackend::<DieselBb8>::new(
143 /// config,
144 /// |_| Pool::builder().max_size(10),
145 /// |_| Pool::builder().max_size(2),
146 /// None,
147 /// move |mut conn| {
148 /// Box::pin(async {
149 /// sql_query("CREATE TABLE book(id SERIAL PRIMARY KEY, title TEXT NOT NULL)")
150 /// .execute(&mut conn)
151 /// .await
152 /// .unwrap();
153 /// Some(conn)
154 /// })
155 /// },
156 /// )
157 /// .await
158 /// .unwrap();
159 ///
160 /// let db_pool = backend.create_database_pool().await.unwrap();
161 /// }
162 ///
163 /// tokio_test::block_on(f());
164 /// ```
165 async fn create_database_pool(
166 self,
167 ) -> Result<
168 DatabasePool<Self>,
169 Error<Self::BuildError, Self::PoolError, Self::ConnectionError, Self::QueryError>,
170 > {
171 self.init().await?;
172 let backend = Arc::new(self);
173 let object_pool = {
174 let backend = backend.clone();
175 ObjectPool::new(
176 move || {
177 let backend = backend.clone();
178 Box::pin(async {
179 ReusableConnectionPoolInner::new(backend)
180 .await
181 .expect("connection pool creation must succeed")
182 })
183 },
184 |mut conn_pool| {
185 Box::pin(async {
186 conn_pool
187 .clean()
188 .await
189 .expect("connection pool cleaning must succeed");
190 conn_pool
191 })
192 },
193 )
194 };
195 Ok(DatabasePool {
196 backend,
197 object_pool,
198 })
199 }
200}
201
202impl<AB: Backend> DatabasePoolBuilder for AB {}