Skip to main content

oca_store/
data_storage.rs

1use dyn_clonable::*;
2use std::{collections::HashMap, path::PathBuf};
3
4/// Represents the namespace for data Storage
5///
6/// OCA - TODO
7/// OCAObjectsJSON - Json representation of OCA objects
8/// CoreModel - Core model of OCA
9/// OCARelations - Relations between OCA objects
10/// OCAReferences - References to OCA objects
11pub enum Namespace {
12    OCA,
13    /// Represents the namespace for OCA Bundle Model in JSON format
14    OCABundlesJSON,
15    /// Represents the namespace for OCA Objects (overlays and capture bases) in JSON format
16    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}