gatekeep_sqlx/fragment/
driver.rs1use url::Url;
2
3use super::GatekeepSqlxBackend;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum SqlxDriver {
9 Postgres,
11 Sqlite,
13 MySql,
15}
16
17impl SqlxDriver {
18 #[must_use]
20 pub const fn name(self) -> &'static str {
21 match self {
22 Self::Postgres => "postgres",
23 Self::Sqlite => "sqlite",
24 Self::MySql => "mysql",
25 }
26 }
27
28 #[must_use]
30 pub const fn is_enabled(self) -> bool {
31 match self {
32 Self::Postgres => cfg!(feature = "postgres"),
33 Self::Sqlite => cfg!(feature = "sqlite"),
34 Self::MySql => cfg!(feature = "mysql"),
35 }
36 }
37}
38
39#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
41#[non_exhaustive]
42pub enum SqlxDriverError {
43 #[error("unsupported SQLx database URL scheme {scheme:?}")]
45 UnsupportedUrlScheme {
46 scheme: Option<String>,
49 },
50
51 #[error("SQLx driver {driver} is not enabled for gatekeep-sqlx")]
53 DriverNotEnabled {
54 driver: &'static str,
56 },
57
58 #[error("SQLx backend mismatch: expected {expected}, found {actual}")]
60 BackendMismatch {
61 expected: &'static str,
63 actual: &'static str,
65 },
66}
67
68pub fn infer_enabled_driver_from_url(database_url: &str) -> Result<SqlxDriver, SqlxDriverError> {
75 let driver = infer_driver_from_url(database_url)?;
76 if driver.is_enabled() {
77 Ok(driver)
78 } else {
79 Err(SqlxDriverError::DriverNotEnabled {
80 driver: driver.name(),
81 })
82 }
83}
84
85pub fn validate_database_url_for_backend<B>(database_url: &str) -> Result<(), SqlxDriverError>
92where
93 B: GatekeepSqlxBackend,
94{
95 let actual = infer_enabled_driver_from_url(database_url)?;
96 if actual == B::DRIVER {
97 Ok(())
98 } else {
99 Err(SqlxDriverError::BackendMismatch {
100 expected: B::NAME,
101 actual: actual.name(),
102 })
103 }
104}
105
106fn infer_driver_from_url(database_url: &str) -> Result<SqlxDriver, SqlxDriverError> {
107 if database_url.starts_with("sqlite:") {
108 return Ok(SqlxDriver::Sqlite);
109 }
110
111 let Some((scheme, rest)) = database_url.split_once(':') else {
112 return Err(SqlxDriverError::UnsupportedUrlScheme { scheme: None });
113 };
114
115 match scheme {
116 "postgres" | "postgresql" => Ok(SqlxDriver::Postgres),
117 "mysql" | "mariadb" => Ok(SqlxDriver::MySql),
118 "sqlite" => Ok(SqlxDriver::Sqlite),
119 _ => Err(SqlxDriverError::UnsupportedUrlScheme {
120 scheme: Url::parse(database_url)
121 .ok()
122 .filter(|url| rest.starts_with("//") && url.scheme().eq_ignore_ascii_case(scheme))
123 .map(|_| scheme.to_owned()),
124 }),
125 }
126}