about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2021-05-04 21:06:24 +0300
committerVika <vika@fireburn.ru>2021-05-04 21:07:39 +0300
commit12a4906117349fa518e4be5550bd8901941abcf0 (patch)
treedeefc3766df9aaee563cbfdf52108f4bc323c233
parent7024cbefb27e1c9649bff57df32b316484de4104 (diff)
downloadkittybox-12a4906117349fa518e4be5550bd8901941abcf0.tar.zst
Implemented MemoryStorage::update_post()
-rw-r--r--src/database/memory.rs83
-rw-r--r--src/database/mod.rs2
2 files changed, 84 insertions, 1 deletions
diff --git a/src/database/memory.rs b/src/database/memory.rs
index a4cf5a9..d1a69a2 100644
--- a/src/database/memory.rs
+++ b/src/database/memory.rs
@@ -21,7 +21,88 @@ impl Storage for MemoryStorage {
     }
 
     async fn update_post<'a>(&self, url: &'a str, update: serde_json::Value) -> Result<()> {
-        todo!()
+        let mut add_keys: HashMap<String, serde_json::Value> = HashMap::new();
+        let mut remove_keys: Vec<String> = vec![];
+        let mut remove_values: HashMap<String, Vec<serde_json::Value>> = HashMap::new();
+
+        if let Some(delete) = update["delete"].as_array() {
+            remove_keys.extend(delete.iter().filter_map(|v| v.as_str()).map(|v| v.to_string()));
+        } else if let Some(delete) = update["delete"].as_object() {
+            for (k, v) in delete {
+                if let Some(v) = v.as_array() {
+                    remove_values.entry(k.to_string()).or_default().extend(v.clone());
+                } else {
+                    return Err(StorageError::new(ErrorKind::BadRequest, "Malformed update object"));
+                }
+            }
+        }
+        if let Some(add) = update["add"].as_object() {
+            for (k, v) in add {
+                if v.is_array() {
+                    add_keys.insert(k.to_string(), v.clone());
+                } else {
+                    return Err(StorageError::new(ErrorKind::BadRequest, "Malformed update object"));
+                }
+            }
+        }
+        if let Some(replace) = update["replace"].as_object() {
+            for (k, v) in replace {
+                remove_keys.push(k.to_string());
+                add_keys.insert(k.to_string(), v.clone());
+            }
+        }
+        let mut mapping = self.mapping.write().await;
+        if let Some(mut post) = mapping.get(url) {
+            if let Some(url) = post["see_other"].as_str() {
+                if let Some(new_post) = mapping.get(url) {
+                    post = new_post
+                } else {
+                    return Err(StorageError::new(ErrorKind::NotFound, "The post you have requested is not found in the database."));
+                }
+            }
+            let mut post = post.clone();
+            for k in remove_keys {
+                post["properties"].as_object_mut().unwrap().remove(&k);
+            }
+            for (k, v) in remove_values {
+                let k = &k;
+                let props;
+                if k == "children" {
+                    props = &mut post;
+                } else {
+                    props = &mut post["properties"];
+                }
+                v.iter().for_each(|v| {
+                    if let Some(vec) = props[k].as_array_mut() {
+                        if let Some(index) = vec.iter().position(|w| w == v) {
+                            vec.remove(index);
+                        }
+                    }
+                });
+            }
+            for (k, v) in add_keys {
+                let props;
+                if k == "children" {
+                    props = &mut post;
+                } else {
+                    props = &mut post["properties"];
+                }
+                let k = &k;
+                if let Some(prop) = props[k].as_array_mut() {
+                    if k == "children" {
+                        v.as_array().unwrap().iter().cloned().rev().for_each(|v| prop.insert(0, v));
+                    } else {
+                        prop.extend(v.as_array().unwrap().iter().cloned());
+                    }
+                } else {
+                    post["properties"][k] = v
+                }
+            }
+            mapping.insert(post["properties"]["uid"][0].as_str().unwrap().to_string(), post);
+        } else {
+            return Err(StorageError::new(ErrorKind::NotFound, "The designated post wasn't found in the database."));
+        }
+        Ok(())
     }
 
     async fn delete_post<'a>(&self, url: &'a str) -> Result<()> {
diff --git a/src/database/mod.rs b/src/database/mod.rs
index 6abe72c..82bbea5 100644
--- a/src/database/mod.rs
+++ b/src/database/mod.rs
@@ -24,6 +24,7 @@ pub enum ErrorKind {
     PermissionDenied,
     JSONParsing,
     NotFound,
+    BadRequest,
     Other
 }
 
@@ -56,6 +57,7 @@ impl std::fmt::Display for StorageError {
             ErrorKind::JSONParsing => write!(f, "error while parsing JSON: "),
             ErrorKind::PermissionDenied => write!(f, "permission denied: "),
             ErrorKind::NotFound => write!(f, "not found: "),
+            ErrorKind::BadRequest => write!(f, "bad request: "),
             ErrorKind::Other => write!(f, "generic storage layer error: ")
         } {
             Ok(_) => write!(f, "{}", self.msg),