about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--kittybox-rs/src/database/memory.rs71
1 files changed, 70 insertions, 1 deletions
diff --git a/kittybox-rs/src/database/memory.rs b/kittybox-rs/src/database/memory.rs
index ce98d05..26d3095 100644
--- a/kittybox-rs/src/database/memory.rs
+++ b/kittybox-rs/src/database/memory.rs
@@ -89,7 +89,76 @@ impl Storage for MemoryStorage {
     }
 
     async fn update_post(&self, url: &'_ str, update: crate::micropub::MicropubUpdate) -> Result<()> {
-        todo!()
+        let mut guard = self.mapping.write().await;
+        let mut post = guard.get_mut(url).ok_or(StorageError::from_static(ErrorKind::NotFound, "The specified post wasn't found in the database."))?;
+
+        use crate::micropub::MicropubPropertyDeletion;
+
+        let mut add_keys: HashMap<String, Vec<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(MicropubPropertyDeletion::Properties(delete)) = update.delete {
+            remove_keys.extend(delete.iter().cloned());
+        } else if let Some(MicropubPropertyDeletion::Values(delete)) = update.delete {
+            for (k, v) in delete {
+                remove_values
+                    .entry(k.to_string())
+                    .or_default()
+                    .extend(v.clone());
+            }
+        }
+        if let Some(add) = update.add {
+            for (k, v) in add {
+                add_keys.insert(k.to_string(), v.clone());
+            }
+        }
+        if let Some(replace) = update.replace {
+            for (k, v) in replace {
+                remove_keys.push(k.to_string());
+                add_keys.insert(k.to_string(), v.clone());
+            }
+        }
+
+        if let Some(props) = post["properties"].as_object_mut() {
+            for k in remove_keys {
+                props.remove(&k);
+            }
+        }
+        for (k, v) in remove_values {
+            let k = &k;
+            let props = if k == "children" {
+                &mut post
+            } else {
+                &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 {
+            tracing::debug!("Adding k/v to post: {} => {:?}", k, v);
+            let props = if k == "children" {
+                &mut post
+            } else {
+                &mut post["properties"]
+            };
+            if let Some(prop) = props[&k].as_array_mut() {
+                if k == "children" {
+                    v.into_iter().rev().for_each(|v| prop.insert(0, v));
+                } else {
+                    prop.extend(v.into_iter());
+                }
+            } else {
+                props[&k] = serde_json::Value::Array(v)
+            }
+        }
+
+        Ok(())
     }
 
     async fn get_channels(&self, user: &'_ str) -> Result<Vec<MicropubChannel>> {