1#[cfg(any(
2 feature = "sqlx-mysql",
3 feature = "sqlx-postgres",
4 feature = "sqlx-sqlite",
5))]
6use std::sync::Arc;
7use std::time::Duration;
8
9#[cfg(feature = "sqlx-mysql")]
10use sqlx::mysql::MySqlConnectOptions;
11#[cfg(feature = "sqlx-postgres")]
12use sqlx::postgres::PgConnectOptions;
13#[cfg(feature = "sqlx-sqlite")]
14use sqlx::sqlite::SqliteConnectOptions;
15
16mod connection;
17mod db_connection;
18#[cfg(feature = "mock")]
19#[cfg_attr(docsrs, doc(cfg(feature = "mock")))]
20mod mock;
21#[cfg(feature = "proxy")]
22#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
23mod proxy;
24mod statement;
25mod stream;
26mod transaction;
27
28pub use connection::*;
29pub use db_connection::*;
30#[cfg(feature = "mock")]
31#[cfg_attr(docsrs, doc(cfg(feature = "mock")))]
32pub use mock::*;
33#[cfg(feature = "proxy")]
34#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
35pub use proxy::*;
36pub use statement::*;
37use std::borrow::Cow;
38pub use stream::*;
39use tracing::instrument;
40pub use transaction::*;
41
42use crate::error::*;
43
44#[derive(Debug, Default)]
46pub struct Database;
47
48#[derive(derive_more::Debug, Clone)]
50pub struct ConnectOptions {
51 pub(crate) url: String,
53 pub(crate) max_connections: Option<u32>,
55 pub(crate) min_connections: Option<u32>,
57 pub(crate) connect_timeout: Option<Duration>,
59 pub(crate) idle_timeout: Option<Duration>,
62 pub(crate) acquire_timeout: Option<Duration>,
64 pub(crate) max_lifetime: Option<Duration>,
66 pub(crate) sqlx_logging: bool,
68 pub(crate) sqlx_logging_level: log::LevelFilter,
70 pub(crate) sqlx_slow_statements_logging_level: log::LevelFilter,
72 pub(crate) sqlx_slow_statements_logging_threshold: Duration,
74 pub(crate) sqlcipher_key: Option<Cow<'static, str>>,
76 pub(crate) schema_search_path: Option<String>,
78 pub(crate) test_before_acquire: bool,
79 pub(crate) connect_lazy: bool,
83 #[cfg(feature = "sqlx-mysql")]
84 #[debug(skip)]
85 pub(crate) mysql_opts_fn:
86 Option<Arc<dyn Fn(MySqlConnectOptions) -> MySqlConnectOptions + Send + Sync>>,
87 #[cfg(feature = "sqlx-postgres")]
88 #[debug(skip)]
89 pub(crate) pg_opts_fn: Option<Arc<dyn Fn(PgConnectOptions) -> PgConnectOptions + Send + Sync>>,
90 #[cfg(feature = "sqlx-sqlite")]
91 #[debug(skip)]
92 pub(crate) sqlite_opts_fn:
93 Option<Arc<dyn Fn(SqliteConnectOptions) -> SqliteConnectOptions + Send + Sync>>,
94}
95
96impl Database {
97 #[instrument(level = "trace", skip(opt))]
100 pub async fn connect<C>(opt: C) -> Result<DatabaseConnection, DbErr>
101 where
102 C: Into<ConnectOptions>,
103 {
104 let opt: ConnectOptions = opt.into();
105
106 if url::Url::parse(&opt.url).is_err() {
107 return Err(conn_err(format!(
108 "The connection string '{}' cannot be parsed.",
109 opt.url
110 )));
111 }
112
113 #[cfg(feature = "sqlx-mysql")]
114 if DbBackend::MySql.is_prefix_of(&opt.url) {
115 return crate::SqlxMySqlConnector::connect(opt).await;
116 }
117 #[cfg(feature = "sqlx-postgres")]
118 if DbBackend::Postgres.is_prefix_of(&opt.url) {
119 return crate::SqlxPostgresConnector::connect(opt).await;
120 }
121 #[cfg(feature = "sqlx-sqlite")]
122 if DbBackend::Sqlite.is_prefix_of(&opt.url) {
123 return crate::SqlxSqliteConnector::connect(opt).await;
124 }
125 #[cfg(feature = "mock")]
126 if crate::MockDatabaseConnector::accepts(&opt.url) {
127 return crate::MockDatabaseConnector::connect(&opt.url).await;
128 }
129
130 Err(conn_err(format!(
131 "The connection string '{}' has no supporting driver.",
132 opt.url
133 )))
134 }
135
136 #[cfg(feature = "proxy")]
138 #[instrument(level = "trace", skip(proxy_func_arc))]
139 pub async fn connect_proxy(
140 db_type: DbBackend,
141 proxy_func_arc: std::sync::Arc<Box<dyn ProxyDatabaseTrait>>,
142 ) -> Result<DatabaseConnection, DbErr> {
143 match db_type {
144 DbBackend::MySql => {
145 return crate::ProxyDatabaseConnector::connect(
146 DbBackend::MySql,
147 proxy_func_arc.to_owned(),
148 );
149 }
150 DbBackend::Postgres => {
151 return crate::ProxyDatabaseConnector::connect(
152 DbBackend::Postgres,
153 proxy_func_arc.to_owned(),
154 );
155 }
156 DbBackend::Sqlite => {
157 return crate::ProxyDatabaseConnector::connect(
158 DbBackend::Sqlite,
159 proxy_func_arc.to_owned(),
160 );
161 }
162 }
163 }
164}
165
166impl<T> From<T> for ConnectOptions
167where
168 T: Into<String>,
169{
170 fn from(s: T) -> ConnectOptions {
171 ConnectOptions::new(s.into())
172 }
173}
174
175impl ConnectOptions {
176 pub fn new<T>(url: T) -> Self
178 where
179 T: Into<String>,
180 {
181 Self {
182 url: url.into(),
183 max_connections: None,
184 min_connections: None,
185 connect_timeout: None,
186 idle_timeout: None,
187 acquire_timeout: None,
188 max_lifetime: None,
189 sqlx_logging: true,
190 sqlx_logging_level: log::LevelFilter::Info,
191 sqlx_slow_statements_logging_level: log::LevelFilter::Off,
192 sqlx_slow_statements_logging_threshold: Duration::from_secs(1),
193 sqlcipher_key: None,
194 schema_search_path: None,
195 test_before_acquire: true,
196 connect_lazy: false,
197 #[cfg(feature = "sqlx-mysql")]
198 mysql_opts_fn: None,
199 #[cfg(feature = "sqlx-postgres")]
200 pg_opts_fn: None,
201 #[cfg(feature = "sqlx-sqlite")]
202 sqlite_opts_fn: None,
203 }
204 }
205
206 pub fn get_url(&self) -> &str {
208 &self.url
209 }
210
211 pub fn max_connections(&mut self, value: u32) -> &mut Self {
213 self.max_connections = Some(value);
214 self
215 }
216
217 pub fn get_max_connections(&self) -> Option<u32> {
219 self.max_connections
220 }
221
222 pub fn min_connections(&mut self, value: u32) -> &mut Self {
224 self.min_connections = Some(value);
225 self
226 }
227
228 pub fn get_min_connections(&self) -> Option<u32> {
230 self.min_connections
231 }
232
233 pub fn connect_timeout(&mut self, value: Duration) -> &mut Self {
235 self.connect_timeout = Some(value);
236 self
237 }
238
239 pub fn get_connect_timeout(&self) -> Option<Duration> {
241 self.connect_timeout
242 }
243
244 pub fn idle_timeout(&mut self, value: Duration) -> &mut Self {
246 self.idle_timeout = Some(value);
247 self
248 }
249
250 pub fn get_idle_timeout(&self) -> Option<Duration> {
252 self.idle_timeout
253 }
254
255 pub fn acquire_timeout(&mut self, value: Duration) -> &mut Self {
257 self.acquire_timeout = Some(value);
258 self
259 }
260
261 pub fn get_acquire_timeout(&self) -> Option<Duration> {
263 self.acquire_timeout
264 }
265
266 pub fn max_lifetime(&mut self, lifetime: Duration) -> &mut Self {
268 self.max_lifetime = Some(lifetime);
269 self
270 }
271
272 pub fn get_max_lifetime(&self) -> Option<Duration> {
274 self.max_lifetime
275 }
276
277 pub fn sqlx_logging(&mut self, value: bool) -> &mut Self {
279 self.sqlx_logging = value;
280 self
281 }
282
283 pub fn get_sqlx_logging(&self) -> bool {
285 self.sqlx_logging
286 }
287
288 pub fn sqlx_logging_level(&mut self, level: log::LevelFilter) -> &mut Self {
291 self.sqlx_logging_level = level;
292 self
293 }
294
295 pub fn sqlx_slow_statements_logging_settings(
298 &mut self,
299 level: log::LevelFilter,
300 duration: Duration,
301 ) -> &mut Self {
302 self.sqlx_slow_statements_logging_level = level;
303 self.sqlx_slow_statements_logging_threshold = duration;
304 self
305 }
306
307 pub fn get_sqlx_logging_level(&self) -> log::LevelFilter {
309 self.sqlx_logging_level
310 }
311
312 pub fn get_sqlx_slow_statements_logging_settings(&self) -> (log::LevelFilter, Duration) {
314 (
315 self.sqlx_slow_statements_logging_level,
316 self.sqlx_slow_statements_logging_threshold,
317 )
318 }
319
320 pub fn sqlcipher_key<T>(&mut self, value: T) -> &mut Self
322 where
323 T: Into<Cow<'static, str>>,
324 {
325 self.sqlcipher_key = Some(value.into());
326 self
327 }
328
329 pub fn set_schema_search_path<T>(&mut self, schema_search_path: T) -> &mut Self
331 where
332 T: Into<String>,
333 {
334 self.schema_search_path = Some(schema_search_path.into());
335 self
336 }
337
338 pub fn test_before_acquire(&mut self, value: bool) -> &mut Self {
340 self.test_before_acquire = value;
341 self
342 }
343
344 pub fn connect_lazy(&mut self, value: bool) -> &mut Self {
347 self.connect_lazy = value;
348 self
349 }
350
351 pub fn get_connect_lazy(&self) -> bool {
353 self.connect_lazy
354 }
355
356 #[cfg(feature = "sqlx-mysql")]
357 #[cfg_attr(docsrs, doc(cfg(feature = "sqlx-mysql")))]
358 pub fn map_sqlx_mysql_opts<F>(&mut self, f: F) -> &mut Self
361 where
362 F: Fn(MySqlConnectOptions) -> MySqlConnectOptions + Send + Sync + 'static,
363 {
364 self.mysql_opts_fn = Some(Arc::new(f));
365 self
366 }
367
368 #[cfg(feature = "sqlx-postgres")]
369 #[cfg_attr(docsrs, doc(cfg(feature = "sqlx-postgres")))]
370 pub fn map_sqlx_postgres_opts<F>(&mut self, f: F) -> &mut Self
373 where
374 F: Fn(PgConnectOptions) -> PgConnectOptions + Send + Sync + 'static,
375 {
376 self.pg_opts_fn = Some(Arc::new(f));
377 self
378 }
379
380 #[cfg(feature = "sqlx-sqlite")]
381 #[cfg_attr(docsrs, doc(cfg(feature = "sqlx-sqlite")))]
382 pub fn map_sqlx_sqlite_opts<F>(&mut self, f: F) -> &mut Self
385 where
386 F: Fn(SqliteConnectOptions) -> SqliteConnectOptions + Send + Sync + 'static,
387 {
388 self.sqlite_opts_fn = Some(Arc::new(f));
389 self
390 }
391}