sea_orm/driver/
sqlx_common.rs1use crate::{ConnAcquireErr, ConnectOptions, DbErr, RuntimeErr};
2use std::{sync::Arc, time::Duration};
3
4pub(crate) type BeforeAcquireFn<DB> = Arc<
12 dyn for<'c> Fn(
13 &'c mut <DB as sqlx::Database>::Connection,
14 sqlx::pool::PoolConnectionMetadata,
15 ) -> futures_util::future::BoxFuture<'c, Result<bool, sqlx::Error>>
16 + Send
17 + Sync,
18>;
19
20pub fn sqlx_error_to_exec_err(err: sqlx::Error) -> DbErr {
22 DbErr::Exec(RuntimeErr::SqlxError(err.into()))
23}
24
25pub fn sqlx_error_to_query_err(err: sqlx::Error) -> DbErr {
27 DbErr::Query(RuntimeErr::SqlxError(err.into()))
28}
29
30pub fn sqlx_error_to_conn_err(err: sqlx::Error) -> DbErr {
32 DbErr::Conn(RuntimeErr::SqlxError(err.into()))
33}
34
35pub fn sqlx_map_err_ignore_not_found<T: std::fmt::Debug>(
37 err: Result<Option<T>, sqlx::Error>,
38) -> Result<Option<T>, DbErr> {
39 if let Err(sqlx::Error::RowNotFound) = err {
40 Ok(None)
41 } else {
42 err.map_err(sqlx_error_to_query_err)
43 }
44}
45
46pub fn sqlx_conn_acquire_err(sqlx_err: sqlx::Error) -> DbErr {
48 match sqlx_err {
49 sqlx::Error::PoolTimedOut => DbErr::ConnectionAcquire(ConnAcquireErr::Timeout),
50 sqlx::Error::PoolClosed => DbErr::ConnectionAcquire(ConnAcquireErr::ConnectionClosed),
51 _ => DbErr::Conn(RuntimeErr::SqlxError(sqlx_err.into())),
52 }
53}
54
55impl ConnectOptions {
56 pub fn sqlx_pool_options<DB>(self) -> sqlx::pool::PoolOptions<DB>
58 where
59 DB: sqlx::Database,
60 {
61 let mut opt = sqlx::pool::PoolOptions::new();
62 if let Some(max_connections) = self.max_connections {
63 opt = opt.max_connections(max_connections);
64 }
65 if let Some(min_connections) = self.min_connections {
66 opt = opt.min_connections(min_connections);
67 }
68 if let Some(connect_timeout) = self.connect_timeout {
69 opt = opt.acquire_timeout(connect_timeout);
70 }
71 if let Some(idle_timeout) = self.idle_timeout {
72 opt = opt.idle_timeout(idle_timeout);
73 }
74 if let Some(acquire_timeout) = self.acquire_timeout {
75 opt = opt.acquire_timeout(acquire_timeout);
76 }
77 if let Some(max_lifetime) = self.max_lifetime {
78 opt = opt.max_lifetime(max_lifetime);
79 }
80 opt = opt.test_before_acquire(self.test_before_acquire);
81 opt
82 }
83
84 pub(crate) fn apply_before_acquire<DB>(
97 mut opt: sqlx::pool::PoolOptions<DB>,
98 ping_after_idle: Option<Duration>,
99 user_cb: Option<BeforeAcquireFn<DB>>,
100 ) -> sqlx::pool::PoolOptions<DB>
101 where
102 DB: sqlx::Database,
103 {
104 use sqlx::Connection;
105
106 if ping_after_idle.is_none() && user_cb.is_none() {
107 return opt;
108 }
109 if ping_after_idle.is_some() {
110 opt = opt.test_before_acquire(false);
111 }
112 opt.before_acquire(move |conn, meta| {
113 let user_cb = user_cb.clone();
114 Box::pin(async move {
115 if let Some(threshold) = ping_after_idle {
116 if meta.idle_for >= threshold {
120 conn.ping().await?;
121 }
122 }
123 match user_cb {
124 Some(user_cb) => user_cb(conn, meta).await,
125 None => Ok(true),
126 }
127 })
128 })
129 }
130}
131
132#[cfg(all(test, feature = "sqlx-postgres"))]
133mod tests {
134 use crate::ConnectOptions;
135 use sqlx::Connection;
136 use std::time::Duration;
137
138 #[test]
139 fn idle_shorthand_disables_test_before_acquire() {
140 let mut opt = ConnectOptions::new("postgres://localhost/db");
141 assert!(opt.get_test_before_acquire());
142 assert_eq!(opt.get_test_before_acquire_if_idle_for(), None);
143
144 opt.test_before_acquire_if_idle_for(Duration::from_secs(30));
145 assert!(!opt.get_test_before_acquire());
146 assert_eq!(
147 opt.get_test_before_acquire_if_idle_for(),
148 Some(Duration::from_secs(30))
149 );
150 }
151
152 #[test]
153 fn compose_shorthand_and_user_callback() {
154 let mut opt = ConnectOptions::new("postgres://localhost/db");
155 opt.test_before_acquire_if_idle_for(Duration::from_secs(30))
156 .map_sqlx_postgres_before_acquire(|conn, _meta| {
157 Box::pin(async move {
158 conn.ping().await?;
159 Ok(true)
160 })
161 });
162
163 let pool_opts = ConnectOptions::apply_before_acquire::<sqlx::Postgres>(
166 sqlx::pool::PoolOptions::new(),
167 opt.get_test_before_acquire_if_idle_for(),
168 opt.pg_before_acquire_fn.clone(),
169 );
170 let _ = pool_opts;
171 }
172
173 #[test]
174 fn apply_before_acquire_noop_when_unset() {
175 let opts = ConnectOptions::apply_before_acquire::<sqlx::Postgres>(
177 sqlx::pool::PoolOptions::new(),
178 None,
179 None,
180 );
181 let _ = opts;
182 }
183}