use crate::{
Error,
error::{StorageError, ValidationError},
};
pub trait DatabaseResultExt<T> {
fn map_db_err(self) -> Result<T, Error>;
fn map_db_err_with_context(self, context: &str) -> Result<T, Error>;
}
impl<T, E: std::fmt::Display> DatabaseResultExt<T> for Result<T, E> {
fn map_db_err(self) -> Result<T, Error> {
self.map_err(|e| Error::Storage(StorageError::Database(e.to_string())))
}
fn map_db_err_with_context(self, context: &str) -> Result<T, Error> {
self.map_err(|e| Error::Storage(StorageError::Database(format!("{context}: {e}"))))
}
}
pub trait RequiredFieldExt<T> {
fn require_field(self, field_name: &str) -> Result<T, ValidationError>;
}
impl<T> RequiredFieldExt<T> for Option<T> {
fn require_field(self, field_name: &str) -> Result<T, ValidationError> {
self.ok_or_else(|| ValidationError::MissingField(format!("{field_name} is required")))
}
}
#[macro_export]
macro_rules! map_storage_err {
($result:expr) => {
$result.map_err(|e| {
$crate::Error::Storage($crate::error::StorageError::Database(e.to_string()))
})
};
}
#[macro_export]
macro_rules! map_storage_err_with_context {
($result:expr, $context:expr) => {
$result.map_err(|e| {
$crate::Error::Storage($crate::error::StorageError::Database(format!(
"{}: {}",
$context, e
)))
})
};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::{StorageError, ValidationError};
#[test]
fn test_database_result_ext() {
let error_result: Result<i32, &str> = Err("database connection failed");
let mapped = error_result.map_db_err();
assert!(mapped.is_err());
match mapped.unwrap_err() {
Error::Storage(StorageError::Database(msg)) => {
assert_eq!(msg, "database connection failed");
}
_ => panic!("Expected storage database error"),
}
}
#[test]
fn test_database_result_ext_with_context() {
let error_result: Result<i32, &str> = Err("timeout");
let mapped = error_result.map_db_err_with_context("Failed to save user");
assert!(mapped.is_err());
match mapped.unwrap_err() {
Error::Storage(StorageError::Database(msg)) => {
assert_eq!(msg, "Failed to save user: timeout");
}
_ => panic!("Expected storage database error"),
}
}
#[test]
fn test_required_field_ext_some() {
let some_value = Some("test@example.com".to_string());
let result = some_value.require_field("Email");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "test@example.com");
}
#[test]
fn test_required_field_ext_none() {
let none_value: Option<String> = None;
let result = none_value.require_field("Email");
assert!(result.is_err());
match result.unwrap_err() {
ValidationError::MissingField(msg) => {
assert_eq!(msg, "Email is required");
}
_ => panic!("Expected missing field validation error"),
}
}
#[test]
fn test_map_storage_err_macro() {
let error_result: Result<i32, &str> = Err("query failed");
let mapped = map_storage_err!(error_result);
assert!(mapped.is_err());
match mapped.unwrap_err() {
Error::Storage(StorageError::Database(msg)) => {
assert_eq!(msg, "query failed");
}
_ => panic!("Expected storage database error"),
}
}
#[test]
fn test_map_storage_err_with_context_macro() {
let error_result: Result<i32, &str> = Err("foreign key constraint");
let mapped = map_storage_err_with_context!(error_result, "Creating user");
assert!(mapped.is_err());
match mapped.unwrap_err() {
Error::Storage(StorageError::Database(msg)) => {
assert_eq!(msg, "Creating user: foreign key constraint");
}
_ => panic!("Expected storage database error"),
}
}
}