Skip to content

Commit f7a4d3b

Browse files
committed
feat(writer): add delete_note with soft and hard modes
1 parent 984ba3c commit f7a4d3b

1 file changed

Lines changed: 104 additions & 0 deletions

File tree

src/writer.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,83 @@ pub fn move_note(
11111111
})
11121112
}
11131113

1114+
// ── Delete ──────────────────────────────────────────────────────
1115+
1116+
#[derive(Debug, Clone)]
1117+
pub enum DeleteMode {
1118+
/// Move the file to the archive folder, update the store path.
1119+
Soft,
1120+
/// Remove the file from disk and purge all store data.
1121+
Hard,
1122+
}
1123+
1124+
/// Delete a note from the vault.
1125+
///
1126+
/// - `Soft`: move the file to `archive_folder` and update the store record (path only).
1127+
/// The note remains on disk but is relocated. No index rebuild — it stays searchable
1128+
/// under its new path.
1129+
/// - `Hard`: remove the file from disk and call `store.delete_file_hard()` to purge all
1130+
/// associated chunks, edges, FTS, and vector data.
1131+
pub fn delete_note(
1132+
store: &Store,
1133+
vault_path: &Path,
1134+
file: &str,
1135+
mode: DeleteMode,
1136+
archive_folder: &str,
1137+
) -> Result<()> {
1138+
let file_record = store
1139+
.resolve_file(file)?
1140+
.ok_or_else(|| anyhow::anyhow!("file not found: {}", file))?;
1141+
1142+
let old_path = vault_path.join(&file_record.path);
1143+
1144+
match mode {
1145+
DeleteMode::Soft => {
1146+
// Build destination path inside archive_folder
1147+
let basename = std::path::Path::new(&file_record.path)
1148+
.file_name()
1149+
.ok_or_else(|| anyhow::anyhow!("cannot determine filename for: {}", file_record.path))?;
1150+
let new_rel_path = format!("{}/{}", archive_folder.trim_end_matches('/'), basename.to_string_lossy());
1151+
let new_full_path = vault_path.join(&new_rel_path);
1152+
1153+
// Ensure target directory exists
1154+
if let Some(parent) = new_full_path.parent() {
1155+
std::fs::create_dir_all(parent)?;
1156+
}
1157+
1158+
// Move file on disk
1159+
std::fs::rename(&old_path, &new_full_path)?;
1160+
1161+
// Update store: remove old record, insert under new path
1162+
let tags = file_record.tags.clone();
1163+
let docid = file_record.docid.as_deref().unwrap_or("").to_string();
1164+
let created_by = file_record.created_by.clone();
1165+
let mtime = file_record.mtime;
1166+
1167+
let content = std::fs::read_to_string(&new_full_path)?;
1168+
let content_hash = compute_content_hash(&content);
1169+
1170+
store.delete_file(file_record.id)?;
1171+
store.insert_file(
1172+
&new_rel_path,
1173+
&content_hash,
1174+
mtime,
1175+
&tags,
1176+
&docid,
1177+
created_by.as_deref(),
1178+
)?;
1179+
1180+
Ok(())
1181+
}
1182+
DeleteMode::Hard => {
1183+
// Delete disk file first, then purge store
1184+
std::fs::remove_file(&old_path)?;
1185+
store.delete_file_hard(&file_record.path)?;
1186+
Ok(())
1187+
}
1188+
}
1189+
}
1190+
11141191
// ── Archive / Unarchive ─────────────────────────────────────────
11151192

11161193
/// Archive a note: move to archive folder, add archived frontmatter, remove from index.
@@ -1810,4 +1887,31 @@ mod tests {
18101887
assert!(updated.contains("priority: high"));
18111888
assert!(!updated.contains("status: draft"));
18121889
}
1890+
1891+
#[test]
1892+
fn test_delete_note_soft() {
1893+
let (tmp, store, root) = setup_vault();
1894+
std::fs::create_dir_all(root.join("04-Archive")).unwrap();
1895+
std::fs::write(root.join("deleteme.md"), "# Delete me").unwrap();
1896+
store.insert_file("deleteme.md", "hash", 100, &[], "del123", None).unwrap();
1897+
1898+
delete_note(&store, &root, "deleteme.md", DeleteMode::Soft, "04-Archive/").unwrap();
1899+
1900+
assert!(!root.join("deleteme.md").exists());
1901+
assert!(root.join("04-Archive/deleteme.md").exists());
1902+
drop(tmp);
1903+
}
1904+
1905+
#[test]
1906+
fn test_delete_note_hard() {
1907+
let (tmp, store, root) = setup_vault();
1908+
std::fs::write(root.join("gone.md"), "# Gone forever").unwrap();
1909+
store.insert_file("gone.md", "hash", 100, &[], "gon123", None).unwrap();
1910+
1911+
delete_note(&store, &root, "gone.md", DeleteMode::Hard, "").unwrap();
1912+
1913+
assert!(!root.join("gone.md").exists());
1914+
assert!(store.get_file("gone.md").unwrap().is_none());
1915+
drop(tmp);
1916+
}
18131917
}

0 commit comments

Comments
 (0)