about summary refs log tree commit diff
path: root/kittybox-rs/src/database/file
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2023-06-15 17:02:39 +0300
committerVika <vika@fireburn.ru>2023-06-15 17:02:39 +0300
commiteca7687439c2b6f804603de75501b6737a82e5a2 (patch)
treea4715e0b8d3d63ee8b77830670c473b83a70031e /kittybox-rs/src/database/file
parent59f3e2d43d30642e4242039ce3ab934961e69602 (diff)
downloadkittybox-eca7687439c2b6f804603de75501b6737a82e5a2.tar.zst
Database: use newtypes to represent settings
This allows much for a cleaner and idiomatic settings interface.
Diffstat (limited to 'kittybox-rs/src/database/file')
-rw-r--r--kittybox-rs/src/database/file/mod.rs31
1 files changed, 14 insertions, 17 deletions
diff --git a/kittybox-rs/src/database/file/mod.rs b/kittybox-rs/src/database/file/mod.rs
index bafb7bf..9319b67 100644
--- a/kittybox-rs/src/database/file/mod.rs
+++ b/kittybox-rs/src/database/file/mod.rs
@@ -1,5 +1,5 @@
 //#![warn(clippy::unwrap_used)]
-use crate::database::{filter_post, ErrorKind, Result, Settings, Storage, StorageError};
+use crate::database::{filter_post, ErrorKind, Result, settings, Storage, StorageError};
 use async_trait::async_trait;
 use futures::{stream, StreamExt, TryStreamExt};
 use serde_json::json;
@@ -582,7 +582,7 @@ impl Storage for FileStorage {
     }
 
     #[tracing::instrument(skip(self))]
-    async fn get_setting(&self, setting: Settings, user: &'_ str) -> Result<String> {
+    async fn get_setting<S: settings::Setting<'a>, 'a>(&self, user: &'_ str) -> Result<S> {
         debug!("User for getting settings: {}", user);
         let url = axum::http::Uri::try_from(user).expect("Couldn't parse a URL");
         let mut path = relative_path::RelativePathBuf::new();
@@ -591,22 +591,20 @@ impl Storage for FileStorage {
 
         let path = path.to_path(&self.root_dir);
         debug!("Getting settings from {:?}", &path);
-        let setting = setting.to_string();
+
         let mut file = File::open(path).await?;
         let mut content = String::new();
         file.read_to_string(&mut content).await?;
 
-        let settings: HashMap<String, String> = serde_json::from_str(&content)?;
-        // XXX consider returning string slices instead of cloning a string every time
-        // it might come with a performance hit and/or memory usage inflation
-        settings
-            .get(&setting)
-            .cloned()
-            .ok_or_else(|| StorageError::new(ErrorKind::Backend, "Setting not set"))
+        let settings: HashMap<&str, serde_json::Value> = serde_json::from_str(&content)?;
+        match settings.get(S::ID) {
+            Some(value) => Ok(serde_json::from_value::<S>(value.clone())?),
+            None => Err(StorageError::new(ErrorKind::Backend, "Setting not set"))
+        }
     }
 
     #[tracing::instrument(skip(self))]
-    async fn set_setting(&self, setting: Settings, user: &'_ str, value: &'_ str) -> Result<()> {
+    async fn set_setting<S: settings::Setting<'a>, 'a>(&self, user: &'_ str, value: S::Data) -> Result<()> {
         let url = axum::http::Uri::try_from(user).expect("Couldn't parse a URL");
         let mut path = relative_path::RelativePathBuf::new();
         path.push(url.authority().unwrap().to_string());
@@ -620,33 +618,32 @@ impl Storage for FileStorage {
             tokio::fs::create_dir_all(path.parent().unwrap()).await?;
         }
 
-        let (setting, value) = (setting.to_string(), value.to_string());
-
         let mut tempfile = OpenOptions::new()
             .write(true)
             .create_new(true)
             .open(&temppath)
             .await?;
 
-        let mut settings: HashMap<String, String> = match File::open(&path).await {
+        let mut settings: HashMap<String, serde_json::Value> = match File::open(&path).await {
             Ok(mut f) => {
                 let mut content = String::new();
                 f.read_to_string(&mut content).await?;
                 if content.is_empty() {
-                    HashMap::default()
+                    Default::default()
                 } else {
                     serde_json::from_str(&content)?
                 }
             }
             Err(err) => {
                 if err.kind() == IOErrorKind::NotFound {
-                    HashMap::default()
+                    Default::default()
                 } else {
                     return Err(err.into());
                 }
             }
         };
-        settings.insert(setting, value);
+        settings.insert(S::ID.to_owned(), serde_json::to_value(S::new(value))?);
+
         tempfile
             .write_all(serde_json::to_string(&settings)?.as_bytes())
             .await?;