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