use crate::error::Error;
use crate::writer::SqlWriter;
pub trait Dialect: std::fmt::Debug + Send + Sync {
fn write_arg(&self, w: &mut SqlWriter<'_>, position: usize);
fn write_quoted(&self, w: &mut SqlWriter<'_>, s: &str);
fn write_named_arg(&self, w: &mut SqlWriter<'_>, _name: &str) {
w.record_error(Error::NoNamedArgs);
}
}
impl<D: Dialect + ?Sized> Dialect for &D {
fn write_arg(&self, w: &mut SqlWriter<'_>, position: usize) {
(**self).write_arg(w, position);
}
fn write_quoted(&self, w: &mut SqlWriter<'_>, s: &str) {
(**self).write_quoted(w, s);
}
fn write_named_arg(&self, w: &mut SqlWriter<'_>, name: &str) {
(**self).write_named_arg(w, name);
}
}
#[cfg(any(test, feature = "testing"))]
pub mod testing {
use super::Dialect;
use crate::writer::SqlWriter;
#[derive(Debug, Clone, Copy, Default)]
pub struct TestDialect;
impl Dialect for TestDialect {
fn write_arg(&self, w: &mut SqlWriter<'_>, position: usize) {
w.push_str("?");
w.push_str(&position.to_string());
}
fn write_quoted(&self, w: &mut SqlWriter<'_>, s: &str) {
w.push_str("\"");
w.push_str(s);
w.push_str("\"");
}
fn write_named_arg(&self, w: &mut SqlWriter<'_>, name: &str) {
w.push_str(":");
w.push_str(name);
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Numbered;
impl Dialect for Numbered {
fn write_arg(&self, w: &mut SqlWriter<'_>, position: usize) {
w.push_str("$");
w.push_str(&position.to_string());
}
fn write_quoted(&self, w: &mut SqlWriter<'_>, s: &str) {
w.push_str("\"");
w.push_str(s);
w.push_str("\"");
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Positional;
impl Dialect for Positional {
fn write_arg(&self, w: &mut SqlWriter<'_>, _position: usize) {
w.push_str("?");
}
fn write_quoted(&self, w: &mut SqlWriter<'_>, s: &str) {
w.push_str("`");
w.push_str(s);
w.push_str("`");
}
}
}
#[cfg(test)]
mod tests {
use super::testing::{Numbered, Positional, TestDialect};
use super::*;
use crate::error::Error;
#[test]
fn the_trait_expresses_all_three_real_dialects() {
let mut w = SqlWriter::new(&Numbered);
w.push_arg(1i32);
w.push_quoted(&["id"]);
assert_eq!(w.sql(), r#"$1"id""#);
let mut w = SqlWriter::new(&Positional);
w.push_arg(1i32);
w.push_quoted(&["id"]);
assert_eq!(w.sql(), "?`id`");
let mut w = SqlWriter::new(&TestDialect);
w.push_arg(1i32);
w.push_named_arg("name");
w.push_quoted(&["id"]);
assert_eq!(w.sql(), r#"?1:name"id""#);
}
#[test]
fn named_args_are_refused_unless_the_dialect_opts_in() {
for d in [&Numbered as &dyn Dialect, &Positional] {
let mut w = SqlWriter::new(d);
w.push_named_arg("id");
assert!(matches!(w.error(), Some(Error::NoNamedArgs)));
}
}
#[test]
fn a_dialect_reference_is_itself_a_dialect() {
let d = &Numbered;
let mut w = SqlWriter::new(&d);
w.push_arg(7i32);
assert_eq!(w.sql(), "$1");
}
}