1use dyn_clonable::*;
2use std::{collections::HashMap, path::PathBuf};
3
4pub enum Namespace {
12 OCA,
13 OCABundlesJSON,
15 OCAObjectsJSON,
17 CoreModel,
18 OCARelations,
19 OCAReferences,
20}
21
22impl Namespace {
23 pub fn as_str(&self) -> &'static str {
24 match self {
25 Self::OCA => "oca",
26 Self::OCABundlesJSON => "oca_bundles_json",
27 Self::OCAObjectsJSON => "oca_objects_json",
28 Self::CoreModel => "core_model",
29 Self::OCARelations => "oca_relations",
30 Self::OCAReferences => "oca_refs",
31 }
32 }
33}
34
35#[clonable]
36pub trait DataStorage: Clone + Send {
37 fn get(&self, namespace: Namespace, key: &str) -> Result<Option<Vec<u8>>, String>;
38 fn get_all(&self, namespace: Namespace) -> Result<HashMap<String, Vec<u8>>, String>;
39 fn insert(&mut self, namespace: Namespace, key: &str, value: &[u8]) -> Result<(), String>;
40 fn new() -> Self
41 where
42 Self: Sized;
43 fn config(&self, config: HashMap<String, String>) -> Self
44 where
45 Self: Sized;
46 fn open(_path: &str) -> Self
47 where
48 Self: Sized,
49 {
50 panic!("DEPRECATED: use new() and config() instead of open()");
51 }
52}
53
54#[derive(Clone)]
55pub struct SledDataStorage {
56 db: Option<sled::Db>,
57}
58
59#[derive(Clone)]
60pub struct SledDataStorageConfig {
61 pub path: String,
62}
63
64impl SledDataStorageConfig {
65 pub fn build() -> SledDataStorageConfigBuilder {
66 SledDataStorageConfigBuilder { path: None }
67 }
68}
69
70pub struct SledDataStorageConfigBuilder {
71 path: Option<PathBuf>,
72}
73
74impl SledDataStorageConfigBuilder {
75 pub fn path(mut self, path: PathBuf) -> Self {
76 self.path = Some(path);
77 self
78 }
79
80 pub fn finalize(&self) -> Result<HashMap<String, String>, String> {
81 let mut config = HashMap::new();
82
83 match &self.path {
84 Some(path) => config.insert(
85 "path".to_string(),
86 path.clone()
87 .into_os_string()
88 .into_string()
89 .map_err(|e| e.into_string().unwrap())?,
90 ),
91 None => return Err("path is required".to_string()),
92 };
93
94 Ok(config)
95 }
96
97 pub fn unwrap(&self) -> HashMap<String, String> {
98 self.finalize().unwrap()
99 }
100}
101
102impl DataStorage for SledDataStorage {
103 fn new() -> Self {
104 Self { db: None }
105 }
106
107 fn config(&self, config: HashMap<String, String>) -> Self {
108 if let Some(path) = config.get("path")
109 && let Ok(db) = sled::open(path)
110 {
111 return Self { db: Some(db) };
112 }
113 self.clone()
114 }
115
116 fn get(&self, namespace: Namespace, key: &str) -> Result<Option<Vec<u8>>, String> {
117 if let Some(ref db) = self.db {
118 let tree = db.open_tree(namespace.as_str().as_bytes()).unwrap();
119 match tree.get(key.as_bytes()).unwrap() {
120 Some(value) => Ok(Some(value.to_vec())),
121 None => Ok(None),
122 }
123 } else {
124 Err("Data Storage must be opened first".to_string())
125 }
126 }
127
128 fn get_all(&self, namespace: Namespace) -> Result<HashMap<String, Vec<u8>>, String> {
129 if let Some(ref db) = self.db {
130 let mut all = HashMap::new();
131 let tree = db.open_tree(namespace.as_str().as_bytes()).unwrap();
132 let mut iter = tree.iter();
133 while let Some(Ok((key, value))) = iter.next() {
134 all.insert(String::from_utf8(key.to_vec()).unwrap(), value.to_vec());
135 }
136
137 Ok(all)
138 } else {
139 Err("Data Storage must be opened first".to_string())
140 }
141 }
142
143 fn insert(&mut self, namespace: Namespace, key: &str, value: &[u8]) -> Result<(), String> {
144 if let Some(ref db) = self.db {
145 let tree = db.open_tree(namespace.as_str().as_bytes()).unwrap();
146 match tree.insert(key.as_bytes(), value) {
147 Ok(_) => Ok(()),
148 Err(e) => Err(e.to_string()),
149 }
150 } else {
151 Err("Data Storage must be opened first".to_string())
152 }
153 }
154}
155
156#[derive(Clone)]
157pub struct InMemoryDataStorage {
158 db: HashMap<String, HashMap<String, Vec<u8>>>,
159}
160
161impl DataStorage for InMemoryDataStorage {
162 fn new() -> Self {
163 Self { db: HashMap::new() }
164 }
165
166 fn config(&self, _config: HashMap<String, String>) -> Self {
167 self.clone()
168 }
169
170 fn get(&self, namespace: Namespace, key: &str) -> Result<Option<Vec<u8>>, String> {
171 let namespace_storage = match self.db.get(namespace.as_str()) {
172 Some(namespace_storage) => namespace_storage,
173 None => return Ok(None),
174 };
175 match namespace_storage.get(key) {
176 Some(value) => Ok(Some(value.to_vec())),
177 None => Ok(None),
178 }
179 }
180
181 fn get_all(&self, namespace: Namespace) -> Result<HashMap<String, Vec<u8>>, String> {
182 match self.db.get(namespace.as_str()) {
183 Some(namespace_storage) => Ok(namespace_storage.clone()),
184 None => Ok(HashMap::new()),
185 }
186 }
187
188 fn insert(&mut self, namespace: Namespace, key: &str, value: &[u8]) -> Result<(), String> {
189 let mut namespace_storage = match self.db.get(namespace.as_str()) {
190 Some(namespace_storage) => namespace_storage.clone(),
191 None => HashMap::new(),
192 };
193 namespace_storage.insert(key.to_string(), value.to_vec());
194 self.db
195 .insert(namespace.as_str().to_string(), namespace_storage);
196
197 Ok(())
198 }
199}
200
201#[derive(Clone)]
202pub struct FileSystemStorage {
203 dir: Option<PathBuf>,
204}
205
206#[derive(Clone)]
207pub struct FileSystemStorageConfig {
208 pub path: String,
209}
210
211impl FileSystemStorageConfig {
212 pub fn build() -> FileSystemStorageConfigBuilder {
213 FileSystemStorageConfigBuilder { path: None }
214 }
215}
216
217pub struct FileSystemStorageConfigBuilder {
218 path: Option<PathBuf>,
219}
220
221impl FileSystemStorageConfigBuilder {
222 pub fn path(mut self, path: PathBuf) -> Self {
223 self.path = Some(path);
224 self
225 }
226
227 pub fn finalize(&self) -> Result<HashMap<String, String>, String> {
228 let mut config = HashMap::new();
229
230 match &self.path {
231 Some(path) => config.insert(
232 "path".to_string(),
233 path.clone()
234 .into_os_string()
235 .into_string()
236 .map_err(|e| e.into_string().unwrap())?,
237 ),
238 None => return Err("path is required".to_string()),
239 };
240
241 Ok(config)
242 }
243
244 pub fn unwrap(&self) -> HashMap<String, String> {
245 self.finalize().unwrap()
246 }
247}
248
249impl DataStorage for FileSystemStorage {
250 fn new() -> Self {
251 Self { dir: None }
252 }
253
254 fn config(&self, config: HashMap<String, String>) -> Self {
255 if let Some(path) = config.get("path") {
256 return Self {
257 dir: Some(PathBuf::from(path)),
258 };
259 }
260 self.clone()
261 }
262
263 fn get(&self, namespace: Namespace, key: &str) -> Result<Option<Vec<u8>>, String> {
264 if let Some(ref dir) = self.dir {
265 let mut path = dir.clone();
266 path.push(namespace.as_str());
267 if path.try_exists().unwrap() {
268 path.push(key);
269 Ok(std::fs::read(path.clone()).ok())
270 } else {
271 Ok(None)
272 }
273 } else {
274 Err("File path is required".to_string())
275 }
276 }
277
278 fn get_all(&self, _namespace: Namespace) -> Result<HashMap<String, Vec<u8>>, String> {
279 Err("Not implemented".to_string())
280 }
281
282 fn insert(&mut self, namespace: Namespace, key: &str, value: &[u8]) -> Result<(), String> {
283 if let Some(ref dir) = self.dir {
284 let mut path = dir.clone();
285 path.push(namespace.as_str());
286 if !path.try_exists().unwrap() {
287 std::fs::create_dir_all(path.clone()).unwrap();
288 }
289
290 path.push(key);
291 std::fs::write(path.clone(), value).map_err(|e| e.to_string())
292 } else {
293 Err("File path is required".to_string())
294 }
295 }
296}