tsuzuri_dynamodb/store/
error.rs1use ::serde::de::StdError;
2use aws_sdk_dynamodb::{
3 error::SdkError,
4 operation::{query::QueryError, scan::ScanError, transact_write_items::TransactWriteItemsError},
5};
6use tsuzuri::{error::AggregateError, persist::PersistenceError};
7
8#[derive(Debug, thiserror::Error)]
9pub enum DynamoAggregateError {
10 #[error("optimistic lock error")]
11 OptimisticLock,
12 #[error("Too many operations: {0}, DynamoDb supports only up to 25 operations per transactions")]
13 TransactionListTooLong(usize),
14 #[error("missing attribute: {0}")]
15 MissingAttribute(String),
16 #[error("builder error: {0}")]
17 BuilderError(String),
18 #[error(transparent)]
19 UnknownError(Box<dyn std::error::Error + Send + Sync + 'static>),
20}
21
22impl<T: std::error::Error> From<DynamoAggregateError> for AggregateError<T> {
23 fn from(error: DynamoAggregateError) -> Self {
24 match error {
25 DynamoAggregateError::OptimisticLock => Self::AggregateConflict,
26 DynamoAggregateError::TransactionListTooLong(_) => Self::UnexpectedError(Box::new(error)),
29 DynamoAggregateError::MissingAttribute(err) => {
30 Self::UnexpectedError(Box::new(DynamoAggregateError::MissingAttribute(err)))
31 }
32 DynamoAggregateError::BuilderError(err) => {
33 Self::UnexpectedError(Box::new(DynamoAggregateError::BuilderError(err)))
34 }
35 DynamoAggregateError::UnknownError(err) => Self::UnexpectedError(err),
36 }
37 }
38}
39
40impl From<serde_json::Error> for DynamoAggregateError {
41 fn from(err: serde_json::Error) -> Self {
42 Self::UnknownError(Box::new(err))
43 }
44}
45
46impl From<SdkError<TransactWriteItemsError>> for DynamoAggregateError {
47 fn from(error: SdkError<TransactWriteItemsError>) -> Self {
48 if let SdkError::ServiceError(err) = &error {
49 if let TransactWriteItemsError::TransactionCanceledException(cancellation) = err.err() {
50 for reason in cancellation.cancellation_reasons() {
51 if reason.code() == Some("ConditionalCheckFailed") {
52 return Self::OptimisticLock;
53 }
54 }
55 }
56 }
57 Self::UnknownError(Box::new(error))
58 }
59}
60
61impl From<SdkError<QueryError>> for DynamoAggregateError {
62 fn from(error: SdkError<QueryError>) -> Self {
63 unknown_error(error)
64 }
65}
66
67impl From<SdkError<ScanError>> for DynamoAggregateError {
68 fn from(error: SdkError<ScanError>) -> Self {
69 unknown_error(error)
70 }
71}
72
73fn unknown_error<T: StdError + Send + Sync + 'static>(error: SdkError<T>) -> DynamoAggregateError {
74 DynamoAggregateError::UnknownError(Box::new(error))
75}
76
77impl From<DynamoAggregateError> for PersistenceError {
78 fn from(error: DynamoAggregateError) -> Self {
79 match error {
80 DynamoAggregateError::OptimisticLock => Self::OptimisticLockError,
81 DynamoAggregateError::TransactionListTooLong(_) => Self::UnknownError(Box::new(error)),
84 DynamoAggregateError::MissingAttribute(err) => {
85 Self::UnknownError(Box::new(DynamoAggregateError::MissingAttribute(err)))
86 }
87 DynamoAggregateError::BuilderError(err) => {
88 Self::UnknownError(Box::new(DynamoAggregateError::BuilderError(err)))
89 }
90 DynamoAggregateError::UnknownError(err) => Self::UnknownError(err),
91 }
92 }
93}