pub(super) fn driver_for_url(database_url: &str) -> &'static str {
let scheme = database_url
.split_once(':')
.map_or("", |(scheme, _)| scheme);
if scheme.eq_ignore_ascii_case("postgres") || scheme.eq_ignore_ascii_case("postgresql") {
"postgres"
} else if scheme.eq_ignore_ascii_case("mysql") || scheme.eq_ignore_ascii_case("mariadb") {
"mysql"
} else {
"sqlite"
}
}
pub(super) fn has_placeholder_brackets(database_url: &str) -> bool {
let mut rest = database_url;
while let Some(open) = rest.find('[') {
let after_open = &rest[open + 1..];
let Some(close) = after_open.find(']') else {
return false;
};
let literal = &after_open[..close];
let address = literal
.split_once('%')
.map_or(literal, |(address, _)| address);
if address.parse::<std::net::Ipv6Addr>().is_err() {
return true;
}
rest = &after_open[close + 1..];
}
false
}
pub(super) fn ensure_configured_dsn(database_url: &str) -> Result<(), crate::Error> {
if has_placeholder_brackets(database_url) {
return Err(crate::Error::Internal(
"DATABASE_URL contains placeholder brackets like [your-database-id]. \
Update your .env file with a real connection string."
.to_string(),
));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::{driver_for_url, ensure_configured_dsn};
#[test]
fn driver_follows_the_dsn_scheme_and_its_aliases() {
for (dsn, driver) in [
("postgres://app:pw@db/app", "postgres"),
("postgresql://app:pw@db/app", "postgres"),
("POSTGRES://app:pw@db/app", "postgres"),
("mysql://app:pw@db/app", "mysql"),
("mariadb://app:pw@db/app", "mysql"),
("MariaDB://app:pw@db/app", "mysql"),
("sqlite::memory:", "sqlite"),
("sqlite://data/app.db", "sqlite"),
("data/app.db", "sqlite"),
] {
assert_eq!(driver_for_url(dsn), driver, "{dsn}");
}
}
#[test]
fn ipv6_literal_hosts_are_not_template_placeholders() {
for dsn in [
"postgres://app:pw@[2001:db8::10]:5432/app",
"mysql://app:pw@[::1]/app",
"postgres://app@[fe80::1%25eth0]:5432/app",
] {
assert!(ensure_configured_dsn(dsn).is_ok(), "{dsn}");
}
for dsn in [
"libsql://[your-database-id].turso.io",
"postgres://app:[YOUR-PASSWORD]@db.example.com/app",
"postgres://app@[::1]:5432/[database]",
] {
assert!(
matches!(ensure_configured_dsn(dsn), Err(crate::Error::Internal(_))),
"{dsn}"
);
}
}
}