stateset_embedded/commerce/constructors.rs
1use super::{Commerce, CommerceBackend, CommerceBuilder};
2#[cfg(feature = "postgres")]
3use super::{block_on_postgres_connect, block_on_postgres_connect_with_options};
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::EventSystem;
13
14#[cfg(feature = "sqlite")]
15use stateset_db::{DatabaseConfig, SqliteDatabase};
16
17impl Commerce {
18 /// Create a new Commerce instance with a SQLite database.
19 ///
20 /// # Arguments
21 ///
22 /// * `path` - Path to the SQLite database file. Creates if not exists.
23 ///
24 /// # Example
25 ///
26 /// ```rust,ignore
27 /// use stateset_embedded::Commerce;
28 ///
29 /// // File-based database
30 /// let commerce = Commerce::new("./my-store.db")?;
31 ///
32 /// // In-memory database (useful for testing)
33 /// let commerce = Commerce::new(":memory:")?;
34 /// # Ok::<(), stateset_embedded::CommerceError>(())
35 /// ```
36 #[cfg(feature = "sqlite")]
37 pub fn new(path: &str) -> Result<Self, CommerceError> {
38 let config = if path == ":memory:" {
39 DatabaseConfig::in_memory()
40 } else {
41 DatabaseConfig::sqlite(path)
42 };
43
44 let sqlite_db = Arc::new(SqliteDatabase::new(&config)?);
45 let db: Arc<dyn Database> = sqlite_db.clone();
46 let file_path = (path != ":memory:").then(|| path.to_owned());
47 let metrics = init_metrics(MetricsConfig::default());
48
49 Ok(Self {
50 db,
51 backend: CommerceBackend::Sqlite,
52 metrics,
53 #[cfg(feature = "events")]
54 event_system: Arc::new(EventSystem::new()),
55 #[cfg(feature = "sqlite")]
56 sqlite_db: Some(sqlite_db),
57 #[cfg(feature = "sqlite")]
58 sqlite_path: file_path,
59 })
60 }
61
62 // ========================================================================
63 // Convenience Constructors
64 // ========================================================================
65
66 /// Create a Commerce instance with SQLite (convenience method).
67 ///
68 /// This is an alias for `Commerce::new()` with a clearer name.
69 ///
70 /// # Example
71 ///
72 /// ```rust,ignore
73 /// use stateset_embedded::Commerce;
74 ///
75 /// let commerce = Commerce::sqlite("./store.db")?;
76 /// # Ok::<(), stateset_embedded::CommerceError>(())
77 /// ```
78 #[cfg(feature = "sqlite")]
79 pub fn sqlite(path: &str) -> Result<Self, CommerceError> {
80 Self::new(path)
81 }
82
83 /// Create a Commerce instance with an in-memory SQLite database.
84 ///
85 /// This is useful for testing or ephemeral data that doesn't need persistence.
86 ///
87 /// # Example
88 ///
89 /// ```rust,ignore
90 /// use stateset_embedded::Commerce;
91 ///
92 /// let commerce = Commerce::in_memory()?;
93 /// // Data will be lost when commerce is dropped
94 /// # Ok::<(), stateset_embedded::CommerceError>(())
95 /// ```
96 #[cfg(feature = "sqlite")]
97 pub fn in_memory() -> Result<Self, CommerceError> {
98 Self::new(":memory:")
99 }
100
101 /// Create a Commerce instance with SQLite and custom pool size.
102 ///
103 /// # Arguments
104 ///
105 /// * `path` - Path to the SQLite database file
106 /// * `max_connections` - Maximum number of connections in the pool
107 ///
108 /// # Example
109 ///
110 /// ```rust,ignore
111 /// use stateset_embedded::Commerce;
112 ///
113 /// // Create with larger connection pool for high concurrency
114 /// let commerce = Commerce::sqlite_pool("./store.db", 10)?;
115 /// # Ok::<(), stateset_embedded::CommerceError>(())
116 /// ```
117 #[cfg(feature = "sqlite")]
118 pub fn sqlite_pool(path: &str, max_connections: u32) -> Result<Self, CommerceError> {
119 Self::builder().sqlite(path).max_connections(max_connections).build()
120 }
121
122 /// Create a Commerce instance with PostgreSQL and custom pool size.
123 ///
124 /// # Arguments
125 ///
126 /// * `url` - PostgreSQL connection string
127 /// * `max_connections` - Maximum number of connections in the pool
128 ///
129 /// # Example
130 ///
131 /// ```rust,ignore
132 /// use stateset_embedded::Commerce;
133 ///
134 /// let commerce = Commerce::postgres_pool(
135 /// "postgres://user:pass@localhost/db",
136 /// 20,
137 /// )?;
138 /// # Ok::<(), stateset_embedded::CommerceError>(())
139 /// ```
140 #[cfg(feature = "postgres")]
141 pub fn postgres_pool(url: &str, max_connections: u32) -> Result<Self, CommerceError> {
142 Self::with_postgres_options(url, max_connections, 30)
143 }
144
145 /// Create a Commerce instance connected to PostgreSQL.
146 ///
147 /// This requires the `postgres` feature to be enabled and performs
148 /// synchronous initialization without panicking inside existing runtimes.
149 ///
150 /// # Arguments
151 ///
152 /// * `url` - PostgreSQL connection string (e.g., `<postgres://user:pass@localhost/db>`)
153 ///
154 /// # Example
155 ///
156 /// ```rust,ignore
157 /// use stateset_embedded::Commerce;
158 ///
159 /// let commerce = Commerce::with_postgres("postgres://localhost/stateset")?;
160 /// # Ok::<(), stateset_embedded::CommerceError>(())
161 /// ```
162 #[cfg(feature = "postgres")]
163 pub fn with_postgres(url: &str) -> Result<Self, CommerceError> {
164 let url = url.to_owned();
165 let db = block_on_postgres_connect(url)?;
166 let db: Arc<dyn Database> = Arc::new(db);
167 let metrics = init_metrics(MetricsConfig::default());
168
169 Ok(Self {
170 db,
171 backend: CommerceBackend::Postgres,
172 metrics,
173 #[cfg(feature = "events")]
174 event_system: Arc::new(EventSystem::new()),
175 #[cfg(feature = "sqlite")]
176 sqlite_db: None,
177 #[cfg(feature = "sqlite")]
178 sqlite_path: None,
179 })
180 }
181
182 /// Create a Commerce instance connected to PostgreSQL with custom options.
183 ///
184 /// # Arguments
185 ///
186 /// * `url` - PostgreSQL connection string
187 /// * `max_connections` - Maximum number of connections in the pool
188 /// * `acquire_timeout_secs` - Timeout in seconds for acquiring a connection
189 ///
190 /// # Example
191 ///
192 /// ```rust,ignore
193 /// use stateset_embedded::Commerce;
194 ///
195 /// let commerce = Commerce::with_postgres_options(
196 /// "postgres://localhost/stateset",
197 /// 20, // max connections
198 /// 60, // timeout in seconds
199 /// )?;
200 /// # Ok::<(), stateset_embedded::CommerceError>(())
201 /// ```
202 #[cfg(feature = "postgres")]
203 pub fn with_postgres_options(
204 url: &str,
205 max_connections: u32,
206 acquire_timeout_secs: u64,
207 ) -> Result<Self, CommerceError> {
208 let url = url.to_owned();
209 let db =
210 block_on_postgres_connect_with_options(url, max_connections, acquire_timeout_secs)?;
211 let db: Arc<dyn Database> = Arc::new(db);
212 let metrics = init_metrics(MetricsConfig::default());
213
214 Ok(Self {
215 db,
216 backend: CommerceBackend::Postgres,
217 metrics,
218 #[cfg(feature = "events")]
219 event_system: Arc::new(EventSystem::new()),
220 #[cfg(feature = "sqlite")]
221 sqlite_db: None,
222 #[cfg(feature = "sqlite")]
223 sqlite_path: None,
224 })
225 }
226
227 /// Create a Commerce instance with a pre-connected database.
228 ///
229 /// This is useful when you want to manage the database connection yourself.
230 /// Note: Tax operations and vector search will not be available when using this method.
231 pub fn with_database(db: Arc<dyn Database>) -> Self {
232 let metrics = init_metrics(MetricsConfig::default());
233 Self {
234 db,
235 backend: CommerceBackend::External,
236 metrics,
237 #[cfg(feature = "events")]
238 event_system: Arc::new(EventSystem::new()),
239 #[cfg(feature = "sqlite")]
240 sqlite_db: None,
241 #[cfg(feature = "sqlite")]
242 sqlite_path: None,
243 }
244 }
245
246 /// Create a Commerce instance with custom configuration.
247 ///
248 /// Use `CommerceBuilder` for more control over initialization.
249 pub fn builder() -> CommerceBuilder {
250 CommerceBuilder::default()
251 }
252}