use super::ServiceContainer;
use crate::{
application::services::consumer::ConsumerRegistry,
domain::repositories::{
AccessTokenRepository, ArticleRepository, AuditEventRepository, CreatorRepository,
EventStreamRepository, ForkRepository, TenantRepository, TransactionRepository,
},
infrastructure::{
persistence::{SystemMetadataStore, SystemRepositories},
repositories::{
EventSourcedConfigRepository, InMemoryAccessTokenRepository, InMemoryArticleRepository,
InMemoryCreatorRepository, InMemoryEventStreamRepository, InMemoryForkRepository,
InMemoryTransactionRepository,
},
},
};
use std::sync::Arc;
#[derive(Default)]
pub struct ContainerBuilder {
creator_repository: Option<Arc<dyn CreatorRepository>>,
article_repository: Option<Arc<dyn ArticleRepository>>,
transaction_repository: Option<Arc<dyn TransactionRepository>>,
access_token_repository: Option<Arc<dyn AccessTokenRepository>>,
fork_repository: Option<Arc<dyn ForkRepository>>,
event_stream_repository: Option<Arc<dyn EventStreamRepository>>,
tenant_repository: Option<Arc<dyn TenantRepository>>,
audit_repository: Option<Arc<dyn AuditEventRepository>>,
config_repository: Option<Arc<EventSourcedConfigRepository>>,
system_store: Option<Arc<SystemMetadataStore>>,
consumer_registry: Option<Arc<ConsumerRegistry>>,
}
impl ContainerBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_in_memory_repositories(mut self) -> Self {
self.creator_repository = Some(Arc::new(InMemoryCreatorRepository::new()));
self.article_repository = Some(Arc::new(InMemoryArticleRepository::new()));
self.transaction_repository = Some(Arc::new(InMemoryTransactionRepository::new()));
self.access_token_repository = Some(Arc::new(InMemoryAccessTokenRepository::new()));
self.fork_repository = Some(Arc::new(InMemoryForkRepository::new()));
self.event_stream_repository = Some(Arc::new(InMemoryEventStreamRepository::new()));
self
}
pub fn with_creator_repository(mut self, repository: Arc<dyn CreatorRepository>) -> Self {
self.creator_repository = Some(repository);
self
}
pub fn with_article_repository(mut self, repository: Arc<dyn ArticleRepository>) -> Self {
self.article_repository = Some(repository);
self
}
pub fn with_transaction_repository(
mut self,
repository: Arc<dyn TransactionRepository>,
) -> Self {
self.transaction_repository = Some(repository);
self
}
pub fn with_access_token_repository(
mut self,
repository: Arc<dyn AccessTokenRepository>,
) -> Self {
self.access_token_repository = Some(repository);
self
}
pub fn with_fork_repository(mut self, repository: Arc<dyn ForkRepository>) -> Self {
self.fork_repository = Some(repository);
self
}
pub fn with_event_stream_repository(
mut self,
repository: Arc<dyn EventStreamRepository>,
) -> Self {
self.event_stream_repository = Some(repository);
self
}
pub fn with_system_repositories(mut self, repos: SystemRepositories) -> Self {
self.system_store = Some(repos.system_store);
self.tenant_repository = Some(repos.tenant_repository);
self.audit_repository = Some(repos.audit_repository);
self.config_repository = Some(repos.config_repository);
self.consumer_registry = Some(repos.consumer_registry);
self
}
pub fn with_tenant_repository(mut self, repository: Arc<dyn TenantRepository>) -> Self {
self.tenant_repository = Some(repository);
self
}
pub fn with_audit_repository(mut self, repository: Arc<dyn AuditEventRepository>) -> Self {
self.audit_repository = Some(repository);
self
}
pub fn build(self) -> ServiceContainer {
let mut container = ServiceContainer::new(
self.creator_repository
.expect("CreatorRepository not configured. Use with_in_memory_repositories() or with_creator_repository()"),
self.article_repository
.expect("ArticleRepository not configured. Use with_in_memory_repositories() or with_article_repository()"),
self.transaction_repository
.expect("TransactionRepository not configured. Use with_in_memory_repositories() or with_transaction_repository()"),
self.access_token_repository
.expect("AccessTokenRepository not configured. Use with_in_memory_repositories() or with_access_token_repository()"),
self.fork_repository
.expect("ForkRepository not configured. Use with_in_memory_repositories() or with_fork_repository()"),
self.event_stream_repository
.expect("EventStreamRepository not configured. Use with_in_memory_repositories() or with_event_stream_repository()"),
);
container.tenant_repository = self.tenant_repository;
container.audit_repository = self.audit_repository;
container.config_repository = self.config_repository;
container.system_store = self.system_store;
container.consumer_registry = self.consumer_registry;
container
}
pub fn try_build(self) -> Result<ServiceContainer, ContainerBuilderError> {
let mut container = ServiceContainer::new(
self.creator_repository
.ok_or(ContainerBuilderError::MissingRepository(
"CreatorRepository",
))?,
self.article_repository
.ok_or(ContainerBuilderError::MissingRepository(
"ArticleRepository",
))?,
self.transaction_repository
.ok_or(ContainerBuilderError::MissingRepository(
"TransactionRepository",
))?,
self.access_token_repository
.ok_or(ContainerBuilderError::MissingRepository(
"AccessTokenRepository",
))?,
self.fork_repository
.ok_or(ContainerBuilderError::MissingRepository("ForkRepository"))?,
self.event_stream_repository
.ok_or(ContainerBuilderError::MissingRepository(
"EventStreamRepository",
))?,
);
container.tenant_repository = self.tenant_repository;
container.audit_repository = self.audit_repository;
container.config_repository = self.config_repository;
container.system_store = self.system_store;
container.consumer_registry = self.consumer_registry;
Ok(container)
}
}
#[derive(Debug, Clone)]
pub enum ContainerBuilderError {
MissingRepository(&'static str),
}
impl std::fmt::Display for ContainerBuilderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ContainerBuilderError::MissingRepository(name) => {
write!(f, "{name} not configured")
}
}
}
}
impl std::error::Error for ContainerBuilderError {}