Skip to main content

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}