sea_orm/database/
mod.rs

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/// Defines a database
49#[derive(Debug, Default)]
50pub struct Database;
51
52/// Defines the configuration options of a database
53#[derive(derive_more::Debug, Clone)]
54pub struct ConnectOptions {
55    /// The URI of the database
56    pub(crate) url: String,
57    /// Maximum number of connections for a pool
58    pub(crate) max_connections: Option<u32>,
59    /// Minimum number of connections for a pool
60    pub(crate) min_connections: Option<u32>,
61    /// The connection timeout for a packet connection
62    pub(crate) connect_timeout: Option<Duration>,
63    /// Maximum idle time for a particular connection to prevent
64    /// network resource exhaustion
65    pub(crate) idle_timeout: Option<Duration>,
66    /// Set the maximum amount of time to spend waiting for acquiring a connection
67    pub(crate) acquire_timeout: Option<Duration>,
68    /// Set the maximum lifetime of individual connections
69    pub(crate) max_lifetime: Option<Duration>,
70    /// Enable SQLx statement logging
71    pub(crate) sqlx_logging: bool,
72    /// SQLx statement logging level (ignored if `sqlx_logging` is false)
73    pub(crate) sqlx_logging_level: log::LevelFilter,
74    /// SQLx slow statements logging level (ignored if `sqlx_logging` is false)
75    pub(crate) sqlx_slow_statements_logging_level: log::LevelFilter,
76    /// SQLx slow statements duration threshold (ignored if `sqlx_logging` is false)
77    pub(crate) sqlx_slow_statements_logging_threshold: Duration,
78    /// set sqlcipher key
79    pub(crate) sqlcipher_key: Option<Cow<'static, str>>,
80    /// Schema search path (PostgreSQL only)
81    pub(crate) schema_search_path: Option<String>,
82    pub(crate) test_before_acquire: bool,
83    /// Only establish connections to the DB as needed. If set to `true`, the db connection will
84    /// be created using SQLx's [connect_lazy](https://docs.rs/sqlx/latest/sqlx/struct.Pool.html#method.connect_lazy)
85    /// method.
86    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    /// Method to create a [DatabaseConnection] on a database. This method will return an error
102    /// if the database is not available.
103    #[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    /// Method to create a [DatabaseConnection] on a proxy database
141    #[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    /// Create new [ConnectOptions] for a [Database] by passing in a URI string
181    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    /// Get the database URL of the pool
211    pub fn get_url(&self) -> &str {
212        &self.url
213    }
214
215    /// Set the maximum number of connections of the pool
216    pub fn max_connections(&mut self, value: u32) -> &mut Self {
217        self.max_connections = Some(value);
218        self
219    }
220
221    /// Get the maximum number of connections of the pool, if set
222    pub fn get_max_connections(&self) -> Option<u32> {
223        self.max_connections
224    }
225
226    /// Set the minimum number of connections of the pool
227    pub fn min_connections(&mut self, value: u32) -> &mut Self {
228        self.min_connections = Some(value);
229        self
230    }
231
232    /// Get the minimum number of connections of the pool, if set
233    pub fn get_min_connections(&self) -> Option<u32> {
234        self.min_connections
235    }
236
237    /// Set the timeout duration when acquiring a connection
238    pub fn connect_timeout(&mut self, value: Duration) -> &mut Self {
239        self.connect_timeout = Some(value);
240        self
241    }
242
243    /// Get the timeout duration when acquiring a connection, if set
244    pub fn get_connect_timeout(&self) -> Option<Duration> {
245        self.connect_timeout
246    }
247
248    /// Set the idle duration before closing a connection
249    pub fn idle_timeout(&mut self, value: Duration) -> &mut Self {
250        self.idle_timeout = Some(value);
251        self
252    }
253
254    /// Get the idle duration before closing a connection, if set
255    pub fn get_idle_timeout(&self) -> Option<Duration> {
256        self.idle_timeout
257    }
258
259    /// Set the maximum amount of time to spend waiting for acquiring a connection
260    pub fn acquire_timeout(&mut self, value: Duration) -> &mut Self {
261        self.acquire_timeout = Some(value);
262        self
263    }
264
265    /// Get the maximum amount of time to spend waiting for acquiring a connection
266    pub fn get_acquire_timeout(&self) -> Option<Duration> {
267        self.acquire_timeout
268    }
269
270    /// Set the maximum lifetime of individual connections
271    pub fn max_lifetime(&mut self, lifetime: Duration) -> &mut Self {
272        self.max_lifetime = Some(lifetime);
273        self
274    }
275
276    /// Get the maximum lifetime of individual connections, if set
277    pub fn get_max_lifetime(&self) -> Option<Duration> {
278        self.max_lifetime
279    }
280
281    /// Enable SQLx statement logging (default true)
282    pub fn sqlx_logging(&mut self, value: bool) -> &mut Self {
283        self.sqlx_logging = value;
284        self
285    }
286
287    /// Get whether SQLx statement logging is enabled
288    pub fn get_sqlx_logging(&self) -> bool {
289        self.sqlx_logging
290    }
291
292    /// Set SQLx statement logging level (default INFO).
293    /// (ignored if `sqlx_logging` is `false`)
294    pub fn sqlx_logging_level(&mut self, level: log::LevelFilter) -> &mut Self {
295        self.sqlx_logging_level = level;
296        self
297    }
298
299    /// Set SQLx slow statements logging level and duration threshold (default `LevelFilter::Off`).
300    /// (ignored if `sqlx_logging` is `false`)
301    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    /// Get the level of SQLx statement logging
312    pub fn get_sqlx_logging_level(&self) -> log::LevelFilter {
313        self.sqlx_logging_level
314    }
315
316    /// Get the SQLx slow statements logging settings
317    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    /// set key for sqlcipher
325    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    /// Set schema search path (PostgreSQL only)
334    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    /// If true, the connection will be pinged upon acquiring from the pool (default true).
343    pub fn test_before_acquire(&mut self, value: bool) -> &mut Self {
344        self.test_before_acquire = value;
345        self
346    }
347
348    /// If set to `true`, the db connection pool will be created using SQLx's
349    /// [connect_lazy](https://docs.rs/sqlx/latest/sqlx/struct.Pool.html#method.connect_lazy) method.
350    pub fn connect_lazy(&mut self, value: bool) -> &mut Self {
351        self.connect_lazy = value;
352        self
353    }
354
355    /// Get whether DB connections will be established when the pool is created or only as needed.
356    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    /// Apply a function to modify the underlying [`MySqlConnectOptions`] before
363    /// creating the connection pool.
364    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    /// Apply a function to modify the underlying [`PgConnectOptions`] before
375    /// creating the connection pool.
376    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    /// Apply a function to modify the underlying [`SqliteConnectOptions`] before
387    /// creating the connection pool.
388    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}