allsource_core/infrastructure/di/container.rs
1//! Service Container implementation
2//!
3//! Holds all repository instances and provides factory methods for use cases.
4//!
5//! Note: Stateless use cases (unit structs with no constructor) are not included
6//! in the container - they should be used directly via their static methods.
7
8use crate::application::use_cases::{
9 // Creator use cases (with state)
10 RegisterCreatorUseCase, UpdateCreatorUseCase,
11 // Article use cases (with state)
12 CreateArticleUseCase, UpdateArticleUseCase,
13 // Payment use cases (with state)
14 InitiatePaymentUseCase, ConfirmTransactionUseCase, RefundTransactionUseCase,
15 // Access use cases (with state)
16 GrantFreeAccessUseCase, ValidateTokenUseCase, RevokeAccessUseCase, CheckAccessUseCase,
17 CleanupExpiredTokensUseCase,
18 // Fork use cases (with state)
19 CreateForkUseCase, UpdateForkUseCase, MergeForkUseCase, DiscardForkUseCase,
20 GetForkUseCase, AppendForkEventUseCase, QueryForkEventsUseCase, BranchForkUseCase,
21 CleanupExpiredForksUseCase,
22};
23use crate::domain::repositories::{
24 AccessTokenRepository, ArticleRepository, CreatorRepository, EventStreamRepository,
25 ForkRepository, TransactionRepository,
26};
27use std::sync::Arc;
28
29/// Service container that holds all repository instances and provides factory methods for use cases.
30///
31/// The container uses `Arc` for thread-safe sharing of repository instances across use cases.
32/// All repositories are stored as trait objects, allowing for easy substitution with mock
33/// implementations during testing.
34///
35/// # Design Principles
36///
37/// 1. **Singleton Repositories**: Repository instances are created once and shared across all use cases
38/// 2. **Factory Methods**: Use cases are created on-demand with their dependencies injected
39/// 3. **Thread Safety**: All repositories are wrapped in `Arc` for concurrent access
40/// 4. **Testability**: Repositories can be swapped with mocks via the builder
41///
42/// # Stateless Use Cases
43///
44/// Some use cases are stateless (unit structs with static methods). These are NOT included
45/// in the container and should be used directly:
46/// - `PublishArticleUseCase::execute(article)`
47/// - `ArchiveArticleUseCase::execute(article)`
48/// - `DeleteArticleUseCase::execute(article)`
49/// - `RestoreArticleUseCase::execute(article)`
50/// - `RecordArticlePurchaseUseCase::execute(article, amount)`
51/// - `ExtendAccessUseCase::execute(token, days)`
52/// - And others...
53///
54/// # Example
55///
56/// ```rust,ignore
57/// let container = ContainerBuilder::new()
58/// .with_in_memory_repositories()
59/// .build();
60///
61/// // Get use cases with dependencies injected
62/// let register_creator = container.register_creator_use_case();
63/// let initiate_payment = container.initiate_payment_use_case();
64/// ```
65#[derive(Clone)]
66pub struct ServiceContainer {
67 // Paywall domain repositories
68 creator_repository: Arc<dyn CreatorRepository>,
69 article_repository: Arc<dyn ArticleRepository>,
70 transaction_repository: Arc<dyn TransactionRepository>,
71 access_token_repository: Arc<dyn AccessTokenRepository>,
72 fork_repository: Arc<dyn ForkRepository>,
73 // Core event sourcing repository
74 event_stream_repository: Arc<dyn EventStreamRepository>,
75}
76
77impl ServiceContainer {
78 /// Creates a new service container with the provided repositories.
79 ///
80 /// Prefer using `ContainerBuilder` for a more fluent API.
81 pub fn new(
82 creator_repository: Arc<dyn CreatorRepository>,
83 article_repository: Arc<dyn ArticleRepository>,
84 transaction_repository: Arc<dyn TransactionRepository>,
85 access_token_repository: Arc<dyn AccessTokenRepository>,
86 fork_repository: Arc<dyn ForkRepository>,
87 event_stream_repository: Arc<dyn EventStreamRepository>,
88 ) -> Self {
89 Self {
90 creator_repository,
91 article_repository,
92 transaction_repository,
93 access_token_repository,
94 fork_repository,
95 event_stream_repository,
96 }
97 }
98
99 // =========================================================================
100 // Repository Accessors
101 // =========================================================================
102
103 /// Returns the creator repository instance.
104 pub fn creator_repository(&self) -> Arc<dyn CreatorRepository> {
105 self.creator_repository.clone()
106 }
107
108 /// Returns the article repository instance.
109 pub fn article_repository(&self) -> Arc<dyn ArticleRepository> {
110 self.article_repository.clone()
111 }
112
113 /// Returns the transaction repository instance.
114 pub fn transaction_repository(&self) -> Arc<dyn TransactionRepository> {
115 self.transaction_repository.clone()
116 }
117
118 /// Returns the access token repository instance.
119 pub fn access_token_repository(&self) -> Arc<dyn AccessTokenRepository> {
120 self.access_token_repository.clone()
121 }
122
123 /// Returns the fork repository instance.
124 pub fn fork_repository(&self) -> Arc<dyn ForkRepository> {
125 self.fork_repository.clone()
126 }
127
128 /// Returns the event stream repository instance.
129 pub fn event_stream_repository(&self) -> Arc<dyn EventStreamRepository> {
130 self.event_stream_repository.clone()
131 }
132
133 // =========================================================================
134 // Creator Use Case Factories
135 // =========================================================================
136
137 /// Creates a new `RegisterCreatorUseCase` with injected dependencies.
138 pub fn register_creator_use_case(&self) -> RegisterCreatorUseCase {
139 RegisterCreatorUseCase::new(self.creator_repository.clone())
140 }
141
142 /// Creates a new `UpdateCreatorUseCase` with injected dependencies.
143 pub fn update_creator_use_case(&self) -> UpdateCreatorUseCase {
144 UpdateCreatorUseCase::new(self.creator_repository.clone())
145 }
146
147 // =========================================================================
148 // Article Use Case Factories
149 // =========================================================================
150
151 /// Creates a new `CreateArticleUseCase` with injected dependencies.
152 pub fn create_article_use_case(&self) -> CreateArticleUseCase {
153 CreateArticleUseCase::new(self.article_repository.clone())
154 }
155
156 /// Creates a new `UpdateArticleUseCase` with injected dependencies.
157 pub fn update_article_use_case(&self) -> UpdateArticleUseCase {
158 UpdateArticleUseCase::new(self.article_repository.clone())
159 }
160
161 // Note: PublishArticleUseCase, ArchiveArticleUseCase, DeleteArticleUseCase,
162 // RestoreArticleUseCase, and RecordArticlePurchaseUseCase are stateless.
163 // Use them directly: e.g., PublishArticleUseCase::execute(article)
164
165 // =========================================================================
166 // Payment Use Case Factories
167 // =========================================================================
168
169 /// Creates a new `InitiatePaymentUseCase` with injected dependencies.
170 pub fn initiate_payment_use_case(&self) -> InitiatePaymentUseCase {
171 InitiatePaymentUseCase::new(
172 self.transaction_repository.clone(),
173 self.article_repository.clone(),
174 self.creator_repository.clone(),
175 )
176 }
177
178 /// Creates a new `ConfirmTransactionUseCase` with injected dependencies.
179 pub fn confirm_transaction_use_case(&self) -> ConfirmTransactionUseCase {
180 ConfirmTransactionUseCase::new(
181 self.transaction_repository.clone(),
182 self.access_token_repository.clone(),
183 self.article_repository.clone(),
184 self.creator_repository.clone(),
185 )
186 }
187
188 /// Creates a new `RefundTransactionUseCase` with injected dependencies.
189 pub fn refund_transaction_use_case(&self) -> RefundTransactionUseCase {
190 RefundTransactionUseCase::new(
191 self.transaction_repository.clone(),
192 self.access_token_repository.clone(),
193 )
194 }
195
196 // Note: FailTransactionUseCase, DisputeTransactionUseCase, ResolveDisputeUseCase,
197 // and ListTransactionsUseCase are stateless. Use them directly.
198
199 // =========================================================================
200 // Access Token Use Case Factories
201 // =========================================================================
202
203 /// Creates a new `GrantFreeAccessUseCase` with injected dependencies.
204 pub fn grant_free_access_use_case(&self) -> GrantFreeAccessUseCase {
205 GrantFreeAccessUseCase::new(
206 self.access_token_repository.clone(),
207 self.article_repository.clone(),
208 )
209 }
210
211 /// Creates a new `ValidateTokenUseCase` with injected dependencies.
212 pub fn validate_token_use_case(&self) -> ValidateTokenUseCase {
213 ValidateTokenUseCase::new(self.access_token_repository.clone())
214 }
215
216 /// Creates a new `RevokeAccessUseCase` with injected dependencies.
217 pub fn revoke_access_use_case(&self) -> RevokeAccessUseCase {
218 RevokeAccessUseCase::new(self.access_token_repository.clone())
219 }
220
221 /// Creates a new `CheckAccessUseCase` with injected dependencies.
222 pub fn check_access_use_case(&self) -> CheckAccessUseCase {
223 CheckAccessUseCase::new(self.access_token_repository.clone())
224 }
225
226 /// Creates a new `CleanupExpiredTokensUseCase` with injected dependencies.
227 pub fn cleanup_expired_tokens_use_case(&self) -> CleanupExpiredTokensUseCase {
228 CleanupExpiredTokensUseCase::new(self.access_token_repository.clone())
229 }
230
231 // Note: ExtendAccessUseCase, RecordAccessUseCase, and ListAccessTokensUseCase
232 // are stateless. Use them directly.
233
234 // =========================================================================
235 // Fork Use Case Factories
236 // =========================================================================
237
238 /// Creates a new `CreateForkUseCase` with injected dependencies.
239 pub fn create_fork_use_case(&self) -> CreateForkUseCase {
240 CreateForkUseCase::new(self.fork_repository.clone())
241 }
242
243 /// Creates a new `UpdateForkUseCase` with injected dependencies.
244 pub fn update_fork_use_case(&self) -> UpdateForkUseCase {
245 UpdateForkUseCase::new(self.fork_repository.clone())
246 }
247
248 /// Creates a new `MergeForkUseCase` with injected dependencies.
249 pub fn merge_fork_use_case(&self) -> MergeForkUseCase {
250 MergeForkUseCase::new(self.fork_repository.clone())
251 }
252
253 /// Creates a new `DiscardForkUseCase` with injected dependencies.
254 pub fn discard_fork_use_case(&self) -> DiscardForkUseCase {
255 DiscardForkUseCase::new(self.fork_repository.clone())
256 }
257
258 /// Creates a new `GetForkUseCase` with injected dependencies.
259 pub fn get_fork_use_case(&self) -> GetForkUseCase {
260 GetForkUseCase::new(self.fork_repository.clone())
261 }
262
263 /// Creates a new `AppendForkEventUseCase` with injected dependencies.
264 pub fn append_fork_event_use_case(&self) -> AppendForkEventUseCase {
265 AppendForkEventUseCase::new(self.fork_repository.clone())
266 }
267
268 /// Creates a new `QueryForkEventsUseCase` with injected dependencies.
269 pub fn query_fork_events_use_case(&self) -> QueryForkEventsUseCase {
270 QueryForkEventsUseCase::new(self.fork_repository.clone())
271 }
272
273 /// Creates a new `BranchForkUseCase` with injected dependencies.
274 pub fn branch_fork_use_case(&self) -> BranchForkUseCase {
275 BranchForkUseCase::new(self.fork_repository.clone())
276 }
277
278 /// Creates a new `CleanupExpiredForksUseCase` with injected dependencies.
279 pub fn cleanup_expired_forks_use_case(&self) -> CleanupExpiredForksUseCase {
280 CleanupExpiredForksUseCase::new(self.fork_repository.clone())
281 }
282
283 // Note: ListForksUseCase is stateless. Use it directly.
284}
285
286impl std::fmt::Debug for ServiceContainer {
287 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 f.debug_struct("ServiceContainer")
289 .field("creator_repository", &"Arc<dyn CreatorRepository>")
290 .field("article_repository", &"Arc<dyn ArticleRepository>")
291 .field("transaction_repository", &"Arc<dyn TransactionRepository>")
292 .field("access_token_repository", &"Arc<dyn AccessTokenRepository>")
293 .field("fork_repository", &"Arc<dyn ForkRepository>")
294 .field("event_stream_repository", &"Arc<dyn EventStreamRepository>")
295 .finish()
296 }
297}