@@ -706,51 +706,57 @@ impl<'a, RT: Runtime> ComponentConfigModel<'a, RT> {
706706
707707 #[ minitrace:: trace]
708708 pub async fn delete_component ( & mut self , component_id : ComponentId ) -> anyhow:: Result < ( ) > {
709- let ComponentId :: Child ( id ) = component_id else {
709+ if component_id . is_root ( ) {
710710 anyhow:: bail!( "Cannot delete root component" ) ;
711- } ;
711+ }
712712
713+ // First, walk the component tree and validate that it's okay to delete each
714+ // component.
713715 let component = BootstrapComponentsModel :: new ( self . tx )
714716 . load_component ( component_id)
715717 . await ?;
716-
717- match component {
718- Some ( component) => {
719- if component. state != ComponentState :: Unmounted {
720- anyhow:: bail!( ErrorMetadata :: bad_request(
721- "ComponentMustBeUnmounted" ,
722- "Component must be unmounted before deletion"
723- ) ) ;
724- }
725- } ,
726- None => {
727- anyhow:: bail!( ErrorMetadata :: transient_not_found(
728- "ComponentNotFound" ,
729- format!( "Component with ID {:?} not found" , component_id)
718+ let Some ( component) = component else {
719+ anyhow:: bail!( ErrorMetadata :: transient_not_found(
720+ "ComponentNotFound" ,
721+ format!( "Component with ID {:?} not found" , component_id)
722+ ) ) ;
723+ } ;
724+ let mut stack = vec ! [ component] ;
725+ let mut all_ids = vec ! [ ] ;
726+ while let Some ( component) = stack. pop ( ) {
727+ if component. state != ComponentState :: Unmounted {
728+ anyhow:: bail!( ErrorMetadata :: bad_request(
729+ "ComponentMustBeUnmounted" ,
730+ "Component must be unmounted before deletion"
730731 ) ) ;
731- } ,
732+ }
733+ let children =
734+ BootstrapComponentsModel :: new ( self . tx ) . component_children ( component. id ( ) . into ( ) ) ?;
735+ stack. extend ( children) ;
736+ all_ids. push ( component. id ( ) ) ;
732737 }
733738
734- let resolved_document_id =
735- BootstrapComponentsModel :: new ( self . tx ) . resolve_component_id ( id) ?;
736- SystemMetadataModel :: new_global ( self . tx )
737- . delete ( resolved_document_id)
738- . await ?;
739-
740- let namespace = TableNamespace :: from ( component_id) ;
741- // delete the schema table first
742- // tables defined in the schema cannot be deleted, so we delete the _schemas
743- // table first to remove that restriction
744- TableModel :: new ( self . tx )
745- . delete_table ( namespace, SCHEMAS_TABLE . clone ( ) )
746- . await ?;
739+ // Delete the components we found.
740+ for component_id in all_ids {
741+ SystemMetadataModel :: new_global ( self . tx )
742+ . delete ( component_id)
743+ . await ?;
747744
748- // then delete all tables, including system tables
749- let namespaced_table_mapping = self . tx . table_mapping ( ) . namespace ( namespace) ;
750- for ( tablet_id, ..) in namespaced_table_mapping. iter ( ) {
745+ let namespace = TableNamespace :: from ( ComponentId :: Child ( component_id. into ( ) ) ) ;
746+ // delete the schema table first
747+ // tables defined in the schema cannot be deleted, so we delete the _schemas
748+ // table first to remove that restriction
751749 TableModel :: new ( self . tx )
752- . delete_table_by_id ( tablet_id )
750+ . delete_table ( namespace , SCHEMAS_TABLE . clone ( ) )
753751 . await ?;
752+
753+ // then delete all tables, including system tables
754+ let namespaced_table_mapping = self . tx . table_mapping ( ) . namespace ( namespace) ;
755+ for ( tablet_id, ..) in namespaced_table_mapping. iter ( ) {
756+ TableModel :: new ( self . tx )
757+ . delete_table_by_id ( tablet_id)
758+ . await ?;
759+ }
754760 }
755761
756762 Ok ( ( ) )
0 commit comments