use std::borrow::Cow;
use crate::placeholders::Dialect;
use super::expr::ColumnRef;
use super::validate::validate_identifier;
use crate::QueryError;
mod common;
mod features;
mod mysql;
mod postgres;
mod sqlite;
pub(super) use features::DialectFeature;
static POSTGRES: postgres::PostgresSpec = postgres::PostgresSpec;
static SQLITE: sqlite::SqliteSpec = sqlite::SqliteSpec;
static MYSQL: mysql::MysqlSpec = mysql::MysqlSpec;
pub(super) trait DialectRenderer: Send + Sync {
fn dialect(&self) -> Dialect;
fn placeholder(&self, position: usize) -> String;
fn validate_feature(&self, feature: DialectFeature) -> Result<(), QueryError>;
fn render_upsert(
&self,
conflict: &[ColumnRef],
update_columns: &[&str],
) -> Result<String, QueryError>;
fn render_returning(&self, columns: &[String]) -> Result<String, QueryError> {
self.validate_feature(DialectFeature::Returning)?;
if columns.is_empty() {
return Err(QueryError::BindError(
"RETURNING requires at least one column".to_string(),
));
}
Ok(format!(" RETURNING {}", columns.join(", ")))
}
fn render_function(&self, name: Cow<'static, str>) -> Result<Cow<'static, str>, QueryError> {
validate_identifier(&name)?;
Ok(name)
}
}
pub(super) fn renderer(dialect: Dialect) -> &'static dyn DialectRenderer {
match dialect {
Dialect::Postgres => &POSTGRES,
Dialect::Sqlite => &SQLITE,
Dialect::Mysql => &MYSQL,
}
}
pub(super) fn validate_feature(
dialect: Dialect,
feature: DialectFeature,
) -> Result<(), QueryError> {
renderer(dialect).validate_feature(feature)
}
pub(super) fn render_function(
dialect: Dialect,
name: Cow<'static, str>,
) -> Result<Cow<'static, str>, QueryError> {
renderer(dialect).render_function(name)
}