sea_orm/database/
mod.rs

1use std::time::Duration;
2
3mod connection;
4mod db_connection;
5#[cfg(feature = "mock")]
6#[cfg_attr(docsrs, doc(cfg(feature = "mock")))]
7mod mock;
8#[cfg(feature = "proxy")]
9#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
10mod proxy;
11mod statement;
12mod stream;
13mod transaction;
14
15pub use connection::*;
16pub use db_connection::*;
17#[cfg(feature = "mock")]
18#[cfg_attr(docsrs, doc(cfg(feature = "mock")))]
19pub use mock::*;
20#[cfg(feature = "proxy")]
21#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
22pub use proxy::*;
23pub use statement::*;
24use std::borrow::Cow;
25pub use stream::*;
26use tracing::instrument;
27pub use transaction::*;
28
29use crate::error::*;
30
31/// Defines a database
32#[derive(Debug, Default)]
33pub struct Database;
34
35/// Defines the configuration options of a database
36#[derive(Debug, Clone)]
37pub struct ConnectOptions {
38    /// The URI of the database
39    pub(crate) url: String,
40    /// Maximum number of connections for a pool
41    pub(crate) max_connections: Option<u32>,
42    /// Minimum number of connections for a pool
43    pub(crate) min_connections: Option<u32>,
44    /// The connection timeout for a packet connection
45    pub(crate) connect_timeout: Option<Duration>,
46    /// Maximum idle time for a particular connection to prevent
47    /// network resource exhaustion
48    pub(crate) idle_timeout: Option<Duration>,
49    /// Set the maximum amount of time to spend waiting for acquiring a connection
50    pub(crate) acquire_timeout: Option<Duration>,
51    /// Set the maximum lifetime of individual connections
52    pub(crate) max_lifetime: Option<Duration>,
53    /// Enable SQLx statement logging
54    pub(crate) sqlx_logging: bool,
55    /// SQLx statement logging level (ignored if `sqlx_logging` is false)
56    pub(crate) sqlx_logging_level: log::LevelFilter,
57    /// SQLx slow statements logging level (ignored if `sqlx_logging` is false)
58    pub(crate) sqlx_slow_statements_logging_level: log::LevelFilter,
59    /// SQLx slow statements duration threshold (ignored if `sqlx_logging` is false)
60    pub(crate) sqlx_slow_statements_logging_threshold: Duration,
61    /// set sqlcipher key
62    pub(crate) sqlcipher_key: Option<Cow<'static, str>>,
63    /// Schema search path (PostgreSQL only)
64    pub(crate) schema_search_path: Option<String>,
65    pub(crate) test_before_acquire: bool,
66    /// Only establish connections to the DB as needed. If set to `true`, the db connection will
67    /// be created using SQLx's [connect_lazy](https://docs.rs/sqlx/latest/sqlx/struct.Pool.html#method.connect_lazy)
68    /// method.
69    pub(crate) connect_lazy: bool,
70}
71
72impl Database {
73    /// Method to create a [DatabaseConnection] on a database. This method will return an error
74    /// if the database is not available.
75    #[instrument(level = "trace", skip(opt))]
76    pub async fn connect<C>(opt: C) -> Result<DatabaseConnection, DbErr>
77    where
78        C: Into<ConnectOptions>,
79    {
80        let opt: ConnectOptions = opt.into();
81
82        if url::Url::parse(&opt.url).is_err() {
83            return Err(conn_err(format!(
84                "The connection string '{}' cannot be parsed.",
85                opt.url
86            )));
87        }
88
89        #[cfg(feature = "sqlx-mysql")]
90        if DbBackend::MySql.is_prefix_of(&opt.url) {
91            return crate::SqlxMySqlConnector::connect(opt).await;
92        }
93        #[cfg(feature = "sqlx-postgres")]
94        if DbBackend::Postgres.is_prefix_of(&opt.url) {
95            return crate::SqlxPostgresConnector::connect(opt).await;
96        }
97        #[cfg(feature = "sqlx-sqlite")]
98        if DbBackend::Sqlite.is_prefix_of(&opt.url) {
99            return crate::SqlxSqliteConnector::connect(opt).await;
100        }
101        #[cfg(feature = "mock")]
102        if crate::MockDatabaseConnector::accepts(&opt.url) {
103            return crate::MockDatabaseConnector::connect(&opt.url).await;
104        }
105
106        Err(conn_err(format!(
107            "The connection string '{}' has no supporting driver.",
108            opt.url
109        )))
110    }
111
112    /// Method to create a [DatabaseConnection] on a proxy database
113    #[cfg(feature = "proxy")]
114    #[instrument(level = "trace", skip(proxy_func_arc))]
115    pub async fn connect_proxy(
116        db_type: DbBackend,
117        proxy_func_arc: std::sync::Arc<Box<dyn ProxyDatabaseTrait>>,
118    ) -> Result<DatabaseConnection, DbErr> {
119        match db_type {
120            DbBackend::MySql => {
121                return crate::ProxyDatabaseConnector::connect(
122                    DbBackend::MySql,
123                    proxy_func_arc.to_owned(),
124                );
125            }
126            DbBackend::Postgres => {
127                return crate::ProxyDatabaseConnector::connect(
128                    DbBackend::Postgres,
129                    proxy_func_arc.to_owned(),
130                );
131            }
132            DbBackend::Sqlite => {
133                return crate::ProxyDatabaseConnector::connect(
134                    DbBackend::Sqlite,
135                    proxy_func_arc.to_owned(),
136                );
137            }
138        }
139    }
140}
141
142impl<T> From<T> for ConnectOptions
143where
144    T: Into<String>,
145{
146    fn from(s: T) -> ConnectOptions {
147        ConnectOptions::new(s.into())
148    }
149}
150
151impl ConnectOptions {
152    /// Create new [ConnectOptions] for a [Database] by passing in a URI string
153    pub fn new<T>(url: T) -> Self
154    where
155        T: Into<String>,
156    {
157        Self {
158            url: url.into(),
159            max_connections: None,
160            min_connections: None,
161            connect_timeout: None,
162            idle_timeout: None,
163            acquire_timeout: None,
164            max_lifetime: None,
165            sqlx_logging: true,
166            sqlx_logging_level: log::LevelFilter::Info,
167            sqlx_slow_statements_logging_level: log::LevelFilter::Off,
168            sqlx_slow_statements_logging_threshold: Duration::from_secs(1),
169            sqlcipher_key: None,
170            schema_search_path: None,
171            test_before_acquire: true,
172            connect_lazy: false,
173        }
174    }
175
176    /// Get the database URL of the pool
177    pub fn get_url(&self) -> &str {
178        &self.url
179    }
180
181    /// Set the maximum number of connections of the pool
182    pub fn max_connections(&mut self, value: u32) -> &mut Self {
183        self.max_connections = Some(value);
184        self
185    }
186
187    /// Get the maximum number of connections of the pool, if set
188    pub fn get_max_connections(&self) -> Option<u32> {
189        self.max_connections
190    }
191
192    /// Set the minimum number of connections of the pool
193    pub fn min_connections(&mut self, value: u32) -> &mut Self {
194        self.min_connections = Some(value);
195        self
196    }
197
198    /// Get the minimum number of connections of the pool, if set
199    pub fn get_min_connections(&self) -> Option<u32> {
200        self.min_connections
201    }
202
203    /// Set the timeout duration when acquiring a connection
204    pub fn connect_timeout(&mut self, value: Duration) -> &mut Self {
205        self.connect_timeout = Some(value);
206        self
207    }
208
209    /// Get the timeout duration when acquiring a connection, if set
210    pub fn get_connect_timeout(&self) -> Option<Duration> {
211        self.connect_timeout
212    }
213
214    /// Set the idle duration before closing a connection
215    pub fn idle_timeout(&mut self, value: Duration) -> &mut Self {
216        self.idle_timeout = Some(value);
217        self
218    }
219
220    /// Get the idle duration before closing a connection, if set
221    pub fn get_idle_timeout(&self) -> Option<Duration> {
222        self.idle_timeout
223    }
224
225    /// Set the maximum amount of time to spend waiting for acquiring a connection
226    pub fn acquire_timeout(&mut self, value: Duration) -> &mut Self {
227        self.acquire_timeout = Some(value);
228        self
229    }
230
231    /// Get the maximum amount of time to spend waiting for acquiring a connection
232    pub fn get_acquire_timeout(&self) -> Option<Duration> {
233        self.acquire_timeout
234    }
235
236    /// Set the maximum lifetime of individual connections
237    pub fn max_lifetime(&mut self, lifetime: Duration) -> &mut Self {
238        self.max_lifetime = Some(lifetime);
239        self
240    }
241
242    /// Get the maximum lifetime of individual connections, if set
243    pub fn get_max_lifetime(&self) -> Option<Duration> {
244        self.max_lifetime
245    }
246
247    /// Enable SQLx statement logging (default true)
248    pub fn sqlx_logging(&mut self, value: bool) -> &mut Self {
249        self.sqlx_logging = value;
250        self
251    }
252
253    /// Get whether SQLx statement logging is enabled
254    pub fn get_sqlx_logging(&self) -> bool {
255        self.sqlx_logging
256    }
257
258    /// Set SQLx statement logging level (default INFO).
259    /// (ignored if `sqlx_logging` is `false`)
260    pub fn sqlx_logging_level(&mut self, level: log::LevelFilter) -> &mut Self {
261        self.sqlx_logging_level = level;
262        self
263    }
264
265    /// Set SQLx slow statements logging level and duration threshold (default `LevelFilter::Off`).
266    /// (ignored if `sqlx_logging` is `false`)
267    pub fn sqlx_slow_statements_logging_settings(
268        &mut self,
269        level: log::LevelFilter,
270        duration: Duration,
271    ) -> &mut Self {
272        self.sqlx_slow_statements_logging_level = level;
273        self.sqlx_slow_statements_logging_threshold = duration;
274        self
275    }
276
277    /// Get the level of SQLx statement logging
278    pub fn get_sqlx_logging_level(&self) -> log::LevelFilter {
279        self.sqlx_logging_level
280    }
281
282    /// Get the SQLx slow statements logging settings
283    pub fn get_sqlx_slow_statements_logging_settings(&self) -> (log::LevelFilter, Duration) {
284        (
285            self.sqlx_slow_statements_logging_level,
286            self.sqlx_slow_statements_logging_threshold,
287        )
288    }
289
290    /// set key for sqlcipher
291    pub fn sqlcipher_key<T>(&mut self, value: T) -> &mut Self
292    where
293        T: Into<Cow<'static, str>>,
294    {
295        self.sqlcipher_key = Some(value.into());
296        self
297    }
298
299    /// Set schema search path (PostgreSQL only)
300    pub fn set_schema_search_path<T>(&mut self, schema_search_path: T) -> &mut Self
301    where
302        T: Into<String>,
303    {
304        self.schema_search_path = Some(schema_search_path.into());
305        self
306    }
307
308    /// If true, the connection will be pinged upon acquiring from the pool (default true).
309    pub fn test_before_acquire(&mut self, value: bool) -> &mut Self {
310        self.test_before_acquire = value;
311        self
312    }
313
314    /// If set to `true`, the db connection pool will be created using SQLx's
315    /// [connect_lazy](https://docs.rs/sqlx/latest/sqlx/struct.Pool.html#method.connect_lazy) method.
316    pub fn connect_lazy(&mut self, value: bool) -> &mut Self {
317        self.connect_lazy = value;
318        self
319    }
320
321    /// Get whether DB connections will be established when the pool is created or only as needed.
322    pub fn get_connect_lazy(&self) -> bool {
323        self.connect_lazy
324    }
325}