use crate::errors::DynoxideError;
use rmcp::model::{CallToolResult, ContentBlock};
fn short_error_type(err: &DynoxideError) -> &'static str {
match err {
DynoxideError::ResourceNotFoundException(_) => "ResourceNotFoundException",
DynoxideError::ResourceInUseException(_) => "ResourceInUseException",
DynoxideError::ValidationException(_)
| DynoxideError::KeyEmptyValueValidation(_)
| DynoxideError::EnvelopedValidation(_) => "ValidationException",
DynoxideError::ConditionalCheckFailedException(..)
| DynoxideError::StatementConditionalCheckFailed(..) => "ConditionalCheckFailedException",
DynoxideError::TransactionCanceledException(..) => "TransactionCanceledException",
DynoxideError::ItemCollectionSizeLimitExceededException(_) => {
"ItemCollectionSizeLimitExceededException"
}
DynoxideError::ProvisionedThroughputExceededException(_) => {
"ProvisionedThroughputExceededException"
}
DynoxideError::InternalServerError(_) | DynoxideError::SqliteError(_) => {
"InternalServerError"
}
DynoxideError::ConversionError(_) => "ValidationException",
DynoxideError::DuplicateItemException(_) => "DuplicateItemException",
DynoxideError::AccessDeniedException(_) => "AccessDeniedException",
DynoxideError::SerializationException(_) => "SerializationException",
DynoxideError::LimitExceededException(_) => "LimitExceededException",
DynoxideError::IdempotentParameterMismatchException(_) => {
"IdempotentParameterMismatchException"
}
DynoxideError::UnsupportedCapability(_) => "UnsupportedOperation",
}
}
fn is_retryable(err: &DynoxideError) -> bool {
matches!(
err,
DynoxideError::ProvisionedThroughputExceededException(_)
| DynoxideError::InternalServerError(_)
| DynoxideError::SqliteError(_)
)
}
pub fn to_tool_error(err: DynoxideError) -> CallToolResult {
let mut error_json = serde_json::json!({
"error_type": short_error_type(&err),
"message": err.to_string(),
"retryable": is_retryable(&err),
});
let item = match &err {
DynoxideError::ConditionalCheckFailedException(_, item) => item.as_ref(),
DynoxideError::StatementConditionalCheckFailed(_, item) => Some(item),
_ => None,
};
if let Some(item) = item
&& let Ok(item) = serde_json::to_value(item)
{
error_json["item"] = item;
}
CallToolResult::error(vec![ContentBlock::text(error_json.to_string())])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_value_key_validation_maps_to_validation_exception() {
assert_eq!(
short_error_type(&DynoxideError::KeyEmptyValueValidation(String::new())),
short_error_type(&DynoxideError::ValidationException(String::new())),
);
assert_eq!(
short_error_type(&DynoxideError::KeyEmptyValueValidation(String::new())),
"ValidationException",
);
}
#[test]
fn enveloped_validation_maps_to_validation_exception() {
assert_eq!(
short_error_type(&DynoxideError::EnvelopedValidation(String::new())),
short_error_type(&DynoxideError::ValidationException(String::new())),
);
assert_eq!(
short_error_type(&DynoxideError::EnvelopedValidation(String::new())),
"ValidationException",
);
}
}