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<SqliteExtension>,
106}
107
108/// Extension for the SQLite database driver.
109#[derive(Debug, PartialEq)]
110#[cfg_attr(
111 feature = "sqlx-toml",
112 derive(serde::Deserialize),
113 serde(untagged, deny_unknown_fields)
114)]
115pub enum SqliteExtension {
116 Path(String),
117 PathWithEntrypoint { path: String, entrypoint: String },
118}
119
120/// Configuration for external database drivers.
121#[derive(Debug, Default)]
122#[cfg_attr(feature = "sqlx-toml", derive(serde::Deserialize), serde(transparent))]
123pub struct ExternalDriverConfig {
124 #[cfg(feature = "sqlx-toml")]
125 by_name: std::collections::BTreeMap<String, toml::Table>,
126}
127
128/// Type-erased [`toml::de::Error`].
129pub type TryParseError = Box<dyn Error + Send + Sync + 'static>;
130
131impl ExternalDriverConfig {
132 /// Try to parse the config for a given driver name, returning `Ok(None)` if it does not exist.
133 #[cfg(feature = "sqlx-toml")]
134 pub fn try_parse<T: serde::de::DeserializeOwned>(
135 &self,
136 name: &str,
137 ) -> Result<Option<T>, TryParseError> {
138 let Some(config) = self.by_name.get(name) else {
139 return Ok(None);
140 };
141
142 // What's really baffling is that `toml` doesn't provide any way to deserialize
143 // from a `&Table` or `&Value`, only owned variants, so cloning is unavoidable here.
144 Ok(Some(config.clone().try_into()?))
145 }
146
147 /// Try to parse the config for a given driver name, returning `Ok(None)` if it does not exist.
148 #[cfg(not(feature = "sqlx-toml"))]
149 pub fn try_parse<T>(&self, _name: &str) -> Result<Option<T>, TryParseError> {
150 Ok(None)
151 }
152}