metabase_api_rs/repository/
factory.rs

1//! Repository factory for creating repository instances
2//!
3//! This module provides a factory pattern implementation for creating
4//! repository instances with proper dependency injection.
5
6use super::{
7    card::{CardRepository, HttpCardRepository, MockCardRepository},
8    collection::{CollectionRepository, HttpCollectionRepository, MockCollectionRepository},
9    dashboard::{DashboardRepository, HttpDashboardRepository, MockDashboardRepository},
10    query::{HttpQueryRepository, MockQueryRepository, QueryRepository},
11};
12use crate::transport::http_provider_safe::HttpProviderSafe;
13use std::sync::Arc;
14
15/// Repository configuration
16#[derive(Clone, Default)]
17pub struct RepositoryConfig {
18    /// Use mock repositories for testing
19    pub use_mocks: bool,
20    /// HTTP provider for real repositories
21    pub http_provider: Option<Arc<dyn HttpProviderSafe>>,
22}
23
24impl std::fmt::Debug for RepositoryConfig {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        f.debug_struct("RepositoryConfig")
27            .field("use_mocks", &self.use_mocks)
28            .field(
29                "http_provider",
30                &self.http_provider.as_ref().map(|_| "Arc<HttpProviderSafe>"),
31            )
32            .finish()
33    }
34}
35
36impl RepositoryConfig {
37    /// Create config for production use
38    pub fn production(http_provider: Arc<dyn HttpProviderSafe>) -> Self {
39        Self {
40            use_mocks: false,
41            http_provider: Some(http_provider),
42        }
43    }
44
45    /// Create config for testing
46    pub fn testing() -> Self {
47        Self {
48            use_mocks: true,
49            http_provider: None,
50        }
51    }
52}
53
54/// Factory for creating repository instances
55pub struct RepositoryFactory {
56    config: RepositoryConfig,
57}
58
59impl RepositoryFactory {
60    /// Create a new repository factory
61    pub fn new(config: RepositoryConfig) -> Self {
62        Self { config }
63    }
64
65    /// Create a card repository
66    pub fn create_card_repository(&self) -> Arc<dyn CardRepository> {
67        if self.config.use_mocks {
68            Arc::new(MockCardRepository::new())
69        } else {
70            let http_provider = self
71                .config
72                .http_provider
73                .as_ref()
74                .expect("HTTP provider required for non-mock repositories")
75                .clone();
76            Arc::new(HttpCardRepository::new(http_provider))
77        }
78    }
79
80    /// Create a collection repository
81    pub fn create_collection_repository(&self) -> Arc<dyn CollectionRepository> {
82        if self.config.use_mocks {
83            Arc::new(MockCollectionRepository::new())
84        } else {
85            let http_provider = self
86                .config
87                .http_provider
88                .as_ref()
89                .expect("HTTP provider required for non-mock repositories")
90                .clone();
91            Arc::new(HttpCollectionRepository::new(http_provider))
92        }
93    }
94
95    /// Create a dashboard repository
96    pub fn create_dashboard_repository(&self) -> Arc<dyn DashboardRepository> {
97        if self.config.use_mocks {
98            Arc::new(MockDashboardRepository::new())
99        } else {
100            let http_provider = self
101                .config
102                .http_provider
103                .as_ref()
104                .expect("HTTP provider required for non-mock repositories")
105                .clone();
106            Arc::new(HttpDashboardRepository::new(http_provider))
107        }
108    }
109
110    /// Create a query repository
111    pub fn create_query_repository(&self) -> Arc<dyn QueryRepository> {
112        if self.config.use_mocks {
113            Arc::new(MockQueryRepository::new())
114        } else {
115            let http_provider = self
116                .config
117                .http_provider
118                .as_ref()
119                .expect("HTTP provider required for non-mock repositories")
120                .clone();
121            Arc::new(HttpQueryRepository::new(http_provider))
122        }
123    }
124
125    /// Create all repositories at once
126    pub fn create_all(&self) -> RepositorySet {
127        RepositorySet {
128            card: self.create_card_repository(),
129            collection: self.create_collection_repository(),
130            dashboard: self.create_dashboard_repository(),
131            query: self.create_query_repository(),
132        }
133    }
134}
135
136/// A set of all repository instances
137pub struct RepositorySet {
138    /// Card repository
139    pub card: Arc<dyn CardRepository>,
140    /// Collection repository
141    pub collection: Arc<dyn CollectionRepository>,
142    /// Dashboard repository
143    pub dashboard: Arc<dyn DashboardRepository>,
144    /// Query repository
145    pub query: Arc<dyn QueryRepository>,
146}
147
148/// Builder for RepositoryFactory
149pub struct RepositoryFactoryBuilder {
150    use_mocks: bool,
151    http_provider: Option<Arc<dyn HttpProviderSafe>>,
152}
153
154impl Default for RepositoryFactoryBuilder {
155    fn default() -> Self {
156        Self::new()
157    }
158}
159
160impl RepositoryFactoryBuilder {
161    /// Create a new builder
162    pub fn new() -> Self {
163        Self {
164            use_mocks: false,
165            http_provider: None,
166        }
167    }
168
169    /// Use mock repositories
170    pub fn with_mocks(mut self) -> Self {
171        self.use_mocks = true;
172        self
173    }
174
175    /// Set HTTP provider
176    pub fn with_http_provider(mut self, provider: Arc<dyn HttpProviderSafe>) -> Self {
177        self.http_provider = Some(provider);
178        self.use_mocks = false;
179        self
180    }
181
182    /// Build the factory
183    pub fn build(self) -> RepositoryFactory {
184        let config = RepositoryConfig {
185            use_mocks: self.use_mocks,
186            http_provider: self.http_provider,
187        };
188        RepositoryFactory::new(config)
189    }
190}
191
192#[cfg(test)]
193mod tests {
194    use super::*;
195
196    #[test]
197    fn test_factory_with_mocks() {
198        let factory = RepositoryFactoryBuilder::new().with_mocks().build();
199
200        let repos = factory.create_all();
201
202        // Verify all repositories are created
203        // The actual functionality is tested through the trait implementations
204        let _ = repos.card;
205        let _ = repos.collection;
206        let _ = repos.dashboard;
207        let _ = repos.query;
208    }
209
210    #[test]
211    fn test_config_presets() {
212        let test_config = RepositoryConfig::testing();
213        assert!(test_config.use_mocks);
214        assert!(test_config.http_provider.is_none());
215
216        // Production config would require an actual HTTP provider
217        // which we can't test here without dependencies
218    }
219}