#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConflictError {
pub code: String,
pub message: String,
pub existing_id: Option<String>,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "crate::error::env_control::should_skip_location")
)]
pub location: Option<crate::error::source_location::SourceLocation>,
}
impl ConflictError {
pub fn new(message: impl Into<String>) -> Self {
Self {
code: String::from(crate::error::codes::resource::CONFLICT),
message: message.into(),
existing_id: None,
location: None,
}
}
pub fn with_existing_id(mut self, id: impl Into<String>) -> Self {
self.existing_id = Some(id.into());
self
}
pub fn with_location(mut self, location: crate::error::source_location::SourceLocation) -> Self {
self.location = Some(location);
self
}
}
impl std::fmt::Display for ConflictError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Error [{}]: {}", self.code, self.message)?;
if let Some(ref id) = self.existing_id {
write!(f, " (existing ID: {})", id)?;
}
write!(
f,
"\nNext Steps: Resolve conflict or use different identifier"
)?;
if let Some(ref location) = self.location {
write!(f, "\nSource: {}", location)?;
}
Ok(())
}
}
impl std::error::Error for ConflictError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_conflict_error_creation() {
let err = ConflictError::new("Resource already exists");
assert_eq!(err.message, "Resource already exists");
assert_eq!(err.code, crate::error::codes::resource::CONFLICT);
assert_eq!(err.existing_id, None);
}
#[test]
fn test_conflict_error_with_existing_id() {
let err = ConflictError::new("Duplicate user").with_existing_id("user-456");
assert_eq!(err.existing_id, Some(String::from("user-456")));
}
#[test]
fn test_conflict_error_display() {
let err = ConflictError::new("Email already registered").with_existing_id("123");
let display = format!("{}", err);
assert!(display.contains("Email already registered"));
assert!(display.contains("123"));
}
}