Skip to main content

lab_resource_manager/application/
error.rs

1use crate::domain::aggregates::identity_link::errors::IdentityLinkError;
2use crate::domain::aggregates::resource_usage::errors::ResourceUsageError;
3use crate::domain::ports::{
4    notifier::NotificationError, repositories::RepositoryError,
5    resource_collection_access::ResourceCollectionAccessError,
6};
7use crate::domain::services::resource_usage::errors::ResourceConflictError;
8use std::fmt;
9
10/// Application層で発生するエラーの列挙型
11///
12/// インフラストラクチャ層、ドメイン層、およびユースケース固有のエラーをラップする。
13#[derive(Debug)]
14pub enum ApplicationError {
15    /// リポジトリ操作中に発生したエラー
16    Repository(RepositoryError),
17    /// 通知送信中に発生したエラー
18    Notification(NotificationError),
19    /// リソースコレクションへのアクセス中に発生したエラー
20    ResourceCollectionAccess(ResourceCollectionAccessError),
21
22    /// リソース使用に関するドメインエラー
23    ResourceUsage(ResourceUsageError),
24    /// ID紐付けに関するドメインエラー
25    IdentityLink(IdentityLinkError),
26
27    /// 外部システムが既に紐付けられている
28    ExternalSystemAlreadyLinked {
29        /// 紐付けられているメールアドレス
30        email: String,
31        /// 既に紐付けられている外部システム名
32        external_system: String,
33    },
34
35    /// リソースの競合エラー
36    ResourceConflict {
37        /// 競合しているリソースの説明
38        resource_description: String,
39        /// 競合している既存の使用予定ID
40        conflicting_usage_id: String,
41    },
42
43    /// 認可エラー(権限不足)
44    Unauthorized(String),
45}
46
47impl fmt::Display for ApplicationError {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        match self {
50            ApplicationError::Repository(e) => write!(f, "リポジトリエラー: {}", e),
51            ApplicationError::Notification(e) => write!(f, "通知エラー: {}", e),
52            ApplicationError::ResourceCollectionAccess(e) => {
53                write!(f, "リソースコレクションアクセスエラー: {}", e)
54            }
55            ApplicationError::ResourceUsage(e) => write!(f, "リソース使用エラー: {}", e),
56            ApplicationError::IdentityLink(e) => write!(f, "ID紐付けエラー: {}", e),
57            ApplicationError::ExternalSystemAlreadyLinked {
58                email,
59                external_system,
60            } => {
61                write!(
62                    f,
63                    "メールアドレス {} は既に {} に紐付けられています",
64                    email, external_system
65                )
66            }
67            ApplicationError::ResourceConflict {
68                resource_description,
69                conflicting_usage_id,
70            } => {
71                write!(
72                    f,
73                    "リソース {} は既に使用予定 {} で使用されています",
74                    resource_description, conflicting_usage_id
75                )
76            }
77            ApplicationError::Unauthorized(msg) => {
78                write!(f, "権限不足: {}", msg)
79            }
80        }
81    }
82}
83
84impl std::error::Error for ApplicationError {
85    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
86        match self {
87            ApplicationError::Repository(e) => Some(e),
88            ApplicationError::Notification(e) => Some(e),
89            ApplicationError::ResourceCollectionAccess(e) => Some(e),
90            ApplicationError::ResourceUsage(e) => Some(e),
91            ApplicationError::IdentityLink(e) => Some(e),
92            ApplicationError::ExternalSystemAlreadyLinked { .. } => None,
93            ApplicationError::ResourceConflict { .. } => None,
94            ApplicationError::Unauthorized(_) => None,
95        }
96    }
97}
98
99impl From<RepositoryError> for ApplicationError {
100    fn from(e: RepositoryError) -> Self {
101        ApplicationError::Repository(e)
102    }
103}
104
105impl From<ResourceUsageError> for ApplicationError {
106    fn from(e: ResourceUsageError) -> Self {
107        ApplicationError::ResourceUsage(e)
108    }
109}
110
111impl From<IdentityLinkError> for ApplicationError {
112    fn from(e: IdentityLinkError) -> Self {
113        ApplicationError::IdentityLink(e)
114    }
115}
116
117impl From<ResourceConflictError> for ApplicationError {
118    fn from(e: ResourceConflictError) -> Self {
119        ApplicationError::ResourceConflict {
120            resource_description: e.resource_description,
121            conflicting_usage_id: e.conflicting_usage_id.as_str().to_string(),
122        }
123    }
124}
125
126impl From<NotificationError> for ApplicationError {
127    fn from(e: NotificationError) -> Self {
128        ApplicationError::Notification(e)
129    }
130}
131
132impl From<ResourceCollectionAccessError> for ApplicationError {
133    fn from(e: ResourceCollectionAccessError) -> Self {
134        ApplicationError::ResourceCollectionAccess(e)
135    }
136}