#[cfg(feature = "postgres")]
pub mod postgres;
#[cfg(feature = "mysql")]
pub mod mysql;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum DialectKind {
#[default]
Postgres,
Mysql,
}
impl std::fmt::Display for DialectKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
impl std::str::FromStr for DialectKind {
type Err = crate::error::WaypointError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.trim().to_lowercase().as_str() {
"postgres" | "postgresql" | "pg" => Ok(DialectKind::Postgres),
"mysql" | "mariadb" => Ok(DialectKind::Mysql),
other => Err(crate::error::WaypointError::ConfigError(format!(
"Invalid database engine '{}'. Use 'postgres' or 'mysql'.",
other
))),
}
}
}
impl DialectKind {
pub fn name(&self) -> &'static str {
match self {
DialectKind::Postgres => "postgres",
DialectKind::Mysql => "mysql",
}
}
pub fn from_url(url: &str) -> Option<Self> {
let lower = url.trim_start().to_lowercase();
if lower.starts_with("postgres://") || lower.starts_with("postgresql://") {
Some(DialectKind::Postgres)
} else if lower.starts_with("mysql://") {
Some(DialectKind::Mysql)
} else {
None
}
}
}
pub trait DatabaseDialect: Send + Sync {
fn kind(&self) -> DialectKind;
fn quote_ident(&self, name: &str) -> String;
fn qualified_table(&self, schema: &str, table: &str) -> String {
format!("{}.{}", self.quote_ident(schema), self.quote_ident(table))
}
fn history_table_ddl(&self, schema: &str, table: &str) -> String;
fn supports_transactional_ddl(&self) -> bool;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_url_recognises_postgres() {
assert_eq!(
DialectKind::from_url("postgres://u:p@h/d"),
Some(DialectKind::Postgres)
);
assert_eq!(
DialectKind::from_url("postgresql://u:p@h/d"),
Some(DialectKind::Postgres)
);
assert_eq!(
DialectKind::from_url("POSTGRES://u:p@h/d"),
Some(DialectKind::Postgres)
);
}
#[test]
fn from_url_recognises_mysql() {
assert_eq!(
DialectKind::from_url("mysql://u:p@h/d"),
Some(DialectKind::Mysql)
);
assert_eq!(
DialectKind::from_url(" mysql://h/d"),
Some(DialectKind::Mysql)
);
}
#[test]
fn from_url_returns_none_for_kv_or_unknown() {
assert_eq!(DialectKind::from_url("host=localhost user=postgres"), None);
assert_eq!(DialectKind::from_url("sqlite://x"), None);
assert_eq!(DialectKind::from_url(""), None);
}
}