use std::error;
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum ConstraintViolationType {
Unique,
ForeignKey,
NotFound,
Other(String),
}
impl fmt::Display for ConstraintViolationType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
ConstraintViolationType::Unique => write!(f, "Unique"),
ConstraintViolationType::ForeignKey => write!(f, "Foreign Key"),
ConstraintViolationType::NotFound => f.write_str("Not Found"),
ConstraintViolationType::Other(ref msg) => write!(f, "{}", msg),
}
}
}
pub struct ConstraintViolationError {
violation_type: ConstraintViolationType,
source: Option<Box<dyn error::Error>>,
}
impl ConstraintViolationError {
pub fn with_violation_type(violation_type: ConstraintViolationType) -> Self {
Self {
violation_type,
source: None,
}
}
pub fn from_source_with_violation_type(
violation_type: ConstraintViolationType,
source: Box<dyn error::Error>,
) -> Self {
Self {
violation_type,
source: Some(source),
}
}
pub fn violation_type(&self) -> &ConstraintViolationType {
&self.violation_type
}
}
impl error::Error for ConstraintViolationError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
self.source.as_ref().map(|s| s.as_ref())
}
}
impl fmt::Display for ConstraintViolationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.source {
Some(s) => write!(f, "{}", s),
None => write!(f, "{} constraint violated", &self.violation_type),
}
}
}
impl fmt::Debug for ConstraintViolationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut debug_struct = f.debug_struct("ConstraintViolationError");
debug_struct.field("violation_type", &self.violation_type);
if let Some(source) = &self.source {
debug_struct.field("source", source);
}
debug_struct.finish()
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn test_debug_with_violation_type() {
let debug = "ConstraintViolationError { violation_type: Unique }";
let err = ConstraintViolationError::with_violation_type(ConstraintViolationType::Unique);
assert_eq!(format!("{:?}", err), debug);
}
#[test]
fn test_debug_from_source_with_violation_type() {
let debug = "ConstraintViolationError { violation_type: Unique, source: ConstraintViolationError { violation_type: Unique } }";
let err = ConstraintViolationError::from_source_with_violation_type(
ConstraintViolationType::Unique,
Box::new(ConstraintViolationError::with_violation_type(
ConstraintViolationType::Unique,
)),
);
assert_eq!(format!("{:?}", err), debug);
}
#[test]
fn test_display_with_violation_type() {
let disp = "Unique constraint violated";
let err = ConstraintViolationError::with_violation_type(ConstraintViolationType::Unique);
assert_eq!(format!("{}", err), disp);
}
#[test]
fn test_display_from_source_with_violation_type() {
let disp = "Unique constraint violated";
let err = ConstraintViolationError::from_source_with_violation_type(
ConstraintViolationType::Unique,
Box::new(ConstraintViolationError::with_violation_type(
ConstraintViolationType::Unique,
)),
);
assert_eq!(format!("{}", err), disp);
}
}