use super::{Dialect, DialectKind, SqlType};
use crate::transaction::IsolationLevel;
#[derive(Debug, Clone, Copy, Default)]
pub struct SqliteDialect;
impl SqliteDialect {
pub const fn new() -> Self {
Self
}
}
impl Dialect for SqliteDialect {
fn name(&self) -> &'static str {
"sqlite"
}
fn kind(&self) -> DialectKind {
DialectKind::Sqlite
}
fn quote_identifier(&self, identifier: &str, out: &mut String) {
out.push('"');
for ch in identifier.chars() {
if ch == '"' {
out.push('"');
}
out.push(ch);
}
out.push('"');
}
fn placeholder(&self, _index: usize, out: &mut String) {
out.push('?');
}
fn supports_returning(&self) -> bool {
rusqlite::version_number() >= 3_035_000
}
fn map_sql_type(&self, ty: SqlType, out: &mut String) {
match ty {
SqlType::Boolean => out.push_str("BOOLEAN"),
SqlType::Integer => out.push_str("INTEGER"),
SqlType::BigInt => out.push_str("BIGINT"),
SqlType::Real => out.push_str("REAL"),
SqlType::Text => out.push_str("TEXT"),
SqlType::Varchar(length) => {
out.push_str("VARCHAR(");
out.push_str(&length.to_string());
out.push(')');
}
SqlType::Timestamp => out.push_str("TIMESTAMP"),
SqlType::Blob => out.push_str("BLOB"),
SqlType::Json | SqlType::Uuid | SqlType::Array(_) => out.push_str("TEXT"),
SqlType::Enum { .. } => out.push_str("TEXT"),
}
}
fn begin_with_sql(&self, level: IsolationLevel) -> String {
match level {
IsolationLevel::Deferred => "BEGIN DEFERRED".to_string(),
IsolationLevel::Immediate => "BEGIN IMMEDIATE".to_string(),
IsolationLevel::Exclusive => "BEGIN EXCLUSIVE".to_string(),
_ => "BEGIN".to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returning_support_follows_the_runtime_sqlite_version() {
let supported = SqliteDialect::new().supports_returning();
assert_eq!(supported, rusqlite::version_number() >= 3_035_000);
assert!(supported, "the bundled SQLite should support RETURNING");
}
}