@@ -29,6 +29,8 @@ use std::sync::Arc;
2929
3030use async_trait:: async_trait;
3131use bytes:: Bytes ;
32+ use futures:: StreamExt ;
33+ use futures:: stream:: BoxStream ;
3234use serde:: { Deserialize , Serialize } ;
3335
3436use crate :: io:: {
@@ -200,6 +202,13 @@ impl Storage for LocalFsStorage {
200202 Ok ( ( ) )
201203 }
202204
205+ async fn delete_stream ( & self , mut paths : BoxStream < ' static , String > ) -> Result < ( ) > {
206+ while let Some ( path) = paths. next ( ) . await {
207+ self . delete ( & path) . await ?;
208+ }
209+ Ok ( ( ) )
210+ }
211+
203212 fn new_input ( & self , path : & str ) -> Result < InputFile > {
204213 Ok ( InputFile :: new ( Arc :: new ( self . clone ( ) ) , path. to_string ( ) ) )
205214 }
@@ -534,4 +543,61 @@ mod tests {
534543
535544 assert ! ( path. exists( ) ) ;
536545 }
546+
547+ #[ tokio:: test]
548+ async fn test_local_fs_storage_delete_stream ( ) {
549+ use futures:: stream;
550+
551+ let tmp_dir = TempDir :: new ( ) . unwrap ( ) ;
552+ let storage = LocalFsStorage :: new ( ) ;
553+
554+ // Create multiple files
555+ let file1 = tmp_dir. path ( ) . join ( "file1.txt" ) ;
556+ let file2 = tmp_dir. path ( ) . join ( "file2.txt" ) ;
557+ let file3 = tmp_dir. path ( ) . join ( "file3.txt" ) ;
558+
559+ storage
560+ . write ( file1. to_str ( ) . unwrap ( ) , Bytes :: from ( "1" ) )
561+ . await
562+ . unwrap ( ) ;
563+ storage
564+ . write ( file2. to_str ( ) . unwrap ( ) , Bytes :: from ( "2" ) )
565+ . await
566+ . unwrap ( ) ;
567+ storage
568+ . write ( file3. to_str ( ) . unwrap ( ) , Bytes :: from ( "3" ) )
569+ . await
570+ . unwrap ( ) ;
571+
572+ // Verify files exist
573+ assert ! ( storage. exists( file1. to_str( ) . unwrap( ) ) . await . unwrap( ) ) ;
574+ assert ! ( storage. exists( file2. to_str( ) . unwrap( ) ) . await . unwrap( ) ) ;
575+ assert ! ( storage. exists( file3. to_str( ) . unwrap( ) ) . await . unwrap( ) ) ;
576+
577+ // Delete multiple files using stream
578+ let paths = vec ! [
579+ file1. to_str( ) . unwrap( ) . to_string( ) ,
580+ file2. to_str( ) . unwrap( ) . to_string( ) ,
581+ ] ;
582+ let path_stream = stream:: iter ( paths) . boxed ( ) ;
583+ storage. delete_stream ( path_stream) . await . unwrap ( ) ;
584+
585+ // Verify deleted files no longer exist
586+ assert ! ( !storage. exists( file1. to_str( ) . unwrap( ) ) . await . unwrap( ) ) ;
587+ assert ! ( !storage. exists( file2. to_str( ) . unwrap( ) ) . await . unwrap( ) ) ;
588+
589+ // Verify file3 still exists
590+ assert ! ( storage. exists( file3. to_str( ) . unwrap( ) ) . await . unwrap( ) ) ;
591+ }
592+
593+ #[ tokio:: test]
594+ async fn test_local_fs_storage_delete_stream_empty ( ) {
595+ use futures:: stream;
596+
597+ let storage = LocalFsStorage :: new ( ) ;
598+
599+ // Delete with empty stream should succeed
600+ let path_stream = stream:: iter ( Vec :: < String > :: new ( ) ) . boxed ( ) ;
601+ storage. delete_stream ( path_stream) . await . unwrap ( ) ;
602+ }
537603}
0 commit comments