use serde::Deserialize;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum MutationErrorClass {
Validation,
Conflict,
NotFound,
Unauthorized,
Forbidden,
Internal,
TransactionFailed,
Timeout,
RateLimited,
ServiceUnavailable,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[non_exhaustive]
pub enum CascadeErrorCode {
ValidationError,
Conflict,
NotFound,
Unauthorized,
Forbidden,
InternalError,
TransactionFailed,
Timeout,
RateLimited,
ServiceUnavailable,
}
impl MutationErrorClass {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Validation => "validation",
Self::Conflict => "conflict",
Self::NotFound => "not_found",
Self::Unauthorized => "unauthorized",
Self::Forbidden => "forbidden",
Self::Internal => "internal",
Self::TransactionFailed => "transaction_failed",
Self::Timeout => "timeout",
Self::RateLimited => "rate_limited",
Self::ServiceUnavailable => "service_unavailable",
}
}
#[must_use]
pub const fn to_cascade_code(self) -> CascadeErrorCode {
match self {
Self::Validation => CascadeErrorCode::ValidationError,
Self::Conflict => CascadeErrorCode::Conflict,
Self::NotFound => CascadeErrorCode::NotFound,
Self::Unauthorized => CascadeErrorCode::Unauthorized,
Self::Forbidden => CascadeErrorCode::Forbidden,
Self::Internal => CascadeErrorCode::InternalError,
Self::TransactionFailed => CascadeErrorCode::TransactionFailed,
Self::Timeout => CascadeErrorCode::Timeout,
Self::RateLimited => CascadeErrorCode::RateLimited,
Self::ServiceUnavailable => CascadeErrorCode::ServiceUnavailable,
}
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use serde_json::json;
use super::*;
#[test]
fn to_cascade_code_is_one_to_one() {
let pairs = [
(MutationErrorClass::Validation, CascadeErrorCode::ValidationError),
(MutationErrorClass::Conflict, CascadeErrorCode::Conflict),
(MutationErrorClass::NotFound, CascadeErrorCode::NotFound),
(MutationErrorClass::Unauthorized, CascadeErrorCode::Unauthorized),
(MutationErrorClass::Forbidden, CascadeErrorCode::Forbidden),
(MutationErrorClass::Internal, CascadeErrorCode::InternalError),
(MutationErrorClass::TransactionFailed, CascadeErrorCode::TransactionFailed),
(MutationErrorClass::Timeout, CascadeErrorCode::Timeout),
(MutationErrorClass::RateLimited, CascadeErrorCode::RateLimited),
(MutationErrorClass::ServiceUnavailable, CascadeErrorCode::ServiceUnavailable),
];
for (class, expected) in pairs {
assert_eq!(class.to_cascade_code(), expected, "class = {class:?}");
}
}
#[test]
fn deserializes_from_pg_enum_snake_case() {
let pairs = [
("validation", MutationErrorClass::Validation),
("conflict", MutationErrorClass::Conflict),
("not_found", MutationErrorClass::NotFound),
("unauthorized", MutationErrorClass::Unauthorized),
("forbidden", MutationErrorClass::Forbidden),
("internal", MutationErrorClass::Internal),
("transaction_failed", MutationErrorClass::TransactionFailed),
("timeout", MutationErrorClass::Timeout),
("rate_limited", MutationErrorClass::RateLimited),
("service_unavailable", MutationErrorClass::ServiceUnavailable),
];
for (raw, expected) in pairs {
let got: MutationErrorClass = serde_json::from_value(json!(raw)).unwrap();
assert_eq!(got, expected, "raw = {raw}");
}
}
#[test]
fn cascade_code_deserializes_from_screaming_snake_case() {
let pairs = [
(CascadeErrorCode::ValidationError, "VALIDATION_ERROR"),
(CascadeErrorCode::Conflict, "CONFLICT"),
(CascadeErrorCode::NotFound, "NOT_FOUND"),
(CascadeErrorCode::Unauthorized, "UNAUTHORIZED"),
(CascadeErrorCode::Forbidden, "FORBIDDEN"),
(CascadeErrorCode::InternalError, "INTERNAL_ERROR"),
(CascadeErrorCode::TransactionFailed, "TRANSACTION_FAILED"),
(CascadeErrorCode::Timeout, "TIMEOUT"),
(CascadeErrorCode::RateLimited, "RATE_LIMITED"),
(CascadeErrorCode::ServiceUnavailable, "SERVICE_UNAVAILABLE"),
];
for (code, raw) in pairs {
let got: CascadeErrorCode = serde_json::from_value(json!(raw)).unwrap();
assert_eq!(got, code, "raw = {raw}");
}
}
}