@@ -28,6 +28,7 @@ pub struct GlobalIndexDropBuilder<'a> {
2828 table : & ' a Table ,
2929 index_column : Option < String > ,
3030 index_type : String ,
31+ dry_run : bool ,
3132}
3233
3334impl < ' a > GlobalIndexDropBuilder < ' a > {
@@ -36,6 +37,7 @@ impl<'a> GlobalIndexDropBuilder<'a> {
3637 table,
3738 index_column : None ,
3839 index_type : BTREE_GLOBAL_INDEX_TYPE . to_string ( ) ,
40+ dry_run : false ,
3941 }
4042 }
4143
@@ -49,6 +51,11 @@ impl<'a> GlobalIndexDropBuilder<'a> {
4951 self
5052 }
5153
54+ pub fn with_dry_run ( & mut self , dry_run : bool ) -> & mut Self {
55+ self . dry_run = dry_run;
56+ self
57+ }
58+
5259 pub async fn execute ( & self ) -> Result < usize > {
5360 let index_type =
5461 normalize_global_index_type_for_drop ( & self . index_type ) . ok_or_else ( || {
@@ -108,6 +115,9 @@ impl<'a> GlobalIndexDropBuilder<'a> {
108115 . or_default ( )
109116 . push ( entry. index_file ) ;
110117 }
118+ if self . dry_run {
119+ return Ok ( dropped) ;
120+ }
111121 if dropped == 0 {
112122 return Ok ( 0 ) ;
113123 }
@@ -477,4 +487,83 @@ mod tests {
477487 if message. contains( "unsupported global index type" ) && message. contains( "ivf-pq" )
478488 ) ) ;
479489 }
490+
491+ #[ tokio:: test]
492+ async fn test_dry_run_previews_without_committing ( ) {
493+ let table = test_table ( "memory:/test_drop_dry_run_preview" ) ;
494+ setup_dirs ( & table) . await ;
495+
496+ let mut message = CommitMessage :: new (
497+ BinaryRow :: new ( 0 ) . to_serialized_bytes ( ) ,
498+ 0 ,
499+ vec ! [ data_file( "data-0.parquet" ) ] ,
500+ ) ;
501+ message. new_index_files = vec ! [ global_index_file(
502+ BTREE_GLOBAL_INDEX_TYPE ,
503+ "btree-id.index" ,
504+ 0 ,
505+ 0 ,
506+ 9 ,
507+ ) ] ;
508+ TableCommit :: new ( table. clone ( ) , "test-user" . to_string ( ) )
509+ . commit ( vec ! [ message] )
510+ . await
511+ . unwrap ( ) ;
512+
513+ // dry-run: returns the matched count, commits nothing.
514+ let would_drop = table
515+ . new_global_index_drop_builder ( )
516+ . with_index_column ( "id" )
517+ . with_dry_run ( true )
518+ . execute ( )
519+ . await
520+ . unwrap ( ) ;
521+ assert_eq ! ( would_drop, 1 ) ;
522+
523+ // Entry is still present (no commit happened).
524+ let after_dry = latest_index_entries ( & table)
525+ . await
526+ . into_iter ( )
527+ . map ( |e| e. index_file . file_name )
528+ . collect :: < Vec < _ > > ( ) ;
529+ assert_eq ! ( after_dry, vec![ "btree-id.index" . to_string( ) ] ) ;
530+
531+ // A real drop (dry_run defaults false) removes it.
532+ let dropped = table
533+ . new_global_index_drop_builder ( )
534+ . with_index_column ( "id" )
535+ . execute ( )
536+ . await
537+ . unwrap ( ) ;
538+ assert_eq ! ( dropped, 1 ) ;
539+ assert ! ( latest_index_entries( & table) . await . is_empty( ) ) ;
540+ }
541+
542+ #[ tokio:: test]
543+ async fn test_dry_run_without_match_returns_zero ( ) {
544+ let table = test_table ( "memory:/test_drop_dry_run_no_match" ) ;
545+ setup_dirs ( & table) . await ;
546+
547+ let mut message = CommitMessage :: new ( vec ! [ ] , 0 , vec ! [ data_file( "data-0.parquet" ) ] ) ;
548+ message. new_index_files = vec ! [ global_index_file(
549+ BTREE_GLOBAL_INDEX_TYPE ,
550+ "btree-name.index" ,
551+ 1 ,
552+ 0 ,
553+ 9 ,
554+ ) ] ;
555+ TableCommit :: new ( table. clone ( ) , "test-user" . to_string ( ) )
556+ . commit ( vec ! [ message] )
557+ . await
558+ . unwrap ( ) ;
559+
560+ let would_drop = table
561+ . new_global_index_drop_builder ( )
562+ . with_index_column ( "id" )
563+ . with_dry_run ( true )
564+ . execute ( )
565+ . await
566+ . unwrap ( ) ;
567+ assert_eq ! ( would_drop, 0 ) ;
568+ }
480569}
0 commit comments