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}