sqlx_core/config/
drivers.rs

1use std::error::Error;
2
3/// Configuration for specific database drivers (**applies to macros and `sqlx-cli` only**).
4///
5/// # Note: Does Not Apply at Application Run-Time
6/// As of writing, these configuration parameters do *not* have any bearing on
7/// the runtime configuration of SQLx database drivers.
8///
9/// Any parameters which overlap with runtime configuration
10/// (e.g. [`drivers.sqlite.unsafe-load-extensions`][SqliteConfig::unsafe_load_extensions])
11/// _must_ be configured their normal ways at runtime (e.g. `SqliteConnectOptions::extension()`).
12///
13/// See the documentation of individual fields for details.
14#[derive(Debug, Default)]
15#[cfg_attr(
16    feature = "sqlx-toml",
17    derive(serde::Deserialize),
18    serde(default, rename_all = "kebab-case", deny_unknown_fields)
19)]
20pub struct Config {
21    /// Configuration for the MySQL database driver.
22    ///
23    /// See [`MySqlConfig`] for details.
24    pub mysql: MySqlConfig,
25
26    /// Configuration for the Postgres database driver.
27    ///
28    /// See [`PgConfig`] for details.
29    pub postgres: PgConfig,
30
31    /// Configuration for the SQLite database driver.
32    ///
33    /// See [`SqliteConfig`] for details.
34    pub sqlite: SqliteConfig,
35
36    /// Configuration for external database drivers.
37    ///
38    /// See [`ExternalDriverConfig`] for details.
39    pub external: ExternalDriverConfig,
40}
41
42/// Configuration for the MySQL database driver.
43#[derive(Debug, Default)]
44#[cfg_attr(
45    feature = "sqlx-toml",
46    derive(serde::Deserialize),
47    serde(default, rename_all = "kebab-case", deny_unknown_fields)
48)]
49pub struct MySqlConfig {
50    // No fields implemented yet. This key is only used to validate parsing.
51}
52
53/// Configuration for the Postgres database driver.
54#[derive(Debug, Default)]
55#[cfg_attr(
56    feature = "sqlx-toml",
57    derive(serde::Deserialize),
58    serde(default, rename_all = "kebab-case", deny_unknown_fields)
59)]
60pub struct PgConfig {
61    // No fields implemented yet. This key is only used to validate parsing.
62}
63
64/// Configuration for the SQLite database driver.
65#[derive(Debug, Default)]
66#[cfg_attr(
67    feature = "sqlx-toml",
68    derive(serde::Deserialize),
69    serde(default, rename_all = "kebab-case", deny_unknown_fields)
70)]
71pub struct SqliteConfig {
72    /// Specify extensions to load, either by name or by path.
73    ///
74    /// Paths should be relative to the workspace root.
75    ///
76    /// See [Loading an Extension](https://www.sqlite.org/loadext.html#loading_an_extension)
77    /// in the SQLite manual for details.
78    ///
79    /// The `sqlite-load-extension` feature must be enabled and SQLite must be built
80    /// _without_ [`SQLITE_OMIT_LOAD_EXTENSION`] enabled.
81    ///
82    /// [`SQLITE_OMIT_LOAD_EXTENSION`]: https://www.sqlite.org/compile.html#omit_load_extension
83    ///
84    /// # Note: Does Not Configure Runtime Extension Loading
85    /// Extensions to be loaded at runtime *must* be separately configured with
86    /// `SqliteConnectOptions::extension()` or `SqliteConnectOptions::extension_with_entrypoint()`.
87    ///
88    /// # Safety
89    /// This causes arbitrary DLLs on the filesystem to be loaded at execution time,
90    /// which can easily result in undefined behavior, memory corruption,
91    /// or exploitable vulnerabilities if misused.
92    ///
93    /// It is not possible to provide a truly safe version of this API.
94    ///
95    /// Use this field with care, and only load extensions that you trust.
96    ///
97    /// # Example
98    /// Load the `uuid` and `vsv` extensions from [`sqlean`](https://github.com/nalgeon/sqlean).
99    ///
100    /// `sqlx.toml`:
101    /// ```toml
102    /// [common.drivers.sqlite]
103    /// unsafe-load-extensions = ["uuid", "vsv"]
104    /// ```
105    pub unsafe_load_extensions: Vec<String>,
106}
107
108/// Configuration for external database drivers.
109#[derive(Debug, Default)]
110#[cfg_attr(feature = "sqlx-toml", derive(serde::Deserialize), serde(transparent))]
111pub struct ExternalDriverConfig {
112    #[cfg(feature = "sqlx-toml")]
113    by_name: std::collections::BTreeMap<String, toml::Table>,
114}
115
116/// Type-erased [`toml::de::Error`].
117pub type TryParseError = Box<dyn Error + Send + Sync + 'static>;
118
119impl ExternalDriverConfig {
120    /// Try to parse the config for a given driver name, returning `Ok(None)` if it does not exist.
121    #[cfg(feature = "sqlx-toml")]
122    pub fn try_parse<T: serde::de::DeserializeOwned>(
123        &self,
124        name: &str,
125    ) -> Result<Option<T>, TryParseError> {
126        let Some(config) = self.by_name.get(name) else {
127            return Ok(None);
128        };
129
130        // What's really baffling is that `toml` doesn't provide any way to deserialize
131        // from a `&Table` or `&Value`, only owned variants, so cloning is unavoidable here.
132        Ok(Some(config.clone().try_into()?))
133    }
134
135    /// Try to parse the config for a given driver name, returning `Ok(None)` if it does not exist.
136    #[cfg(not(feature = "sqlx-toml"))]
137    pub fn try_parse<T>(&self, _name: &str) -> Result<Option<T>, TryParseError> {
138        Ok(None)
139    }
140}