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    // 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}