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