8
8
use crate :: { AsyncConnection , SimpleAsyncConnection } ;
9
9
use crate :: { TransactionManager , UpdateAndFetchResults } ;
10
10
use diesel:: associations:: HasTable ;
11
- use diesel:: query_builder:: { QueryFragment , QueryId } ;
12
11
use diesel:: QueryResult ;
13
12
use futures_util:: { future, FutureExt } ;
13
+ use std:: borrow:: Cow ;
14
14
use std:: fmt;
15
15
use std:: ops:: DerefMut ;
16
16
@@ -42,18 +42,83 @@ impl fmt::Display for PoolError {
42
42
43
43
impl std:: error:: Error for PoolError { }
44
44
45
- type SetupCallback < C > =
45
+ /// Type of the custom setup closure passed to [`ManagerConfig::custom_setup`]
46
+ pub type SetupCallback < C > =
46
47
Box < dyn Fn ( & str ) -> future:: BoxFuture < diesel:: ConnectionResult < C > > + Send + Sync > ;
47
48
49
+ /// Type of the recycle check callback for the [`RecyclingMethod::CustomFunction`] variant
50
+ pub type RecycleCheckCallback < C > =
51
+ dyn Fn ( & mut C ) -> future:: BoxFuture < QueryResult < ( ) > > + Send + Sync ;
52
+
53
+ /// Possible methods of how a connection is recycled.
54
+ #[ derive( Default ) ]
55
+ pub enum RecyclingMethod < C > {
56
+ /// Only check for open transactions when recycling existing connections
57
+ /// Unless you have special needs this is a safe choice.
58
+ ///
59
+ /// If the database connection is closed you will recieve an error on the first place
60
+ /// you actually try to use the connection
61
+ Fast ,
62
+ /// In addition to checking for open transactions a test query is executed
63
+ ///
64
+ /// This is slower, but guarantees that the database connection is ready to be used.
65
+ #[ default]
66
+ Verified ,
67
+ /// Like `Verified` but with a custom query
68
+ CustomQuery ( Cow < ' static , str > ) ,
69
+ /// Like `Verified` but with a custom callback that allows to perform more checks
70
+ ///
71
+ /// The connection is only recycled if the callback returns `Ok(())`
72
+ CustomFunction ( Box < RecycleCheckCallback < C > > ) ,
73
+ }
74
+
75
+ impl < C : fmt:: Debug > fmt:: Debug for RecyclingMethod < C > {
76
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
77
+ match self {
78
+ Self :: Fast => write ! ( f, "Fast" ) ,
79
+ Self :: Verified => write ! ( f, "Verified" ) ,
80
+ Self :: CustomQuery ( arg0) => f. debug_tuple ( "CustomQuery" ) . field ( arg0) . finish ( ) ,
81
+ Self :: CustomFunction ( _) => f. debug_tuple ( "CustomFunction" ) . finish ( ) ,
82
+ }
83
+ }
84
+ }
85
+
86
+ /// Configuration object for a Manager.
87
+ ///
88
+ /// This currently only makes it possible to specify which [`RecyclingMethod`]
89
+ /// should be used when retrieving existing objects from the [`Pool`].
90
+ pub struct ManagerConfig < C > {
91
+ /// Method of how a connection is recycled. See [RecyclingMethod].
92
+ pub recycling_method : RecyclingMethod < C > ,
93
+ /// Construct a new connection manger
94
+ /// with a custom setup procedure
95
+ ///
96
+ /// This can be used to for example establish a SSL secured
97
+ /// postgres connection
98
+ pub custom_setup : SetupCallback < C > ,
99
+ }
100
+
101
+ impl < C > Default for ManagerConfig < C >
102
+ where
103
+ C : AsyncConnection + ' static ,
104
+ {
105
+ fn default ( ) -> Self {
106
+ Self {
107
+ recycling_method : Default :: default ( ) ,
108
+ custom_setup : Box :: new ( |url| C :: establish ( url) . boxed ( ) ) ,
109
+ }
110
+ }
111
+ }
112
+
48
113
/// An connection manager for use with diesel-async.
49
114
///
50
115
/// See the concrete pool implementations for examples:
51
116
/// * [deadpool](self::deadpool)
52
117
/// * [bb8](self::bb8)
53
118
/// * [mobc](self::mobc)
54
119
pub struct AsyncDieselConnectionManager < C > {
55
- setup : SetupCallback < C > ,
56
120
connection_url : String ,
121
+ manager_config : ManagerConfig < C > ,
57
122
}
58
123
59
124
impl < C > fmt:: Debug for AsyncDieselConnectionManager < C > {
@@ -66,28 +131,31 @@ impl<C> fmt::Debug for AsyncDieselConnectionManager<C> {
66
131
}
67
132
}
68
133
69
- impl < C > AsyncDieselConnectionManager < C > {
134
+ impl < C > AsyncDieselConnectionManager < C >
135
+ where
136
+ C : AsyncConnection + ' static ,
137
+ {
70
138
/// Returns a new connection manager,
71
139
/// which establishes connections to the given database URL.
140
+ #[ must_use]
72
141
pub fn new ( connection_url : impl Into < String > ) -> Self
73
142
where
74
143
C : AsyncConnection + ' static ,
75
144
{
76
- Self :: new_with_setup ( connection_url, |url| C :: establish ( url ) . boxed ( ) )
145
+ Self :: new_with_config ( connection_url, Default :: default ( ) )
77
146
}
78
147
79
- /// Construct a new connection manger
80
- /// with a custom setup procedure
81
- ///
82
- /// This can be used to for example establish a SSL secured
83
- /// postgres connection
84
- pub fn new_with_setup (
148
+ /// Returns a new connection manager,
149
+ /// which establishes connections with the given database URL
150
+ /// and that uses the specified configuration
151
+ #[ must_use]
152
+ pub fn new_with_config (
85
153
connection_url : impl Into < String > ,
86
- setup : impl Fn ( & str ) -> future :: BoxFuture < diesel :: ConnectionResult < C > > + Send + Sync + ' static ,
154
+ manager_config : ManagerConfig < C > ,
87
155
) -> Self {
88
156
Self {
89
- setup : Box :: new ( setup) ,
90
157
connection_url : connection_url. into ( ) ,
158
+ manager_config,
91
159
}
92
160
}
93
161
}
@@ -218,9 +286,8 @@ where
218
286
}
219
287
}
220
288
221
- #[ doc( hidden) ]
222
289
#[ derive( diesel:: query_builder:: QueryId ) ]
223
- pub struct CheckConnectionQuery ;
290
+ struct CheckConnectionQuery ;
224
291
225
292
impl < DB > diesel:: query_builder:: QueryFragment < DB > for CheckConnectionQuery
226
293
where
@@ -244,19 +311,34 @@ impl<C> diesel::query_dsl::RunQueryDsl<C> for CheckConnectionQuery {}
244
311
#[ doc( hidden) ]
245
312
#[ async_trait:: async_trait]
246
313
pub trait PoolableConnection : AsyncConnection {
247
- type PingQuery : QueryFragment < Self :: Backend > + QueryId + Send ;
248
-
249
- fn make_ping_query ( ) -> Self :: PingQuery ;
250
-
251
314
/// Check if a connection is still valid
252
315
///
253
- /// The default implementation performs a `SELECT 1` query
254
- async fn ping ( & mut self ) -> diesel:: QueryResult < ( ) >
316
+ /// The default implementation will perform a check based on the provided
317
+ /// recycling method variant
318
+ async fn ping ( & mut self , config : & RecyclingMethod < Self > ) -> diesel:: QueryResult < ( ) >
255
319
where
256
320
for < ' a > Self : ' a ,
321
+ diesel:: dsl:: BareSelect < diesel:: dsl:: AsExprOf < i32 , diesel:: sql_types:: Integer > > :
322
+ crate :: methods:: ExecuteDsl < Self > ,
323
+ diesel:: query_builder:: SqlQuery : crate :: methods:: ExecuteDsl < Self > ,
257
324
{
258
- use crate :: RunQueryDsl ;
259
- Self :: make_ping_query ( ) . execute ( self ) . await . map ( |_| ( ) )
325
+ use crate :: run_query_dsl:: RunQueryDsl ;
326
+ use diesel:: IntoSql ;
327
+
328
+ match config {
329
+ RecyclingMethod :: Fast => Ok ( ( ) ) ,
330
+ RecyclingMethod :: Verified => {
331
+ diesel:: select ( 1_i32 . into_sql :: < diesel:: sql_types:: Integer > ( ) )
332
+ . execute ( self )
333
+ . await
334
+ . map ( |_| ( ) )
335
+ }
336
+ RecyclingMethod :: CustomQuery ( query) => diesel:: sql_query ( query. as_ref ( ) )
337
+ . execute ( self )
338
+ . await
339
+ . map ( |_| ( ) ) ,
340
+ RecyclingMethod :: CustomFunction ( c) => c ( self ) . await ,
341
+ }
260
342
}
261
343
262
344
/// Checks if the connection is broken and should not be reused
0 commit comments