@@ -216,6 +216,20 @@ impl SpaceService {
216216 SpaceRoomList :: new ( self . client . clone ( ) , space_id) . await
217217 }
218218
219+ /// Returns all known direct-parents of a given space room ID.
220+ pub async fn joined_parents_of_child ( & self , child_id : & RoomId ) -> Vec < SpaceRoom > {
221+ let graph = & self . space_state . lock ( ) . await . graph ;
222+
223+ graph
224+ . parents_of ( child_id)
225+ . into_iter ( )
226+ . filter_map ( |parent_id| self . client . get_room ( parent_id) )
227+ . map ( |room| {
228+ SpaceRoom :: new_from_known ( & room, graph. children_of ( room. room_id ( ) ) . len ( ) as u64 )
229+ } )
230+ . collect ( )
231+ }
232+
219233 pub async fn add_child_to_space (
220234 & self ,
221235 child_id : OwnedRoomId ,
@@ -716,6 +730,88 @@ mod tests {
716730 ) ;
717731 }
718732
733+ #[ async_test]
734+ async fn test_joined_parents_of_child ( ) {
735+ // Given a space with three parent spaces, two of which are joined.
736+ let server = MatrixMockServer :: new ( ) . await ;
737+ let client = server. client_builder ( ) . build ( ) . await ;
738+ let user_id = client. user_id ( ) . unwrap ( ) ;
739+ let factory = EventFactory :: new ( ) ;
740+
741+ server. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
742+
743+ let parent_space_id_1 = room_id ! ( "!parent_space_1:example.org" ) ;
744+ let parent_space_id_2 = room_id ! ( "!parent_space_2:example.org" ) ;
745+ let unknown_parent_space_id = room_id ! ( "!unknown_parent_space:example.org" ) ;
746+ let child_space_id = room_id ! ( "!child_space:example.org" ) ;
747+
748+ server
749+ . sync_room (
750+ & client,
751+ JoinedRoomBuilder :: new ( child_space_id)
752+ . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
753+ . add_state_event (
754+ factory
755+ . space_parent ( parent_space_id_1. to_owned ( ) , child_space_id. to_owned ( ) )
756+ . sender ( user_id) ,
757+ )
758+ . add_state_event (
759+ factory
760+ . space_parent ( parent_space_id_2. to_owned ( ) , child_space_id. to_owned ( ) )
761+ . sender ( user_id) ,
762+ )
763+ . add_state_event (
764+ factory
765+ . space_parent (
766+ unknown_parent_space_id. to_owned ( ) ,
767+ child_space_id. to_owned ( ) ,
768+ )
769+ . sender ( user_id) ,
770+ ) ,
771+ )
772+ . await ;
773+
774+ server
775+ . sync_room (
776+ & client,
777+ JoinedRoomBuilder :: new ( parent_space_id_1)
778+ . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
779+ . add_state_event (
780+ factory
781+ . space_child ( parent_space_id_1. to_owned ( ) , child_space_id. to_owned ( ) )
782+ . sender ( user_id) ,
783+ ) ,
784+ )
785+ . await ;
786+
787+ server
788+ . sync_room (
789+ & client,
790+ JoinedRoomBuilder :: new ( parent_space_id_2)
791+ . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
792+ . add_state_event (
793+ factory
794+ . space_child ( parent_space_id_2. to_owned ( ) , child_space_id. to_owned ( ) )
795+ . sender ( user_id) ,
796+ ) ,
797+ )
798+ . await ;
799+
800+ let space_service = SpaceService :: new ( client. clone ( ) ) ;
801+
802+ // Wait for the space hierarchy to register.
803+ _ = space_service. joined_spaces ( ) . await ;
804+
805+ // When retrieving the joined parents of the child space
806+ let parents = space_service. joined_parents_of_child ( child_space_id) . await ;
807+
808+ // Then both parent spaces are returned
809+ assert_eq ! (
810+ parents. iter( ) . map( |space| space. room_id. to_owned( ) ) . collect:: <Vec <_>>( ) ,
811+ vec![ parent_space_id_1, parent_space_id_2]
812+ ) ;
813+ }
814+
719815 #[ async_test]
720816 async fn test_add_child_to_space ( ) {
721817 // Given a space and child room where the user is admin of both.
0 commit comments