1#[cfg(feature = "postgres")]
16pub mod postgres;
17#[cfg(feature = "sqlite")]
18pub mod sqlite;
19
20use std::str::FromStr;
21
22#[cfg(feature = "diesel")]
23use diesel::r2d2::{ConnectionManager, Pool};
24
25#[cfg(feature = "batch-store")]
26use crate::batches::store::BatchStore;
27use crate::commits::store::CommitStore;
28use crate::error::InternalError;
29#[cfg(feature = "location")]
30use crate::location::store::LocationStore;
31#[cfg(feature = "pike")]
32use crate::pike::store::PikeStore;
33#[cfg(feature = "product")]
34use crate::product::store::ProductStore;
35#[cfg(feature = "purchase-order")]
36use crate::purchase_order::store::PurchaseOrderStore;
37#[cfg(feature = "schema")]
38use crate::schema::store::SchemaStore;
39#[cfg(feature = "track-and-trace")]
40use crate::track_and_trace::store::TrackAndTraceStore;
41
42pub trait StoreFactory {
44 fn get_grid_commit_store<'a>(&'a self) -> Box<dyn CommitStore + 'a>;
46 #[cfg(feature = "pike")]
48 fn get_grid_pike_store<'a>(&'a self) -> Box<dyn PikeStore + 'a>;
49 #[cfg(feature = "location")]
51 fn get_grid_location_store<'a>(&'a self) -> Box<dyn LocationStore + 'a>;
52 #[cfg(feature = "product")]
54 fn get_grid_product_store<'a>(&'a self) -> Box<dyn ProductStore + 'a>;
55 #[cfg(feature = "schema")]
57 fn get_grid_schema_store<'a>(&'a self) -> Box<dyn SchemaStore + 'a>;
58 #[cfg(feature = "track-and-trace")]
60 fn get_grid_track_and_trace_store<'a>(&'a self) -> Box<dyn TrackAndTraceStore + 'a>;
61 #[cfg(feature = "batch-store")]
62 fn get_batch_store<'a>(&'a self) -> Box<dyn BatchStore + 'a>;
63 #[cfg(feature = "purchase-order")]
64 fn get_grid_purchase_order_store<'a>(&'a self) -> Box<dyn PurchaseOrderStore + 'a>;
65}
66
67pub trait TransactionalStoreFactory: StoreFactory + Send + Sync {
68 fn begin_transaction<'a>(&self) -> Result<Box<dyn InContextStoreFactory<'a>>, InternalError>;
69
70 fn clone_box(&self) -> Box<dyn TransactionalStoreFactory>;
71}
72
73pub trait InContextStoreFactory<'a>: StoreFactory {
74 fn commit(&self) -> Result<(), InternalError>;
75
76 fn rollback(&self) -> Result<(), InternalError>;
77}
78
79pub fn create_store_factory(
86 connection_uri: &ConnectionUri,
87) -> Result<Box<dyn TransactionalStoreFactory>, InternalError> {
88 #[allow(clippy::match_single_binding)]
92 match connection_uri {
93 #[cfg(feature = "postgres")]
94 ConnectionUri::Postgres(url) => {
95 let connection_manager = ConnectionManager::<diesel::pg::PgConnection>::new(url);
96 let pool = Pool::builder().build(connection_manager).map_err(|err| {
97 InternalError::from_source_with_prefix(
98 Box::new(err),
99 "Failed to build connection pool".to_string(),
100 )
101 })?;
102 Ok(Box::new(postgres::PgStoreFactory::new(pool)))
103 }
104 #[cfg(feature = "sqlite")]
105 ConnectionUri::Sqlite(conn_str) => {
106 let connection_manager =
107 ConnectionManager::<diesel::sqlite::SqliteConnection>::new(conn_str);
108 let mut pool_builder = Pool::builder();
109 if conn_str == ":memory:" {
113 pool_builder = pool_builder.max_size(1);
114 }
115 let pool = pool_builder.build(connection_manager).map_err(|err| {
116 InternalError::from_source_with_prefix(
117 Box::new(err),
118 "Failed to build connection pool".to_string(),
119 )
120 })?;
121 Ok(Box::new(sqlite::SqliteStoreFactory::new(pool)))
122 }
123 #[cfg(all(not(feature = "sqlite"), not(feature = "postgres")))]
124 _ => Err(InternalError::with_message(
125 "No valid database connection URI".to_string(),
126 )),
127 }
128}
129
130#[derive(Clone)]
132pub enum ConnectionUri {
133 #[cfg(feature = "postgres")]
134 Postgres(String),
135 #[cfg(feature = "sqlite")]
136 Sqlite(String),
137}
138
139impl FromStr for ConnectionUri {
140 type Err = InternalError;
141
142 #[allow(clippy::match_single_binding)]
146 fn from_str(s: &str) -> Result<Self, Self::Err> {
147 match s {
148 #[cfg(feature = "postgres")]
149 _ if s.starts_with("postgres://") => Ok(ConnectionUri::Postgres(s.into())),
150 #[cfg(feature = "sqlite")]
151 _ => Ok(ConnectionUri::Sqlite(s.into())),
152 #[cfg(not(feature = "sqlite"))]
153 _ => Err(InternalError::with_message(format!(
154 "No compatible connection type: {}",
155 s
156 ))),
157 }
158 }
159}