use surrealdb_types::{
AlreadyExistsError, AuthError, ConfigurationError, Error as TypesError, NotAllowedError,
NotFoundError, SerializationError, ValidationError,
};
use uuid::Uuid;
use crate::api::err::ApiError;
use crate::err;
use crate::err::into_types_error;
pub fn parse_error() -> TypesError {
TypesError::validation("Parse error".to_string(), ValidationError::Parse)
}
pub fn too_many_transactions() -> TypesError {
TypesError::validation("Too many open transactions".to_string(), ValidationError::InvalidParams)
}
pub fn invalid_request() -> TypesError {
TypesError::validation("Invalid request".to_string(), ValidationError::InvalidRequest)
}
pub fn method_not_found(name: String) -> TypesError {
TypesError::not_found(
"Method not found".to_string(),
NotFoundError::Method {
name,
},
)
}
pub fn method_not_allowed(name: String) -> TypesError {
TypesError::not_allowed(
"Method not allowed".to_string(),
NotAllowedError::Method {
name,
},
)
}
pub fn invalid_params(msg: impl Into<String>) -> TypesError {
TypesError::validation(msg.into(), ValidationError::InvalidParams)
}
#[allow(clippy::needless_pass_by_value)] pub fn internal_error(err: anyhow::Error) -> TypesError {
TypesError::from_anyhow_with_chain(err)
}
pub fn lq_not_supported() -> TypesError {
TypesError::configuration(
"Live query not supported".to_string(),
ConfigurationError::LiveQueryNotSupported,
)
}
pub fn bad_lq_config() -> TypesError {
TypesError::configuration(
"Bad live query config".to_string(),
ConfigurationError::BadLiveQueryConfig,
)
}
pub fn bad_gql_config() -> TypesError {
TypesError::configuration(
"Bad GraphQL config".to_string(),
ConfigurationError::BadGraphqlConfig,
)
}
pub fn thrown(msg: impl Into<String>) -> TypesError {
TypesError::thrown(msg.into())
}
pub fn serialize(msg: impl Into<String>) -> TypesError {
TypesError::serialization(msg.into(), SerializationError::Serialization)
}
pub fn deserialize(msg: impl Into<String>) -> TypesError {
TypesError::serialization(msg.into(), SerializationError::Deserialization)
}
pub fn session_not_found(id: Uuid) -> TypesError {
TypesError::not_found(
format!("Session not found: {id:?}"),
NotFoundError::Session {
id: Some(id.to_string()),
},
)
}
pub fn session_exists(id: Uuid) -> TypesError {
TypesError::already_exists(
format!("Session already exists: {id}"),
AlreadyExistsError::Session {
id: id.to_string(),
},
)
}
pub fn session_expired() -> TypesError {
TypesError::not_allowed("The session has expired".to_string(), AuthError::SessionExpired)
}
pub fn types_error_from_anyhow(error: anyhow::Error) -> TypesError {
match error.downcast::<TypesError>() {
Ok(types_error) => types_error,
Err(error) => {
if let Some(api_error) = error.downcast_ref::<ApiError>() {
return api_error.to_types_error();
}
let error = match error.downcast::<err::Error>() {
Ok(db_error) => return into_types_error(db_error),
Err(error) => error,
};
match error.downcast::<crate::kvs::Error>() {
Ok(kvs_error) => into_types_error(err::Error::Kvs(kvs_error)),
Err(error) => TypesError::from_anyhow_with_chain(error),
}
}
}
}
#[cfg(test)]
mod tests {
use surrealdb_types::{Error as TypesError, QueryError};
use super::types_error_from_anyhow;
use crate::err;
use crate::kvs::Error as KvsError;
#[test]
fn bare_kvs_conflict_maps_to_transaction_conflict() {
let err = anyhow::Error::new(KvsError::TransactionConflict("write conflict".into()));
let te = types_error_from_anyhow(err);
assert_eq!(te.query_details(), Some(&QueryError::TransactionConflict));
}
#[test]
fn wrapped_kvs_conflict_still_maps_to_transaction_conflict() {
let err = anyhow::Error::new(err::Error::Kvs(KvsError::TransactionConflict(
"write conflict".into(),
)));
let te = types_error_from_anyhow(err);
assert_eq!(te.query_details(), Some(&QueryError::TransactionConflict));
}
#[test]
fn existing_types_error_is_returned_verbatim() {
let original = TypesError::query("boom".to_string(), QueryError::NotExecuted);
let te = types_error_from_anyhow(anyhow::Error::new(original));
assert_eq!(te.query_details(), Some(&QueryError::NotExecuted));
}
}