diff --git a/src/service/rooms/read_receipt/data.rs b/src/service/rooms/read_receipt/data.rs index 29242b5d..44f272e9 100644 --- a/src/service/rooms/read_receipt/data.rs +++ b/src/service/rooms/read_receipt/data.rs @@ -7,7 +7,7 @@ use ruma::{ serde::Raw, }; use tuwunel_core::{ - Result, trace, + Result, err, is_equal_to, trace, utils::{ReadyExt, stream::TryIgnore}, }; use tuwunel_database::{Deserialized, Interfix, Json, Map}; @@ -84,6 +84,28 @@ impl Data { .ignore_err() } + #[inline] + pub(super) async fn last_receipt_count<'a>( + &'a self, + room_id: &'a RoomId, + since: Option, + user_id: Option<&'a UserId>, + ) -> Result { + type Key<'a> = (&'a RoomId, u64, &'a UserId); + + let key = (room_id, u64::MAX); + self.readreceiptid_readreceipt + .rev_keys_prefix(&key) + .ignore_err() + .ready_take_while(|(_, c, _): &Key<'_>| since.is_none_or(|since| since.gt(&c))) + .ready_filter(|(_, _, u): &Key<'_>| user_id.as_ref().is_none_or(is_equal_to!(u))) + .map(|(_, c, _): Key<'_>| c) + .boxed() + .next() + .await + .ok_or_else(|| err!(Request(NotFound("No receipts found in room")))) + } + #[inline] pub(super) fn private_read_set(&self, room_id: &RoomId, user_id: &UserId, pdu_count: u64) { let key = (room_id, user_id); diff --git a/src/service/rooms/read_receipt/mod.rs b/src/service/rooms/read_receipt/mod.rs index 0148ad05..90771f8b 100644 --- a/src/service/rooms/read_receipt/mod.rs +++ b/src/service/rooms/read_receipt/mod.rs @@ -146,6 +146,17 @@ impl Service { .await } + pub async fn last_receipt_count( + &self, + room_id: &RoomId, + user_id: Option<&UserId>, + since: Option, + ) -> Result { + self.db + .last_receipt_count(room_id, since, user_id) + .await + } + pub async fn delete_all_read_receipts(&self, room_id: &RoomId) -> Result { self.db.delete_all_read_receipts(room_id).await }