pub const GUARD_MESSAGE_PREFIX: &str = "fraiseql-server: unsupported database URL";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DatabaseScheme {
Postgres,
MySql,
Sqlite,
SqlServer,
}
impl DatabaseScheme {
#[must_use]
pub const fn required_feature(self) -> Option<&'static str> {
match self {
Self::Postgres => None,
Self::MySql => Some("mysql"),
Self::Sqlite => Some("sqlite"),
Self::SqlServer => Some("sqlserver"),
}
}
}
pub fn guard_sqlite_mutations(
schema: &fraiseql_core::schema::CompiledSchema,
) -> anyhow::Result<()> {
if schema.mutations.is_empty() {
return Ok(());
}
let sample: Vec<&str> = schema.mutations.iter().take(3).map(|m| m.name.as_str()).collect();
let suffix = if schema.mutations.len() > sample.len() {
format!(", … (+{} more)", schema.mutations.len() - sample.len())
} else {
String::new()
};
anyhow::bail!(
"fraiseql-server: SQLite is a read-only runtime adapter, but the compiled schema declares \
{} mutation(s) which cannot be executed against a SQLite database. Use a postgresql:// / \
mysql:// / sqlserver:// URL, or remove the mutations from the schema. Affected: {}{}",
schema.mutations.len(),
sample.join(", "),
suffix,
)
}
pub fn parse_database_url(url: &str) -> anyhow::Result<DatabaseScheme> {
let scheme = url.split("://").next().unwrap_or("");
match scheme {
"postgresql" | "postgres" => Ok(DatabaseScheme::Postgres),
"mysql" => Ok(DatabaseScheme::MySql),
"sqlite" => Ok(DatabaseScheme::Sqlite),
"sqlserver" => Ok(DatabaseScheme::SqlServer),
"" => anyhow::bail!(
"{GUARD_MESSAGE_PREFIX} — the URL has no scheme. Expected one of \
postgresql:// | postgres:// | mysql:// | sqlite:// | sqlserver://."
),
other => anyhow::bail!(
"{GUARD_MESSAGE_PREFIX} (observed URL scheme: {other:?}). The \
fraiseql-server binary dispatches on the URL scheme and supports \
postgresql:// | postgres:// | mysql:// | sqlite:// | sqlserver:// \
only."
),
}
}
#[cfg(test)]
mod tests;