Skip to main content

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