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;
24#[cfg(feature = "rbac")]
25mod restricted_connection;
26mod statement;
27mod stream;
28mod transaction;
29
30pub use connection::*;
31pub use db_connection::*;
32#[cfg(feature = "mock")]
33#[cfg_attr(docsrs, doc(cfg(feature = "mock")))]
34pub use mock::*;
35#[cfg(feature = "proxy")]
36#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
37pub use proxy::*;
38#[cfg(feature = "rbac")]
39pub use restricted_connection::*;
40pub use statement::*;
41use std::borrow::Cow;
42pub use stream::*;
43use tracing::instrument;
44pub use transaction::*;
45
46use crate::error::*;
47
48#[derive(Debug, Default)]
50pub struct Database;
51
52#[derive(derive_more::Debug, Clone)]
54pub struct ConnectOptions {
55 pub(crate) url: String,
57 pub(crate) max_connections: Option<u32>,
59 pub(crate) min_connections: Option<u32>,
61 pub(crate) connect_timeout: Option<Duration>,
63 pub(crate) idle_timeout: Option<Duration>,
66 pub(crate) acquire_timeout: Option<Duration>,
68 pub(crate) max_lifetime: Option<Duration>,
70 pub(crate) sqlx_logging: bool,
72 pub(crate) sqlx_logging_level: log::LevelFilter,
74 pub(crate) sqlx_slow_statements_logging_level: log::LevelFilter,
76 pub(crate) sqlx_slow_statements_logging_threshold: Duration,
78 pub(crate) sqlcipher_key: Option<Cow<'static, str>>,
80 pub(crate) schema_search_path: Option<String>,
82 pub(crate) test_before_acquire: bool,
83 pub(crate) connect_lazy: bool,
87 #[cfg(feature = "sqlx-mysql")]
88 #[debug(skip)]
89 pub(crate) mysql_opts_fn:
90 Option<Arc<dyn Fn(MySqlConnectOptions) -> MySqlConnectOptions + Send + Sync>>,
91 #[cfg(feature = "sqlx-postgres")]
92 #[debug(skip)]
93 pub(crate) pg_opts_fn: Option<Arc<dyn Fn(PgConnectOptions) -> PgConnectOptions + Send + Sync>>,
94 #[cfg(feature = "sqlx-sqlite")]
95 #[debug(skip)]
96 pub(crate) sqlite_opts_fn:
97 Option<Arc<dyn Fn(SqliteConnectOptions) -> SqliteConnectOptions + Send + Sync>>,
98}
99
100impl Database {
101 #[instrument(level = "trace", skip(opt))]
104 pub async fn connect<C>(opt: C) -> Result<DatabaseConnection, DbErr>
105 where
106 C: Into<ConnectOptions>,
107 {
108 let opt: ConnectOptions = opt.into();
109
110 if url::Url::parse(&opt.url).is_err() {
111 return Err(conn_err(format!(
112 "The connection string '{}' cannot be parsed.",
113 opt.url
114 )));
115 }
116
117 #[cfg(feature = "sqlx-mysql")]
118 if DbBackend::MySql.is_prefix_of(&opt.url) {
119 return crate::SqlxMySqlConnector::connect(opt).await;
120 }
121 #[cfg(feature = "sqlx-postgres")]
122 if DbBackend::Postgres.is_prefix_of(&opt.url) {
123 return crate::SqlxPostgresConnector::connect(opt).await;
124 }
125 #[cfg(feature = "sqlx-sqlite")]
126 if DbBackend::Sqlite.is_prefix_of(&opt.url) {
127 return crate::SqlxSqliteConnector::connect(opt).await;
128 }
129 #[cfg(feature = "mock")]
130 if crate::MockDatabaseConnector::accepts(&opt.url) {
131 return crate::MockDatabaseConnector::connect(&opt.url).await;
132 }
133
134 Err(conn_err(format!(
135 "The connection string '{}' has no supporting driver.",
136 opt.url
137 )))
138 }
139
140 #[cfg(feature = "proxy")]
142 #[instrument(level = "trace", skip(proxy_func_arc))]
143 pub async fn connect_proxy(
144 db_type: DbBackend,
145 proxy_func_arc: std::sync::Arc<Box<dyn ProxyDatabaseTrait>>,
146 ) -> Result<DatabaseConnection, DbErr> {
147 match db_type {
148 DbBackend::MySql => {
149 return crate::ProxyDatabaseConnector::connect(
150 DbBackend::MySql,
151 proxy_func_arc.to_owned(),
152 );
153 }
154 DbBackend::Postgres => {
155 return crate::ProxyDatabaseConnector::connect(
156 DbBackend::Postgres,
157 proxy_func_arc.to_owned(),
158 );
159 }
160 DbBackend::Sqlite => {
161 return crate::ProxyDatabaseConnector::connect(
162 DbBackend::Sqlite,
163 proxy_func_arc.to_owned(),
164 );
165 }
166 }
167 }
168}
169
170impl<T> From<T> for ConnectOptions
171where
172 T: Into<String>,
173{
174 fn from(s: T) -> ConnectOptions {
175 ConnectOptions::new(s.into())
176 }
177}
178
179impl ConnectOptions {
180 pub fn new<T>(url: T) -> Self
182 where
183 T: Into<String>,
184 {
185 Self {
186 url: url.into(),
187 max_connections: None,
188 min_connections: None,
189 connect_timeout: None,
190 idle_timeout: None,
191 acquire_timeout: None,
192 max_lifetime: None,
193 sqlx_logging: true,
194 sqlx_logging_level: log::LevelFilter::Info,
195 sqlx_slow_statements_logging_level: log::LevelFilter::Off,
196 sqlx_slow_statements_logging_threshold: Duration::from_secs(1),
197 sqlcipher_key: None,
198 schema_search_path: None,
199 test_before_acquire: true,
200 connect_lazy: false,
201 #[cfg(feature = "sqlx-mysql")]
202 mysql_opts_fn: None,
203 #[cfg(feature = "sqlx-postgres")]
204 pg_opts_fn: None,
205 #[cfg(feature = "sqlx-sqlite")]
206 sqlite_opts_fn: None,
207 }
208 }
209
210 pub fn get_url(&self) -> &str {
212 &self.url
213 }
214
215 pub fn max_connections(&mut self, value: u32) -> &mut Self {
217 self.max_connections = Some(value);
218 self
219 }
220
221 pub fn get_max_connections(&self) -> Option<u32> {
223 self.max_connections
224 }
225
226 pub fn min_connections(&mut self, value: u32) -> &mut Self {
228 self.min_connections = Some(value);
229 self
230 }
231
232 pub fn get_min_connections(&self) -> Option<u32> {
234 self.min_connections
235 }
236
237 pub fn connect_timeout(&mut self, value: Duration) -> &mut Self {
239 self.connect_timeout = Some(value);
240 self
241 }
242
243 pub fn get_connect_timeout(&self) -> Option<Duration> {
245 self.connect_timeout
246 }
247
248 pub fn idle_timeout(&mut self, value: Duration) -> &mut Self {
250 self.idle_timeout = Some(value);
251 self
252 }
253
254 pub fn get_idle_timeout(&self) -> Option<Duration> {
256 self.idle_timeout
257 }
258
259 pub fn acquire_timeout(&mut self, value: Duration) -> &mut Self {
261 self.acquire_timeout = Some(value);
262 self
263 }
264
265 pub fn get_acquire_timeout(&self) -> Option<Duration> {
267 self.acquire_timeout
268 }
269
270 pub fn max_lifetime(&mut self, lifetime: Duration) -> &mut Self {
272 self.max_lifetime = Some(lifetime);
273 self
274 }
275
276 pub fn get_max_lifetime(&self) -> Option<Duration> {
278 self.max_lifetime
279 }
280
281 pub fn sqlx_logging(&mut self, value: bool) -> &mut Self {
283 self.sqlx_logging = value;
284 self
285 }
286
287 pub fn get_sqlx_logging(&self) -> bool {
289 self.sqlx_logging
290 }
291
292 pub fn sqlx_logging_level(&mut self, level: log::LevelFilter) -> &mut Self {
295 self.sqlx_logging_level = level;
296 self
297 }
298
299 pub fn sqlx_slow_statements_logging_settings(
302 &mut self,
303 level: log::LevelFilter,
304 duration: Duration,
305 ) -> &mut Self {
306 self.sqlx_slow_statements_logging_level = level;
307 self.sqlx_slow_statements_logging_threshold = duration;
308 self
309 }
310
311 pub fn get_sqlx_logging_level(&self) -> log::LevelFilter {
313 self.sqlx_logging_level
314 }
315
316 pub fn get_sqlx_slow_statements_logging_settings(&self) -> (log::LevelFilter, Duration) {
318 (
319 self.sqlx_slow_statements_logging_level,
320 self.sqlx_slow_statements_logging_threshold,
321 )
322 }
323
324 pub fn sqlcipher_key<T>(&mut self, value: T) -> &mut Self
326 where
327 T: Into<Cow<'static, str>>,
328 {
329 self.sqlcipher_key = Some(value.into());
330 self
331 }
332
333 pub fn set_schema_search_path<T>(&mut self, schema_search_path: T) -> &mut Self
335 where
336 T: Into<String>,
337 {
338 self.schema_search_path = Some(schema_search_path.into());
339 self
340 }
341
342 pub fn test_before_acquire(&mut self, value: bool) -> &mut Self {
344 self.test_before_acquire = value;
345 self
346 }
347
348 pub fn connect_lazy(&mut self, value: bool) -> &mut Self {
351 self.connect_lazy = value;
352 self
353 }
354
355 pub fn get_connect_lazy(&self) -> bool {
357 self.connect_lazy
358 }
359
360 #[cfg(feature = "sqlx-mysql")]
361 #[cfg_attr(docsrs, doc(cfg(feature = "sqlx-mysql")))]
362 pub fn map_sqlx_mysql_opts<F>(&mut self, f: F) -> &mut Self
365 where
366 F: Fn(MySqlConnectOptions) -> MySqlConnectOptions + Send + Sync + 'static,
367 {
368 self.mysql_opts_fn = Some(Arc::new(f));
369 self
370 }
371
372 #[cfg(feature = "sqlx-postgres")]
373 #[cfg_attr(docsrs, doc(cfg(feature = "sqlx-postgres")))]
374 pub fn map_sqlx_postgres_opts<F>(&mut self, f: F) -> &mut Self
377 where
378 F: Fn(PgConnectOptions) -> PgConnectOptions + Send + Sync + 'static,
379 {
380 self.pg_opts_fn = Some(Arc::new(f));
381 self
382 }
383
384 #[cfg(feature = "sqlx-sqlite")]
385 #[cfg_attr(docsrs, doc(cfg(feature = "sqlx-sqlite")))]
386 pub fn map_sqlx_sqlite_opts<F>(&mut self, f: F) -> &mut Self
389 where
390 F: Fn(SqliteConnectOptions) -> SqliteConnectOptions + Send + Sync + 'static,
391 {
392 self.sqlite_opts_fn = Some(Arc::new(f));
393 self
394 }
395}