aboutsummaryrefslogtreecommitdiffstats
path: root/src/document
diff options
context:
space:
mode:
Diffstat (limited to 'src/document')
-rw-r--r--src/document/store.rs80
1 files changed, 30 insertions, 50 deletions
diff --git a/src/document/store.rs b/src/document/store.rs
index 9134795..b698d19 100644
--- a/src/document/store.rs
+++ b/src/document/store.rs
@@ -603,74 +603,54 @@ pub(crate) fn copy_path_to(
)
}
-/// Deletes the value at `path` as the API names it: through lists too, where a segment
-/// is an index (`list_index`; the items after it move down one); `prune` doesn't reach
-/// through a list. Within maps only, as `delete_path`.
-pub(crate) fn delete_at(
+/// Deletes the value at `path`, through lists too, where a segment is an index
+/// (`list_index`; the items after it move down one). With `prune`, the maps above it
+/// that it leaves empty go too, up to (not including) the root or a list.
+pub(crate) fn delete_path(
doc: &mut AutoCommit,
path: &[String],
prune: bool,
) -> Result<(), StoreError> {
let (leaf, parents) = path.split_last().ok_or(StoreError::NotFound)?;
- let mut current = Resolved::Maps(vec![automerge::ROOT]);
- let mut through_list = false;
+
+ // levels[d] = what path[..d] resolves to
+ let mut levels = vec![Resolved::Maps(vec![automerge::ROOT])];
for segment in parents {
- if let Resolved::Other(Value::Object(ObjType::List), _) = current {
- through_list = true;
- }
- current = step(doc, &current, segment, None)?.ok_or(StoreError::NotFound)?;
+ let next = step(doc, levels.last().expect("non-empty"), segment, None)?
+ .ok_or(StoreError::NotFound)?;
+ levels.push(next);
}
- match (&current, through_list) {
- (Resolved::Other(Value::Object(ObjType::List), list), _) => {
- let index = list_index(leaf).ok_or(StoreError::NotFound)?;
- if index >= doc.length(list) {
+
+ match levels.last().expect("non-empty") {
+ Resolved::Maps(maps) => {
+ if resolve(doc, maps, leaf, None)?.is_none() {
return Err(StoreError::NotFound);
}
- doc.delete(list, index)?;
- Ok(())
+ delete_in_all(doc, maps, leaf)?;
}
- (Resolved::Maps(maps), true) => {
- if resolve(doc, maps, leaf, None)?.is_none() {
+ Resolved::Other(Value::Object(ObjType::List), list) => {
+ let index = list_index(leaf).ok_or(StoreError::NotFound)?;
+ if index >= doc.length(list) {
return Err(StoreError::NotFound);
}
- delete_in_all(doc, maps, leaf)
+ doc.delete(list, index)?;
+ return Ok(());
}
- (Resolved::Maps(_), false) => delete_path(doc, path, prune),
- (Resolved::Other(..), _) => Err(StoreError::NotFound),
+ Resolved::Other(..) => return Err(StoreError::NotFound),
}
-}
-
-/// Deletes the value at `path`, optionally pruning ancestors that become empty.
-pub(crate) fn delete_path(
- doc: &mut AutoCommit,
- path: &[String],
- prune: bool,
-) -> Result<(), StoreError> {
- let (leaf, parents) = path.split_last().ok_or(StoreError::NotFound)?;
-
- // levels[d] = merged maps at path[..d]
- let mut levels = vec![vec![automerge::ROOT]];
- for segment in parents {
- let next = match resolve(doc, levels.last().expect("non-empty"), segment, None)? {
- Some(Resolved::Maps(maps)) => maps,
- _ => return Err(StoreError::NotFound),
- };
- levels.push(next);
- }
-
- let maps = levels.last().expect("non-empty");
- if resolve(doc, maps, leaf, None)?.is_none() {
- return Err(StoreError::NotFound);
- }
- delete_in_all(doc, maps, leaf)?;
if prune {
- // Never prune the root (depth 0).
+ // Never prune the root (depth 0), nor through a list.
for depth in (1..levels.len()).rev() {
- if !merged_keys(doc, &levels[depth]).is_empty() {
+ let (Resolved::Maps(above), Resolved::Maps(maps)) =
+ (&levels[depth - 1], &levels[depth])
+ else {
+ break;
+ };
+ if !merged_keys(doc, maps).is_empty() {
break;
}
- delete_in_all(doc, &levels[depth - 1], &path[depth - 1])?;
+ delete_in_all(doc, above, &path[depth - 1])?;
}
}
@@ -1051,7 +1031,7 @@ mod tests {
read_path(&doc, &path("list")).unwrap(),
Some(json!(["a", {"k": 2}, "d", "e"]))
);
- delete_at(&mut doc, &path("list/2"), false).unwrap();
+ delete_path(&mut doc, &path("list/2"), false).unwrap();
assert_eq!(
read_path(&doc, &path("list")).unwrap(),
Some(json!(["a", {"k": 2}, "e"]))