use crate::core::{
AggregateQuery, BulkInsertQuery, BulkUpdateQuery, ConflictClause, CountQuery, DeleteQuery,
FieldType, InsertQuery, Op, SelectQuery, UpdateQuery,
};
use super::{CompiledStatement, SqlError};
fn write_pg_array_keys(
sql: &mut String,
qualified_col: &str,
placeholders: &[String],
keyword: &str,
) {
sql.push_str(qualified_col);
sql.push_str(keyword);
let mut first = true;
for p in placeholders {
if !first {
sql.push_str(", ");
}
first = false;
sql.push_str(p);
}
sql.push(']');
}
pub trait Dialect {
fn name(&self) -> &'static str;
fn quote_ident(&self, name: &str) -> String {
let escaped = name.replace('"', "\"\"");
format!("\"{escaped}\"")
}
fn placeholder(&self, n: usize) -> String {
let _ = n;
"?".to_owned()
}
fn serial_type(&self, field_type: FieldType) -> &'static str {
match field_type {
FieldType::I32 => "INTEGER",
_ => "BIGINT",
}
}
fn serial_type_includes_primary_key(&self) -> bool {
false
}
fn bool_literal(&self, b: bool) -> &'static str {
if b {
"TRUE"
} else {
"FALSE"
}
}
fn supports_concurrent_index(&self) -> bool {
false
}
fn supports_returning(&self) -> bool {
false
}
fn cast_aggregate_to_int(&self, expr: &str) -> String {
format!("CAST({expr} AS BIGINT)")
}
fn cast_aggregate_to_float(&self, expr: &str) -> String {
format!("CAST({expr} AS DOUBLE PRECISION)")
}
fn null_cast(&self, ty: FieldType) -> Option<&'static str> {
let _ = ty;
None
}
fn column_type(&self, ty: FieldType, max_length: Option<u32>) -> String {
match ty {
FieldType::I16 => "SMALLINT".into(),
FieldType::I32 => "INTEGER".into(),
FieldType::I64 => "BIGINT".into(),
FieldType::F32 => "REAL".into(),
FieldType::F64 => "DOUBLE PRECISION".into(),
FieldType::Bool => "BOOLEAN".into(),
FieldType::String => match max_length {
Some(n) => format!("VARCHAR({n})"),
None => "TEXT".into(),
},
FieldType::DateTime => "TIMESTAMPTZ".into(),
FieldType::Date => "DATE".into(),
FieldType::Uuid => "UUID".into(),
FieldType::Json => "JSONB".into(),
}
}
fn supports_op(&self, op: Op) -> bool {
let _ = op;
true
}
fn write_ilike(&self, sql: &mut String, qualified_col: &str, placeholder: &str, negated: bool) {
sql.push_str(qualified_col);
sql.push_str(if negated { " NOT ILIKE " } else { " ILIKE " });
sql.push_str(placeholder);
}
fn write_null_safe_eq(
&self,
sql: &mut String,
qualified_col: &str,
placeholder: &str,
distinct: bool,
) {
sql.push_str(qualified_col);
sql.push_str(if distinct {
" IS DISTINCT FROM "
} else {
" IS NOT DISTINCT FROM "
});
sql.push_str(placeholder);
}
fn write_json_contains(&self, sql: &mut String, qualified_col: &str, placeholder: &str) {
sql.push_str(qualified_col);
sql.push_str(" @> ");
sql.push_str(placeholder);
sql.push_str("::jsonb");
}
fn write_json_contained_by(&self, sql: &mut String, qualified_col: &str, placeholder: &str) {
sql.push_str(qualified_col);
sql.push_str(" <@ ");
sql.push_str(placeholder);
sql.push_str("::jsonb");
}
fn write_json_has_key(&self, sql: &mut String, qualified_col: &str, placeholder: &str) {
sql.push_str(qualified_col);
sql.push_str(" ? ");
sql.push_str(placeholder);
}
fn write_json_has_any_keys(
&self,
sql: &mut String,
qualified_col: &str,
placeholders: &[String],
) {
write_pg_array_keys(sql, qualified_col, placeholders, " ?| ARRAY[");
}
fn write_json_has_all_keys(
&self,
sql: &mut String,
qualified_col: &str,
placeholders: &[String],
) {
write_pg_array_keys(sql, qualified_col, placeholders, " ?& ARRAY[");
}
fn write_conflict_clause(
&self,
sql: &mut String,
conflict: &ConflictClause,
) -> Result<(), SqlError> {
let _ = sql;
let shape = match conflict {
ConflictClause::DoNothing => "DO NOTHING",
ConflictClause::DoUpdate { .. } => "DO UPDATE",
};
Err(SqlError::ConflictNotSupportedInDialect {
shape,
dialect: self.name(),
})
}
fn acquire_session_lock_sql(&self) -> Option<String> {
None
}
fn release_session_lock_sql(&self) -> Option<String> {
None
}
fn acquire_xact_lock_sql(&self) -> Option<String> {
None
}
fn compile_select(&self, query: &SelectQuery) -> Result<CompiledStatement, SqlError>;
fn compile_insert(&self, query: &InsertQuery) -> Result<CompiledStatement, SqlError>;
fn compile_bulk_insert(&self, query: &BulkInsertQuery) -> Result<CompiledStatement, SqlError>;
fn compile_update(&self, query: &UpdateQuery) -> Result<CompiledStatement, SqlError>;
fn compile_delete(&self, query: &DeleteQuery) -> Result<CompiledStatement, SqlError>;
fn compile_count(&self, query: &CountQuery) -> Result<CompiledStatement, SqlError>;
fn compile_aggregate(&self, query: &AggregateQuery) -> Result<CompiledStatement, SqlError>;
fn compile_bulk_update(&self, query: &BulkUpdateQuery) -> Result<CompiledStatement, SqlError>;
}