use darling::FromMeta;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DatabaseDialect {
#[default]
Postgres,
ClickHouse,
MongoDB
}
impl DatabaseDialect {
#[must_use]
pub fn placeholder(&self, index: usize) -> String {
match self {
Self::Postgres | Self::ClickHouse => format!("${index}"),
Self::MongoDB => format!("${index}") }
}
#[must_use]
pub fn placeholders(&self, count: usize) -> String {
(1..=count)
.map(|i| format!("${i}"))
.collect::<Vec<_>>()
.join(", ")
}
#[must_use]
pub fn set_clause(&self, fields: &[&str]) -> String {
match self {
Self::Postgres | Self::ClickHouse => fields
.iter()
.enumerate()
.map(|(i, f)| format!("{} = ${}", f, i + 1))
.collect::<Vec<_>>()
.join(", "),
Self::MongoDB => fields.join(", ") }
}
#[must_use]
pub fn feature_flag(&self) -> &'static str {
match self {
Self::Postgres => "postgres",
Self::ClickHouse => "clickhouse",
Self::MongoDB => "mongodb"
}
}
}
impl FromMeta for DatabaseDialect {
fn from_string(value: &str) -> darling::Result<Self> {
match value.to_lowercase().as_str() {
"postgres" | "postgresql" | "pg" => Ok(Self::Postgres),
"clickhouse" | "ch" => Ok(Self::ClickHouse),
"mongodb" | "mongo" => Ok(Self::MongoDB),
_ => Err(darling::Error::unknown_value(value))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn postgres_placeholders() {
let d = DatabaseDialect::Postgres;
assert_eq!(d.placeholder(1), "$1");
assert_eq!(d.placeholder(5), "$5");
assert_eq!(d.placeholders(3), "$1, $2, $3");
assert_eq!(d.placeholders(0), "");
}
#[test]
fn clickhouse_placeholders() {
let d = DatabaseDialect::ClickHouse;
assert_eq!(d.placeholder(1), "$1");
assert_eq!(d.placeholders(3), "$1, $2, $3");
}
#[test]
fn mongodb_placeholders() {
let d = DatabaseDialect::MongoDB;
assert_eq!(d.placeholder(1), "$1");
assert_eq!(d.placeholders(3), "$1, $2, $3");
}
#[test]
fn set_clause_postgres() {
let d = DatabaseDialect::Postgres;
let fields = ["name", "email"];
assert_eq!(d.set_clause(&fields), "name = $1, email = $2");
}
#[test]
fn set_clause_clickhouse() {
let d = DatabaseDialect::ClickHouse;
let fields = ["name", "email"];
assert_eq!(d.set_clause(&fields), "name = $1, email = $2");
}
#[test]
fn set_clause_mongodb() {
let d = DatabaseDialect::MongoDB;
let fields = ["name", "email"];
assert_eq!(d.set_clause(&fields), "name, email");
}
#[test]
fn feature_flags() {
assert_eq!(DatabaseDialect::Postgres.feature_flag(), "postgres");
assert_eq!(DatabaseDialect::ClickHouse.feature_flag(), "clickhouse");
assert_eq!(DatabaseDialect::MongoDB.feature_flag(), "mongodb");
}
#[test]
fn from_meta_postgres() {
assert_eq!(
DatabaseDialect::from_string("postgres").unwrap(),
DatabaseDialect::Postgres
);
assert_eq!(
DatabaseDialect::from_string("POSTGRESQL").unwrap(),
DatabaseDialect::Postgres
);
assert_eq!(
DatabaseDialect::from_string("pg").unwrap(),
DatabaseDialect::Postgres
);
}
#[test]
fn from_meta_clickhouse() {
assert_eq!(
DatabaseDialect::from_string("clickhouse").unwrap(),
DatabaseDialect::ClickHouse
);
assert_eq!(
DatabaseDialect::from_string("CH").unwrap(),
DatabaseDialect::ClickHouse
);
}
#[test]
fn from_meta_mongodb() {
assert_eq!(
DatabaseDialect::from_string("mongodb").unwrap(),
DatabaseDialect::MongoDB
);
assert_eq!(
DatabaseDialect::from_string("MONGO").unwrap(),
DatabaseDialect::MongoDB
);
}
#[test]
fn from_meta_invalid() {
assert!(DatabaseDialect::from_string("mysql").is_err());
assert!(DatabaseDialect::from_string("sqlite").is_err());
assert!(DatabaseDialect::from_string("oracle").is_err());
}
#[test]
fn default_is_postgres() {
assert_eq!(DatabaseDialect::default(), DatabaseDialect::Postgres);
}
}