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