1use serde::Deserialize;
11
12#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Deserialize)]
19#[serde(rename_all = "snake_case")]
20#[non_exhaustive]
21pub enum MutationErrorClass {
22 Validation,
24 Conflict,
26 NotFound,
28 Unauthorized,
30 Forbidden,
32 Internal,
34 TransactionFailed,
36 Timeout,
38 RateLimited,
40 ServiceUnavailable,
42}
43
44#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Deserialize)]
49#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
50#[non_exhaustive]
51pub enum CascadeErrorCode {
52 ValidationError,
54 Conflict,
56 NotFound,
58 Unauthorized,
60 Forbidden,
62 InternalError,
64 TransactionFailed,
66 Timeout,
68 RateLimited,
70 ServiceUnavailable,
72}
73
74impl MutationErrorClass {
75 #[must_use]
80 pub const fn as_str(self) -> &'static str {
81 match self {
82 Self::Validation => "validation",
83 Self::Conflict => "conflict",
84 Self::NotFound => "not_found",
85 Self::Unauthorized => "unauthorized",
86 Self::Forbidden => "forbidden",
87 Self::Internal => "internal",
88 Self::TransactionFailed => "transaction_failed",
89 Self::Timeout => "timeout",
90 Self::RateLimited => "rate_limited",
91 Self::ServiceUnavailable => "service_unavailable",
92 }
93 }
94
95 #[must_use]
97 pub const fn to_cascade_code(self) -> CascadeErrorCode {
98 match self {
99 Self::Validation => CascadeErrorCode::ValidationError,
100 Self::Conflict => CascadeErrorCode::Conflict,
101 Self::NotFound => CascadeErrorCode::NotFound,
102 Self::Unauthorized => CascadeErrorCode::Unauthorized,
103 Self::Forbidden => CascadeErrorCode::Forbidden,
104 Self::Internal => CascadeErrorCode::InternalError,
105 Self::TransactionFailed => CascadeErrorCode::TransactionFailed,
106 Self::Timeout => CascadeErrorCode::Timeout,
107 Self::RateLimited => CascadeErrorCode::RateLimited,
108 Self::ServiceUnavailable => CascadeErrorCode::ServiceUnavailable,
109 }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 #![allow(clippy::unwrap_used)] use serde_json::json;
118
119 use super::*;
120
121 #[test]
122 fn to_cascade_code_is_one_to_one() {
123 let pairs = [
124 (MutationErrorClass::Validation, CascadeErrorCode::ValidationError),
125 (MutationErrorClass::Conflict, CascadeErrorCode::Conflict),
126 (MutationErrorClass::NotFound, CascadeErrorCode::NotFound),
127 (MutationErrorClass::Unauthorized, CascadeErrorCode::Unauthorized),
128 (MutationErrorClass::Forbidden, CascadeErrorCode::Forbidden),
129 (MutationErrorClass::Internal, CascadeErrorCode::InternalError),
130 (MutationErrorClass::TransactionFailed, CascadeErrorCode::TransactionFailed),
131 (MutationErrorClass::Timeout, CascadeErrorCode::Timeout),
132 (MutationErrorClass::RateLimited, CascadeErrorCode::RateLimited),
133 (MutationErrorClass::ServiceUnavailable, CascadeErrorCode::ServiceUnavailable),
134 ];
135 for (class, expected) in pairs {
136 assert_eq!(class.to_cascade_code(), expected, "class = {class:?}");
137 }
138 }
139
140 #[test]
141 fn deserializes_from_pg_enum_snake_case() {
142 let pairs = [
143 ("validation", MutationErrorClass::Validation),
144 ("conflict", MutationErrorClass::Conflict),
145 ("not_found", MutationErrorClass::NotFound),
146 ("unauthorized", MutationErrorClass::Unauthorized),
147 ("forbidden", MutationErrorClass::Forbidden),
148 ("internal", MutationErrorClass::Internal),
149 ("transaction_failed", MutationErrorClass::TransactionFailed),
150 ("timeout", MutationErrorClass::Timeout),
151 ("rate_limited", MutationErrorClass::RateLimited),
152 ("service_unavailable", MutationErrorClass::ServiceUnavailable),
153 ];
154 for (raw, expected) in pairs {
155 let got: MutationErrorClass = serde_json::from_value(json!(raw)).unwrap();
156 assert_eq!(got, expected, "raw = {raw}");
157 }
158 }
159
160 #[test]
161 fn cascade_code_deserializes_from_screaming_snake_case() {
162 let pairs = [
163 (CascadeErrorCode::ValidationError, "VALIDATION_ERROR"),
164 (CascadeErrorCode::Conflict, "CONFLICT"),
165 (CascadeErrorCode::NotFound, "NOT_FOUND"),
166 (CascadeErrorCode::Unauthorized, "UNAUTHORIZED"),
167 (CascadeErrorCode::Forbidden, "FORBIDDEN"),
168 (CascadeErrorCode::InternalError, "INTERNAL_ERROR"),
169 (CascadeErrorCode::TransactionFailed, "TRANSACTION_FAILED"),
170 (CascadeErrorCode::Timeout, "TIMEOUT"),
171 (CascadeErrorCode::RateLimited, "RATE_LIMITED"),
172 (CascadeErrorCode::ServiceUnavailable, "SERVICE_UNAVAILABLE"),
173 ];
174 for (code, raw) in pairs {
175 let got: CascadeErrorCode = serde_json::from_value(json!(raw)).unwrap();
176 assert_eq!(got, code, "raw = {raw}");
177 }
178 }
179}