88use crate :: { AsyncConnection , SimpleAsyncConnection } ;
99use crate :: { TransactionManager , UpdateAndFetchResults } ;
1010use diesel:: associations:: HasTable ;
11- use diesel:: query_builder:: { QueryFragment , QueryId } ;
1211use diesel:: QueryResult ;
1312use futures_util:: { future, FutureExt } ;
13+ use std:: borrow:: Cow ;
1414use std:: fmt;
1515use std:: ops:: DerefMut ;
1616
@@ -42,18 +42,83 @@ impl fmt::Display for PoolError {
4242
4343impl std:: error:: Error for PoolError { }
4444
45- type SetupCallback < C > =
45+ /// Type of the custom setup closure passed to [`ManagerConfig::custom_setup`]
46+ pub type SetupCallback < C > =
4647 Box < dyn Fn ( & str ) -> future:: BoxFuture < diesel:: ConnectionResult < C > > + Send + Sync > ;
4748
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+
48113/// An connection manager for use with diesel-async.
49114///
50115/// See the concrete pool implementations for examples:
51116/// * [deadpool](self::deadpool)
52117/// * [bb8](self::bb8)
53118/// * [mobc](self::mobc)
54119pub struct AsyncDieselConnectionManager < C > {
55- setup : SetupCallback < C > ,
56120 connection_url : String ,
121+ manager_config : ManagerConfig < C > ,
57122}
58123
59124impl < C > fmt:: Debug for AsyncDieselConnectionManager < C > {
@@ -66,28 +131,31 @@ impl<C> fmt::Debug for AsyncDieselConnectionManager<C> {
66131 }
67132}
68133
69- impl < C > AsyncDieselConnectionManager < C > {
134+ impl < C > AsyncDieselConnectionManager < C >
135+ where
136+ C : AsyncConnection + ' static ,
137+ {
70138 /// Returns a new connection manager,
71139 /// which establishes connections to the given database URL.
140+ #[ must_use]
72141 pub fn new ( connection_url : impl Into < String > ) -> Self
73142 where
74143 C : AsyncConnection + ' static ,
75144 {
76- Self :: new_with_setup ( connection_url, |url| C :: establish ( url ) . boxed ( ) )
145+ Self :: new_with_config ( connection_url, Default :: default ( ) )
77146 }
78147
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 (
85153 connection_url : impl Into < String > ,
86- setup : impl Fn ( & str ) -> future :: BoxFuture < diesel :: ConnectionResult < C > > + Send + Sync + ' static ,
154+ manager_config : ManagerConfig < C > ,
87155 ) -> Self {
88156 Self {
89- setup : Box :: new ( setup) ,
90157 connection_url : connection_url. into ( ) ,
158+ manager_config,
91159 }
92160 }
93161}
@@ -218,9 +286,8 @@ where
218286 }
219287}
220288
221- #[ doc( hidden) ]
222289#[ derive( diesel:: query_builder:: QueryId ) ]
223- pub struct CheckConnectionQuery ;
290+ struct CheckConnectionQuery ;
224291
225292impl < DB > diesel:: query_builder:: QueryFragment < DB > for CheckConnectionQuery
226293where
@@ -244,19 +311,34 @@ impl<C> diesel::query_dsl::RunQueryDsl<C> for CheckConnectionQuery {}
244311#[ doc( hidden) ]
245312#[ async_trait:: async_trait]
246313pub trait PoolableConnection : AsyncConnection {
247- type PingQuery : QueryFragment < Self :: Backend > + QueryId + Send ;
248-
249- fn make_ping_query ( ) -> Self :: PingQuery ;
250-
251314 /// Check if a connection is still valid
252315 ///
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 < ( ) >
255319 where
256320 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 > ,
257324 {
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+ }
260342 }
261343
262344 /// Checks if the connection is broken and should not be reused
0 commit comments