Skip to content

Commit 5a0b002

Browse files
committed
refactor: yield pages from the message search streams
Have the search streams yield whole pages instead of individual results so consumers can decide to stop between (potentially expensive) polls, and to mirror how server-side search pagination works.
1 parent ce0acfc commit 5a0b002

5 files changed

Lines changed: 119 additions & 107 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[**breaking**] `Room::search_messages` and `Client::search_messages` no longer take a `num_results_per_batch` parameter. The returned `RoomSearchIterator`/`GlobalSearchIterator`'s `next_events()` now yields one page of results per call.

bindings/matrix-sdk-ffi/src/search.rs

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,23 @@ impl From<SdkSearchError> for SearchError {
4747
}
4848
}
4949

50-
/// A boxed stream of the [`TimelineEvent`]s matching a single-room search.
51-
type RoomEventStream = Pin<Box<dyn Stream<Item = Result<TimelineEvent, SdkSearchError>> + Send>>;
50+
/// A boxed stream of pages of the [`TimelineEvent`]s matching a single-room
51+
/// search.
52+
type RoomEventStream =
53+
Pin<Box<dyn Stream<Item = Result<Vec<TimelineEvent>, SdkSearchError>> + Send>>;
5254

53-
/// A boxed stream of the `(room_id, event)`s matching a global search.
55+
/// A boxed stream of pages of the `(room_id, event)`s matching a global search.
5456
type GlobalEventStream =
55-
Pin<Box<dyn Stream<Item = Result<(OwnedRoomId, TimelineEvent), SdkSearchError>> + Send>>;
57+
Pin<Box<dyn Stream<Item = Result<Vec<(OwnedRoomId, TimelineEvent)>, SdkSearchError>> + Send>>;
5658

5759
#[matrix_sdk_ffi_macros::export]
5860
impl Room {
5961
/// Search for messages in this room matching the given query, returning an
60-
/// iterator over the results that yields `num_results_per_batch` results at
61-
/// a time.
62-
pub fn search_messages(&self, query: String, num_results_per_batch: u32) -> RoomSearchIterator {
62+
/// iterator that yields one page of results at a time.
63+
pub fn search_messages(&self, query: String) -> RoomSearchIterator {
6364
RoomSearchIterator {
6465
sdk_room: (*self.inner).clone(),
6566
stream: Mutex::new(Box::pin(self.inner.search_messages_events(query))),
66-
num_results_per_batch: num_results_per_batch as usize,
6767
}
6868
}
6969
}
@@ -72,29 +72,18 @@ impl Room {
7272
pub struct RoomSearchIterator {
7373
sdk_room: matrix_sdk::room::Room,
7474
stream: Mutex<RoomEventStream>,
75-
num_results_per_batch: usize,
7675
}
7776

7877
#[matrix_sdk_ffi_macros::export]
7978
impl RoomSearchIterator {
80-
/// Return a list of events for the next batch of search results, or `None`
81-
/// if there are no more results.
79+
/// Return the next page of search results, or `None` if there are no more
80+
/// results.
8281
pub async fn next_events(&self) -> Result<Option<Vec<RoomSearchResult>>, SearchError> {
83-
let mut stream = self.stream.lock().await;
84-
85-
let mut events = Vec::with_capacity(self.num_results_per_batch);
86-
while events.len() < self.num_results_per_batch {
87-
let Some(event) = stream.next().await else {
88-
break;
89-
};
90-
events.push(event?);
91-
}
92-
93-
if events.is_empty() {
82+
let Some(events) = self.stream.lock().await.next().await else {
9483
return Ok(None);
95-
}
96-
drop(stream);
84+
};
9785

86+
let events = events?;
9887
let mut results = Vec::with_capacity(events.len());
9988
for event in events {
10089
if let Some(result) = RoomSearchResult::from(&self.sdk_room, event).await {
@@ -158,7 +147,6 @@ impl Client {
158147
&self,
159148
query: String,
160149
filter: SearchRoomFilter,
161-
num_results_per_batch: u32,
162150
) -> Result<GlobalSearchIterator, ClientError> {
163151
let sdk_client = (*self.inner).clone();
164152
let mut builder = sdk_client.search_messages(query);
@@ -172,7 +160,6 @@ impl Client {
172160
Ok(GlobalSearchIterator {
173161
sdk_client,
174162
stream: Mutex::new(Box::pin(builder.build_events())),
175-
num_results_per_batch: num_results_per_batch as usize,
176163
})
177164
}
178165
}
@@ -187,29 +174,18 @@ pub struct GlobalSearchResult {
187174
pub struct GlobalSearchIterator {
188175
sdk_client: matrix_sdk::Client,
189176
stream: Mutex<GlobalEventStream>,
190-
num_results_per_batch: usize,
191177
}
192178

193179
#[matrix_sdk_ffi_macros::export]
194180
impl GlobalSearchIterator {
195-
/// Return a list of events for the next batch of search results, or `None`
196-
/// if there are no more results.
181+
/// Return the next page of search results, or `None` if there are no more
182+
/// results.
197183
pub async fn next_events(&self) -> Result<Option<Vec<GlobalSearchResult>>, SearchError> {
198-
let mut stream = self.stream.lock().await;
199-
200-
let mut batch = Vec::with_capacity(self.num_results_per_batch);
201-
while batch.len() < self.num_results_per_batch {
202-
let Some(item) = stream.next().await else {
203-
break;
204-
};
205-
batch.push(item?);
206-
}
207-
208-
if batch.is_empty() {
184+
let Some(batch) = self.stream.lock().await.next().await else {
209185
return Ok(None);
210-
}
211-
drop(stream);
186+
};
212187

188+
let batch = batch?;
213189
let mut results = Vec::with_capacity(batch.len());
214190
for (room_id, event) in batch {
215191
let Some(room) = self.sdk_client.get_room(&room_id) else {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[**breaking**] The message search helpers now expose their results as `Stream`s instead of bespoke iterators. `Room::search_messages` returns a stream of `(score, event_id)` pairs (use the new `Room::search_messages_events` for full `TimelineEvent`s), and `GlobalSearchBuilder::build`/`build_events` replace the removed `RoomSearchIterator`/`GlobalSearchIterator` types. The `num_results_per_batch` parameter is gone, as batching is now up to the caller.
1+
[**breaking**] The message search helpers now expose their results as `Stream`s of pages instead of bespoke iterators. `Room::search_messages` returns a stream of pages of `(score, event_id)` pairs (use the new `Room::search_messages_events` for full `TimelineEvent`s), and `GlobalSearchBuilder::build`/`build_events` replace the removed `RoomSearchIterator`/`GlobalSearchIterator` types.

0 commit comments

Comments
 (0)