refactor(sdk): Room::search_messages and Client::search_messages

This commit is contained in:
Benjamin Bouvier
2026-04-17 11:59:25 +02:00
parent 7f8c9b0244
commit ce01854078
3 changed files with 58 additions and 56 deletions
+11 -10
View File
@@ -49,10 +49,13 @@ impl From<SdkSearchError> for SearchError {
#[matrix_sdk_ffi_macros::export]
impl Room {
pub fn search(&self, query: String) -> RoomSearchIterator {
/// Search for messages in this room matching the given query, returning an
/// iterator over the results that yields `num_results_per_batch` results at
/// a time.
pub fn search_messages(&self, query: String, num_results_per_batch: u32) -> RoomSearchIterator {
RoomSearchIterator {
sdk_room: self.inner.clone(),
inner: Mutex::new(SdkRoomSearchIterator::new(self.inner.clone(), query)),
inner: Mutex::new(self.inner.search_messages(query, num_results_per_batch as usize)),
}
}
}
@@ -68,7 +71,7 @@ impl RoomSearchIterator {
/// Return a list of events for the next batch of search results, or `None`
/// if there are no more results.
pub async fn next_events(&self) -> Result<Option<Vec<RoomSearchResult>>, SearchError> {
let Some(events) = self.inner.lock().await.next_events(20).await? else {
let Some(events) = self.inner.lock().await.next_events().await? else {
return Ok(None);
};
@@ -132,13 +135,14 @@ pub enum SearchRoomFilter {
impl Client {
/// Search across all all rooms for the given query, returning an iterator
/// over the results.
pub async fn search(
pub async fn search_messages(
&self,
query: String,
filter: SearchRoomFilter,
num_results_per_batch: u32,
) -> Result<GlobalSearchIterator, ClientError> {
let sdk_client = (*self.inner).clone();
let mut search = SdkGlobalSearchIterator::builder(sdk_client.clone(), query);
let mut search = sdk_client.search_messages(query, num_results_per_batch as usize);
match filter {
SearchRoomFilter::Rooms => {}
@@ -172,11 +176,8 @@ pub struct GlobalSearchIterator {
impl GlobalSearchIterator {
/// Return a list of events for the next batch of search results, or `None`
/// if there are no more results.
pub async fn next_events(
&self,
num_results: u64,
) -> Result<Option<Vec<GlobalSearchResult>>, SearchError> {
let Some(events) = self.inner.lock().await.next_events(num_results as usize).await? else {
pub async fn next_events(&self) -> Result<Option<Vec<GlobalSearchResult>>, SearchError> {
let Some(events) = self.inner.lock().await.next_events().await? else {
return Ok(None);
};
+42 -36
View File
@@ -51,6 +51,24 @@ pub enum SearchError {
EventLoadError(#[from] crate::Error),
}
impl Room {
/// Search for messages in this room matching the given query, returning an
/// iterator over the results.
pub fn search_messages(
&self,
query: String,
num_results_per_batch: usize,
) -> RoomSearchIterator {
RoomSearchIterator {
room: self.clone(),
query,
offset: None,
is_done: false,
num_results_per_batch,
}
}
}
/// An async iterator for a search query in a single room.
#[derive(Debug)]
pub struct RoomSearchIterator {
@@ -73,11 +91,6 @@ pub struct RoomSearchIterator {
}
impl RoomSearchIterator {
/// Create a new search iterator for the given room and query.
pub fn new(room: Room, query: String, num_results_per_batch: usize) -> Self {
Self { room, query, offset: None, is_done: false, num_results_per_batch }
}
/// Return the next batch of event IDs matching the search query, or `None`
/// if there are no more results.
pub async fn next(&mut self) -> Result<Option<Vec<OwnedEventId>>, IndexError> {
@@ -116,6 +129,7 @@ impl RoomSearchIterator {
struct GlobalSearchRoomState {
/// The room for which we're storing state.
room: Room,
/// The current start offset in the search results for this room, or `None`
/// if we haven't called the iterator for this room yet.
offset: Option<usize>,
@@ -187,6 +201,18 @@ impl GlobalSearchBuilder {
}
}
impl Client {
/// Search across all rooms for events with the given query, returning a
/// builder for an iterator over the results.
pub fn search_messages(
&self,
query: String,
num_results_per_batch: usize,
) -> GlobalSearchBuilder {
GlobalSearchBuilder::new(self.clone(), query, num_results_per_batch)
}
}
/// An async iterator for a search query across multiple rooms.
#[derive(Debug)]
pub struct GlobalSearchIterator {
@@ -213,16 +239,6 @@ pub struct GlobalSearchIterator {
}
impl GlobalSearchIterator {
/// Create a new [`GlobalSearchBuilder`] for the given client and query, on
/// all joined rooms by default.
pub fn builder(
client: Client,
query: String,
num_results_per_batch: usize,
) -> GlobalSearchBuilder {
GlobalSearchBuilder::new(client, query, num_results_per_batch)
}
/// Return the next batch of event IDs matching the search query across all
/// rooms, or `None` if there are no more results.
pub async fn next(&mut self) -> Result<Option<Vec<(OwnedRoomId, OwnedEventId)>>, SearchError> {
@@ -307,11 +323,7 @@ mod tests {
use matrix_sdk_test::{BOB, JoinedRoomBuilder, async_test, event_factory::EventFactory};
use ruma::{event_id, room_id, user_id};
use crate::{
message_search::{GlobalSearchIterator, RoomSearchIterator},
sleep::sleep,
test_utils::mocks::MatrixMockServer,
};
use crate::{sleep::sleep, test_utils::mocks::MatrixMockServer};
#[async_test]
async fn test_room_message_search() {
@@ -341,8 +353,7 @@ mod tests {
// Search for a missing keyword.
{
let mut room_search =
RoomSearchIterator::new(room.clone(), "search query".to_owned(), 5);
let mut room_search = room.search_messages("search query".to_owned(), 5);
// Searching for an event that's non-existing should succeed.
let maybe_results = room_search.next().await.unwrap();
@@ -356,7 +367,7 @@ mod tests {
// Search for an existing keyword, by event id.
{
let mut room_search = RoomSearchIterator::new(room.clone(), "world".to_owned(), 5);
let mut room_search = room.search_messages("world".to_owned(), 5);
// Searching for a keyword that matches an existing event should return the
// event ID.
@@ -372,7 +383,7 @@ mod tests {
// Search for an existing keyword, by events.
{
let mut room_search = RoomSearchIterator::new(room.clone(), "world".to_owned(), 5);
let mut room_search = room.search_messages("world".to_owned(), 5);
// Searching for a keyword that matches an existing event should return the
// event ID.
@@ -425,8 +436,7 @@ mod tests {
// Search for a missing keyword.
{
let mut search =
GlobalSearchIterator::builder(client.clone(), "search query".to_owned(), 5).build();
let mut search = client.search_messages("search query".to_owned(), 5).build();
// Searching for an event that's non-existing should succeed.
let maybe_results = search.next().await.unwrap();
@@ -440,8 +450,7 @@ mod tests {
// Search for an existing keyword, by event id.
{
let mut search =
GlobalSearchIterator::builder(client.clone(), "world".to_owned(), 5).build();
let mut search = client.search_messages("world".to_owned(), 5).build();
// Searching for a keyword that matches an existing event should return the
// event ID.
@@ -460,8 +469,7 @@ mod tests {
// Search for an existing keyword, by event.
{
let mut search =
GlobalSearchIterator::builder(client.clone(), "world".to_owned(), 5).build();
let mut search = client.search_messages("world".to_owned(), 5).build();
// Searching for a keyword that matches an existing event should return the
// event ID.
@@ -527,7 +535,8 @@ mod tests {
// Search for an existing keyword, by event id, only in DMs.
{
let mut search = GlobalSearchIterator::builder(client.clone(), "world".to_owned(), 5)
let mut search = client
.search_messages("world".to_owned(), 5)
.only_dm_rooms()
.await
.unwrap()
@@ -545,11 +554,8 @@ mod tests {
// Search for an existing keyword, by event, only in groups.
{
let mut search = GlobalSearchIterator::builder(client.clone(), "world".to_owned(), 5)
.no_dms()
.await
.unwrap()
.build();
let mut search =
client.search_messages("world".to_owned(), 5).no_dms().await.unwrap().build();
let maybe_results = search.next_events().await.unwrap();
let results = maybe_results.unwrap();
+5 -10
View File
@@ -34,7 +34,6 @@ use matrix_sdk_common::{cross_process_lock::CrossProcessLockConfig, locks::Mutex
use matrix_sdk_ui::{
Timeline as SdkTimeline,
room_list_service::{self, State, filters::new_filter_non_left},
search::{GlobalSearchIterator, RoomSearchIterator},
sync_service::SyncService,
timeline::{RoomExt as _, TimelineFocus, TimelineItem},
};
@@ -744,16 +743,12 @@ impl App {
Enter => {
if let Some(query) = view.get_text() {
if *is_global {
let mut search = GlobalSearchIterator::builder(
self.client.clone(),
query,
)
.build();
let mut search =
self.client.search_messages(query, 5).build();
let mut all_results = HashMap::new();
loop {
let Ok(results) = search.next_events(5).await
else {
let Ok(results) = search.next_events().await else {
continue;
};
let Some(results) = results else {
@@ -780,11 +775,11 @@ impl App {
view.get_text().zip(self.room_view.room())
{
let mut room_search =
RoomSearchIterator::new(room, query);
room.search_messages(query, 5);
let mut all_results = Vec::new();
while let Some(results) =
room_search.next_events(5).await?
room_search.next_events().await?
{
all_results.extend(results);
}