use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
NoNamedArgs,
RawArgCount {
placeholders: usize,
args: usize,
clause: String,
},
TypeMismatch {
expected: &'static str,
found: &'static str,
},
Incomplete(&'static str),
ConflictingClauses {
first: &'static str,
second: &'static str,
},
Other(String),
}
impl Error {
pub fn type_mismatch(expected: &'static str, found: &'static str) -> Self {
Error::TypeMismatch { expected, found }
}
pub fn raw_arg_count(placeholders: usize, args: usize, clause: impl Into<String>) -> Self {
Error::RawArgCount {
placeholders,
args,
clause: clause.into(),
}
}
pub fn conflicting_clauses(first: &'static str, second: &'static str) -> Self {
Error::ConflictingClauses { first, second }
}
pub fn other(msg: impl Into<String>) -> Self {
Error::Other(msg.into())
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::NoNamedArgs => f.write_str("Dialect does not support named arguments"),
Error::RawArgCount {
placeholders,
args,
clause,
} => write!(
f,
"Bad Statement: has {placeholders} placeholders but {args} args: {clause}"
),
Error::TypeMismatch { expected, found } => {
write!(f, "cannot read {found} as {expected}")
}
Error::Incomplete(what) => write!(f, "query is missing {what}"),
Error::ConflictingClauses { first, second } => write!(
f,
"{first} and {second} are both set, but they are two spellings of one clause — set only one"
),
Error::Other(msg) => f.write_str(msg),
}
}
}
impl std::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn named_arg_error_reads_like_bobs() {
assert_eq!(
Error::NoNamedArgs.to_string(),
"Dialect does not support named arguments"
);
}
#[test]
fn raw_arg_count_message_is_byte_compatible_with_bob() {
let e = Error::raw_arg_count(2, 0, "SELECT a, b FROM alphabet WHERE c = ? AND d <= ?");
assert_eq!(
e.to_string(),
"Bad Statement: has 2 placeholders but 0 args: SELECT a, b FROM alphabet WHERE c = ? AND d <= ?"
);
}
#[test]
fn conflicting_clauses_names_what_the_caller_set() {
assert_eq!(
Error::conflicting_clauses("LIMIT", "FETCH").to_string(),
"LIMIT and FETCH are both set, but they are two spellings of one clause — set only one"
);
}
#[test]
fn is_a_std_error() {
fn takes(_: &dyn std::error::Error) {}
takes(&Error::Incomplete("a table"));
}
}