@@ -212,6 +212,20 @@ impl SpaceService {
212212 SpaceRoomList :: new ( self . client . clone ( ) , space_id) . await
213213 }
214214
215+ /// Returns all known direct-parents of a given space room ID.
216+ pub async fn joined_parents_of_child ( & self , child_id : & RoomId ) -> Vec < SpaceRoom > {
217+ let graph = & self . space_state . lock ( ) . await . graph ;
218+
219+ graph
220+ . parents_of ( child_id)
221+ . into_iter ( )
222+ . filter_map ( |parent_id| self . client . get_room ( parent_id) ) // The graph is built from joined rooms so nothing should be filtered out here.
223+ . map ( |room| {
224+ SpaceRoom :: new_from_known ( & room, graph. children_of ( room. room_id ( ) ) . len ( ) as u64 )
225+ } )
226+ . collect ( )
227+ }
228+
215229 pub async fn add_child_to_space (
216230 & self ,
217231 child_id : OwnedRoomId ,
@@ -708,6 +722,88 @@ mod tests {
708722 ) ;
709723 }
710724
725+ #[ async_test]
726+ async fn test_joined_parents_of_child ( ) {
727+ // Given a space with three parent spaces, two of which are joined.
728+ let server = MatrixMockServer :: new ( ) . await ;
729+ let client = server. client_builder ( ) . build ( ) . await ;
730+ let user_id = client. user_id ( ) . unwrap ( ) ;
731+ let factory = EventFactory :: new ( ) ;
732+
733+ server. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
734+
735+ let parent_space_id_1 = room_id ! ( "!parent_space_1:example.org" ) ;
736+ let parent_space_id_2 = room_id ! ( "!parent_space_2:example.org" ) ;
737+ let unknown_parent_space_id = room_id ! ( "!unknown_parent_space:example.org" ) ;
738+ let child_space_id = room_id ! ( "!child_space:example.org" ) ;
739+
740+ server
741+ . sync_room (
742+ & client,
743+ JoinedRoomBuilder :: new ( child_space_id)
744+ . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
745+ . add_state_event (
746+ factory
747+ . space_parent ( parent_space_id_1. to_owned ( ) , child_space_id. to_owned ( ) )
748+ . sender ( user_id) ,
749+ )
750+ . add_state_event (
751+ factory
752+ . space_parent ( parent_space_id_2. to_owned ( ) , child_space_id. to_owned ( ) )
753+ . sender ( user_id) ,
754+ )
755+ . add_state_event (
756+ factory
757+ . space_parent (
758+ unknown_parent_space_id. to_owned ( ) ,
759+ child_space_id. to_owned ( ) ,
760+ )
761+ . sender ( user_id) ,
762+ ) ,
763+ )
764+ . await ;
765+
766+ server
767+ . sync_room (
768+ & client,
769+ JoinedRoomBuilder :: new ( parent_space_id_1)
770+ . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
771+ . add_state_event (
772+ factory
773+ . space_child ( parent_space_id_1. to_owned ( ) , child_space_id. to_owned ( ) )
774+ . sender ( user_id) ,
775+ ) ,
776+ )
777+ . await ;
778+
779+ server
780+ . sync_room (
781+ & client,
782+ JoinedRoomBuilder :: new ( parent_space_id_2)
783+ . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
784+ . add_state_event (
785+ factory
786+ . space_child ( parent_space_id_2. to_owned ( ) , child_space_id. to_owned ( ) )
787+ . sender ( user_id) ,
788+ ) ,
789+ )
790+ . await ;
791+
792+ let space_service = SpaceService :: new ( client. clone ( ) ) ;
793+
794+ // Wait for the space hierarchy to register.
795+ _ = space_service. joined_spaces ( ) . await ;
796+
797+ // When retrieving the joined parents of the child space
798+ let parents = space_service. joined_parents_of_child ( & child_space_id) . await ;
799+
800+ // Then both parent spaces are returned
801+ assert_eq ! (
802+ parents. iter( ) . map( |space| space. room_id. to_owned( ) ) . collect:: <Vec <_>>( ) ,
803+ vec![ parent_space_id_1, parent_space_id_2]
804+ ) ;
805+ }
806+
711807 #[ async_test]
712808 async fn test_add_child_to_space ( ) {
713809 // Given a space and child room where the user is admin of both.
0 commit comments