sqlx_core/any/
driver.rs

1use crate::any::connection::AnyConnectionBackend;
2use crate::any::{AnyConnectOptions, AnyConnection};
3use crate::common::DebugFn;
4use crate::connection::Connection;
5use crate::database::Database;
6use crate::Error;
7use futures_core::future::BoxFuture;
8use once_cell::sync::OnceCell;
9use std::fmt::{Debug, Formatter};
10use url::Url;
11
12static DRIVERS: OnceCell<&'static [AnyDriver]> = OnceCell::new();
13
14#[macro_export]
15macro_rules! declare_driver_with_optional_migrate {
16    ($name:ident = $db:path) => {
17        #[cfg(feature = "migrate")]
18        pub const $name: $crate::any::driver::AnyDriver =
19            $crate::any::driver::AnyDriver::with_migrate::<$db>();
20
21        #[cfg(not(feature = "migrate"))]
22        pub const $name: $crate::any::driver::AnyDriver =
23            $crate::any::driver::AnyDriver::without_migrate::<$db>();
24    };
25}
26
27#[non_exhaustive]
28pub struct AnyDriver {
29    pub(crate) name: &'static str,
30    pub(crate) url_schemes: &'static [&'static str],
31    pub(crate) connect:
32        DebugFn<fn(&AnyConnectOptions) -> BoxFuture<'_, crate::Result<AnyConnection>>>,
33    pub(crate) migrate_database: Option<AnyMigrateDatabase>,
34}
35
36impl AnyDriver {
37    pub const fn without_migrate<DB: Database>() -> Self
38    where
39        DB::Connection: AnyConnectionBackend,
40        <DB::Connection as Connection>::Options:
41            for<'a> TryFrom<&'a AnyConnectOptions, Error = Error>,
42    {
43        Self {
44            name: DB::NAME,
45            url_schemes: DB::URL_SCHEMES,
46            connect: DebugFn(AnyConnection::connect_with_db::<DB>),
47            migrate_database: None,
48        }
49    }
50
51    #[cfg(not(feature = "migrate"))]
52    pub const fn with_migrate<DB: Database>() -> Self
53    where
54        DB::Connection: AnyConnectionBackend,
55        <DB::Connection as Connection>::Options:
56            for<'a> TryFrom<&'a AnyConnectOptions, Error = Error>,
57    {
58        Self::without_migrate::<DB>()
59    }
60
61    #[cfg(feature = "migrate")]
62    pub const fn with_migrate<DB: Database + crate::migrate::MigrateDatabase>() -> Self
63    where
64        DB::Connection: AnyConnectionBackend,
65        <DB::Connection as Connection>::Options:
66            for<'a> TryFrom<&'a AnyConnectOptions, Error = Error>,
67    {
68        Self {
69            migrate_database: Some(AnyMigrateDatabase {
70                create_database: DebugFn(DB::create_database),
71                database_exists: DebugFn(DB::database_exists),
72                drop_database: DebugFn(DB::drop_database),
73                force_drop_database: DebugFn(DB::force_drop_database),
74            }),
75            ..Self::without_migrate::<DB>()
76        }
77    }
78
79    pub fn get_migrate_database(&self) -> crate::Result<&AnyMigrateDatabase> {
80        self.migrate_database.as_ref()
81            .ok_or_else(|| Error::Configuration(format!("{} driver does not support migrations or the `migrate` feature was not enabled for it", self.name).into()))
82    }
83}
84
85impl Debug for AnyDriver {
86    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
87        f.debug_struct("AnyDriver")
88            .field("name", &self.name)
89            .field("url_schemes", &self.url_schemes)
90            .finish()
91    }
92}
93
94pub struct AnyMigrateDatabase {
95    create_database: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<()>>>,
96    database_exists: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<bool>>>,
97    drop_database: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<()>>>,
98    force_drop_database: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<()>>>,
99}
100
101impl AnyMigrateDatabase {
102    pub fn create_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> {
103        (self.create_database)(url)
104    }
105
106    pub fn database_exists<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<bool>> {
107        (self.database_exists)(url)
108    }
109
110    pub fn drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> {
111        (self.drop_database)(url)
112    }
113
114    pub fn force_drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> {
115        (self.force_drop_database)(url)
116    }
117}
118
119/// Install the list of drivers for [`AnyConnection`] to use.
120///
121/// Must be called before an `AnyConnection` or `AnyPool` can be connected.
122///
123/// ### Errors
124/// If called more than once.
125pub fn install_drivers(
126    drivers: &'static [AnyDriver],
127) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
128    DRIVERS
129        .set(drivers)
130        .map_err(|_| "drivers already installed".into())
131}
132
133pub(crate) fn from_url_str(url: &str) -> crate::Result<&'static AnyDriver> {
134    from_url(&url.parse().map_err(Error::config)?)
135}
136
137pub(crate) fn from_url(url: &Url) -> crate::Result<&'static AnyDriver> {
138    let scheme = url.scheme();
139
140    let drivers: &[AnyDriver] = DRIVERS
141        .get()
142        .expect("No drivers installed. Please see the documentation in `sqlx::any` for details.");
143
144    drivers
145        .iter()
146        .find(|driver| driver.url_schemes.contains(&url.scheme()))
147        .ok_or_else(|| {
148            Error::Configuration(format!("no driver found for URL scheme {scheme:?}").into())
149        })
150}