stateset_embedded/commerce/
builder.rs1#[cfg(feature = "postgres")]
2use super::block_on_postgres_connect_with_options;
3use super::{Commerce, CommerceBackend};
4
5use std::sync::Arc;
6
7use stateset_core::CommerceError;
8use stateset_db::Database;
9use stateset_observability::{MetricsConfig, init_metrics};
10
11#[cfg(feature = "events")]
12use crate::events::{EventConfig, EventSystem};
13
14#[cfg(feature = "sqlite")]
15use stateset_db::{DatabaseConfig, SqliteDatabase};
16
17#[derive(Default)]
19#[must_use]
20pub struct CommerceBuilder {
21 #[cfg(feature = "sqlite")]
22 sqlite_path: Option<String>,
23 #[cfg(feature = "postgres")]
24 postgres_url: Option<String>,
25 max_connections: Option<u32>,
26 #[cfg(feature = "postgres")]
27 acquire_timeout_secs: Option<u64>,
28 #[cfg(feature = "events")]
29 event_config: Option<EventConfig>,
30 metrics_config: MetricsConfig,
31}
32
33impl std::fmt::Debug for CommerceBuilder {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 f.debug_struct("CommerceBuilder").finish_non_exhaustive()
36 }
37}
38
39impl CommerceBuilder {
40 pub fn new() -> Self {
42 Self::default()
43 }
44
45 #[cfg(feature = "sqlite")]
47 pub fn sqlite(mut self, path: &str) -> Self {
48 self.sqlite_path = Some(path.to_string());
49 self
50 }
51
52 #[cfg(feature = "sqlite")]
54 pub fn database(self, path: &str) -> Self {
55 self.sqlite(path)
56 }
57
58 #[cfg(feature = "sqlite")]
60 pub fn in_memory(mut self) -> Self {
61 self.sqlite_path = Some(":memory:".to_string());
62 self
63 }
64
65 #[cfg(feature = "postgres")]
70 pub fn postgres(mut self, url: &str) -> Self {
71 self.postgres_url = Some(url.to_string());
72 self
73 }
74
75 pub const fn max_connections(mut self, count: u32) -> Self {
77 self.max_connections = Some(count);
78 self
79 }
80
81 pub const fn metrics_config(mut self, config: MetricsConfig) -> Self {
83 self.metrics_config = config;
84 self
85 }
86
87 pub const fn disable_metrics(mut self) -> Self {
89 self.metrics_config.enabled = false;
90 self
91 }
92
93 #[cfg(feature = "postgres")]
95 pub const fn acquire_timeout_secs(mut self, secs: u64) -> Self {
96 self.acquire_timeout_secs = Some(secs);
97 self
98 }
99
100 #[cfg(feature = "events")]
118 pub fn event_config(mut self, config: EventConfig) -> Self {
119 self.event_config = Some(config);
120 self
121 }
122
123 #[cfg(feature = "sqlite")]
138 pub fn build_with_defaults(self) -> Result<Commerce, CommerceError> {
139 self.in_memory().build()
140 }
141
142 pub fn build(self) -> Result<Commerce, CommerceError> {
144 let metrics = init_metrics(self.metrics_config.clone());
145
146 #[cfg(feature = "events")]
148 let event_system =
149 Arc::new(self.event_config.map(EventSystem::with_config).unwrap_or_default());
150
151 #[cfg(feature = "postgres")]
153 if let Some(url) = self.postgres_url {
154 let max_connections = self.max_connections.unwrap_or(10);
155 let acquire_timeout_secs = self.acquire_timeout_secs.unwrap_or(30);
156 let db =
157 block_on_postgres_connect_with_options(url, max_connections, acquire_timeout_secs)?;
158 let db: Arc<dyn Database> = Arc::new(db);
159
160 return Ok(Commerce {
161 db,
162 backend: CommerceBackend::Postgres,
163 metrics,
164 #[cfg(feature = "events")]
165 event_system,
166 #[cfg(feature = "sqlite")]
167 sqlite_db: None,
168 #[cfg(feature = "sqlite")]
169 sqlite_path: None,
170 });
171 }
172
173 #[cfg(all(feature = "postgres", not(feature = "sqlite")))]
174 return Err(CommerceError::Internal(
175 "PostgreSQL URL is required when the sqlite feature is disabled".to_string(),
176 ));
177
178 #[cfg(feature = "sqlite")]
180 {
181 let path = self.sqlite_path.unwrap_or_else(|| "stateset.db".to_string());
182
183 let mut config = if path == ":memory:" {
184 DatabaseConfig::in_memory()
185 } else {
186 DatabaseConfig::sqlite(&path)
187 };
188 if let Some(max) = self.max_connections {
189 config.max_connections = max;
190 }
191
192 let sqlite_db = Arc::new(SqliteDatabase::new(&config)?);
193 let db: Arc<dyn Database> = sqlite_db.clone();
194 let file_path = (path != ":memory:").then(|| path.clone());
195 Ok(Commerce {
196 db,
197 backend: CommerceBackend::Sqlite,
198 metrics,
199 #[cfg(feature = "events")]
200 event_system,
201 #[cfg(feature = "sqlite")]
202 sqlite_db: Some(sqlite_db),
203 #[cfg(feature = "sqlite")]
204 sqlite_path: file_path,
205 })
206 }
207
208 #[cfg(not(any(feature = "sqlite", feature = "postgres")))]
209 Err(CommerceError::Internal(
210 "No database backend enabled. Enable 'sqlite' or 'postgres' feature.".to_string(),
211 ))
212 }
213}