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
119pub 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}