@@ -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