use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LoaderError {
InvalidResource {
message: String,
url: Option<String>,
},
MissingField {
field: String,
url: Option<String>,
},
InvalidExpression {
expression: String,
error: String,
},
EmbeddedLoadFailed {
version: String,
message: String,
},
ConfigLoadFailed {
path: String,
message: String,
},
StorageError {
message: String,
},
}
impl fmt::Display for LoaderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LoaderError::InvalidResource { message, url } => {
if let Some(url) = url {
write!(f, "Invalid SearchParameter '{}': {}", url, message)
} else {
write!(f, "Invalid SearchParameter: {}", message)
}
}
LoaderError::MissingField { field, url } => {
if let Some(url) = url {
write!(
f,
"SearchParameter '{}' missing required field '{}'",
url, field
)
} else {
write!(f, "SearchParameter missing required field '{}'", field)
}
}
LoaderError::InvalidExpression { expression, error } => {
write!(f, "Invalid FHIRPath expression '{}': {}", expression, error)
}
LoaderError::EmbeddedLoadFailed { version, message } => {
write!(
f,
"Failed to load embedded {} parameters: {}",
version, message
)
}
LoaderError::ConfigLoadFailed { path, message } => {
write!(f, "Failed to load config from '{}': {}", path, message)
}
LoaderError::StorageError { message } => {
write!(f, "Storage error loading parameters: {}", message)
}
}
}
}
impl std::error::Error for LoaderError {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RegistryError {
DuplicateUrl {
url: String,
},
NotFound {
identifier: String,
},
InvalidDefinition {
message: String,
},
Locked {
reason: String,
},
}
impl fmt::Display for RegistryError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RegistryError::DuplicateUrl { url } => {
write!(f, "SearchParameter with URL '{}' already exists", url)
}
RegistryError::NotFound { identifier } => {
write!(f, "SearchParameter '{}' not found", identifier)
}
RegistryError::InvalidDefinition { message } => {
write!(f, "Invalid SearchParameter definition: {}", message)
}
RegistryError::Locked { reason } => {
write!(f, "Registry is locked: {}", reason)
}
}
}
}
impl std::error::Error for RegistryError {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ExtractionError {
EvaluationFailed {
param_name: String,
expression: String,
error: String,
},
ConversionFailed {
param_name: String,
expected_type: String,
actual_value: String,
},
UnsupportedType {
param_name: String,
value_type: String,
},
InvalidResource {
message: String,
},
FhirPathError {
expression: String,
message: String,
},
ConversionError {
message: String,
},
}
impl fmt::Display for ExtractionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExtractionError::EvaluationFailed {
param_name,
expression,
error,
} => {
write!(
f,
"Failed to evaluate '{}' for parameter '{}': {}",
expression, param_name, error
)
}
ExtractionError::ConversionFailed {
param_name,
expected_type,
actual_value,
} => {
write!(
f,
"Cannot convert '{}' to {} for parameter '{}'",
actual_value, expected_type, param_name
)
}
ExtractionError::UnsupportedType {
param_name,
value_type,
} => {
write!(
f,
"Unsupported value type '{}' for parameter '{}'",
value_type, param_name
)
}
ExtractionError::InvalidResource { message } => {
write!(f, "Invalid resource: {}", message)
}
ExtractionError::FhirPathError {
expression,
message,
} => {
write!(f, "FHIRPath error evaluating '{}': {}", expression, message)
}
ExtractionError::ConversionError { message } => {
write!(f, "Conversion error: {}", message)
}
}
}
}
impl std::error::Error for ExtractionError {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ReindexError {
JobNotFound {
job_id: String,
},
AlreadyRunning {
existing_job_id: String,
},
ProcessingFailed {
resource_type: String,
resource_id: String,
error: String,
},
StorageError {
message: String,
},
Cancelled {
job_id: String,
},
}
impl fmt::Display for ReindexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ReindexError::JobNotFound { job_id } => {
write!(f, "Reindex job '{}' not found", job_id)
}
ReindexError::AlreadyRunning { existing_job_id } => {
write!(
f,
"Reindex already running with job ID '{}'",
existing_job_id
)
}
ReindexError::ProcessingFailed {
resource_type,
resource_id,
error,
} => {
write!(
f,
"Failed to reindex {}/{}: {}",
resource_type, resource_id, error
)
}
ReindexError::StorageError { message } => {
write!(f, "Storage error during reindex: {}", message)
}
ReindexError::Cancelled { job_id } => {
write!(f, "Reindex job '{}' was cancelled", job_id)
}
}
}
}
impl std::error::Error for ReindexError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_loader_error_display() {
let err = LoaderError::MissingField {
field: "expression".to_string(),
url: Some("http://example.org/SearchParameter/test".to_string()),
};
assert!(err.to_string().contains("expression"));
assert!(err.to_string().contains("test"));
}
#[test]
fn test_registry_error_display() {
let err = RegistryError::DuplicateUrl {
url: "http://example.org/sp".to_string(),
};
assert!(err.to_string().contains("already exists"));
}
#[test]
fn test_extraction_error_display() {
let err = ExtractionError::EvaluationFailed {
param_name: "name".to_string(),
expression: "Patient.name".to_string(),
error: "syntax error".to_string(),
};
assert!(err.to_string().contains("name"));
assert!(err.to_string().contains("Patient.name"));
}
#[test]
fn test_reindex_error_display() {
let err = ReindexError::ProcessingFailed {
resource_type: "Patient".to_string(),
resource_id: "123".to_string(),
error: "database error".to_string(),
};
assert!(err.to_string().contains("Patient/123"));
}
}