Skip to main content

xmtp_db/encrypted_store/
pending_remove.rs

1use super::ConnectionExt;
2use crate::schema::pending_remove::dsl;
3use crate::{DbConnection, impl_fetch, impl_store_or_ignore, schema::pending_remove};
4use diesel::dsl::exists;
5use diesel::prelude::*;
6use diesel::select;
7use serde::{Deserialize, Serialize};
8
9use xmtp_proto::types::GroupId;
10#[derive(
11    Debug,
12    Clone,
13    Serialize,
14    Deserialize,
15    Insertable,
16    Identifiable,
17    Queryable,
18    Eq,
19    PartialEq,
20    QueryableByName,
21)]
22#[diesel(table_name = pending_remove)]
23#[diesel(primary_key(inbox_id, group_id))]
24pub struct PendingRemove {
25    /// Id of the group this message is tied to.
26    pub group_id: GroupId,
27    /// Id of the inbox user want to leave the group.
28    pub inbox_id: String,
29    /// Id of the LeaveRequest message
30    pub message_id: Vec<u8>,
31}
32
33impl_store_or_ignore!(PendingRemove, pending_remove);
34impl_fetch!(PendingRemove, pending_remove);
35pub trait QueryPendingRemove {
36    fn get_pending_remove_users(
37        &self,
38        group_id: &GroupId,
39    ) -> Result<Vec<String>, crate::ConnectionError>;
40    fn get_user_pending_remove_status(
41        &self,
42        group_id: &GroupId,
43        inbox_id: &str,
44    ) -> Result<bool, crate::ConnectionError>;
45    fn delete_pending_remove_users(
46        &self,
47        group_id: &GroupId,
48        inbox_ids: Vec<String>,
49    ) -> Result<usize, crate::ConnectionError>;
50}
51impl<T> QueryPendingRemove for &T
52where
53    T: QueryPendingRemove,
54{
55    fn get_pending_remove_users(
56        &self,
57        group_id: &GroupId,
58    ) -> Result<Vec<String>, crate::ConnectionError> {
59        (**self).get_pending_remove_users(group_id)
60    }
61    fn get_user_pending_remove_status(
62        &self,
63        group_id: &GroupId,
64        inbox_id: &str,
65    ) -> Result<bool, crate::ConnectionError> {
66        (**self).get_user_pending_remove_status(group_id, inbox_id)
67    }
68    fn delete_pending_remove_users(
69        &self,
70        group_id: &GroupId,
71        inbox_ids: Vec<String>,
72    ) -> Result<usize, crate::ConnectionError> {
73        (**self).delete_pending_remove_users(group_id, inbox_ids)
74    }
75}
76impl<C: ConnectionExt> QueryPendingRemove for DbConnection<C> {
77    fn get_pending_remove_users(
78        &self,
79        group_id: &GroupId,
80    ) -> Result<Vec<String>, crate::ConnectionError> {
81        let result = self.raw_query(|conn| {
82            dsl::pending_remove
83                .filter(dsl::group_id.eq(group_id))
84                .select(dsl::inbox_id)
85                .load::<String>(conn)
86        })?;
87
88        Ok(result)
89    }
90
91    fn get_user_pending_remove_status(
92        &self,
93        group_id: &GroupId,
94        inbox_id: &str,
95    ) -> Result<bool, crate::ConnectionError> {
96        let result: bool = self.raw_query(|conn| {
97            select(exists(dsl::pending_remove.filter(
98                dsl::group_id.eq(group_id).and(dsl::inbox_id.eq(inbox_id)),
99            )))
100            .get_result::<bool>(conn)
101        })?;
102        Ok(result)
103    }
104
105    fn delete_pending_remove_users(
106        &self,
107        group_id: &GroupId,
108        inbox_ids: Vec<String>,
109    ) -> Result<usize, crate::ConnectionError> {
110        let result = self.raw_query(|conn| {
111            diesel::delete(
112                dsl::pending_remove.filter(
113                    dsl::inbox_id
114                        .eq_any(inbox_ids)
115                        .and(dsl::group_id.eq(group_id)),
116                ),
117            )
118            .execute(conn)
119        })?;
120        Ok(result)
121    }
122}
123#[cfg(test)]
124mod tests {
125    use super::GroupId;
126    use crate::encrypted_store::pending_remove::{PendingRemove, QueryPendingRemove};
127    use crate::{StoreOrIgnore, with_connection};
128
129    #[xmtp_common::test(unwrap_try = true)]
130    fn test_add_pending_remove() {
131        with_connection(|conn| {
132            PendingRemove {
133                inbox_id: "123".to_string(),
134                group_id: GroupId::ONE,
135                message_id: vec![1, 2, 3],
136            }
137            .store_or_ignore(conn)?;
138            let users = conn.get_pending_remove_users(&GroupId::ONE).unwrap();
139            assert_eq!(users.len(), 1);
140            let users = conn.get_pending_remove_users(&GroupId::TWO).unwrap();
141            assert_eq!(users.len(), 0);
142        })
143    }
144
145    #[xmtp_common::test(unwrap_try = true)]
146    fn test_delete_pending_remove_user() {
147        with_connection(|conn| {
148            PendingRemove {
149                inbox_id: "1".to_string(),
150                group_id: GroupId::ONE,
151                message_id: vec![1, 2, 3],
152            }
153            .store_or_ignore(conn)?;
154            PendingRemove {
155                inbox_id: "2".to_string(),
156                group_id: GroupId::ONE,
157                message_id: vec![1, 2, 3],
158            }
159            .store_or_ignore(conn)?;
160            PendingRemove {
161                inbox_id: "3".to_string(),
162                group_id: GroupId::ONE,
163                message_id: vec![1, 2, 3],
164            }
165            .store_or_ignore(conn)?;
166            let group_id = GroupId::ONE;
167            let users = conn.get_pending_remove_users(&group_id).unwrap();
168            assert_eq!(users.len(), 3);
169            let deleted_users = conn
170                .delete_pending_remove_users(&group_id, vec!["1".to_string(), "2".to_string()])
171                .unwrap();
172            assert_eq!(deleted_users, 2usize);
173            let users = conn.get_pending_remove_users(&group_id).unwrap();
174            assert_eq!(users.len(), 1);
175            let deleted_users = conn
176                .delete_pending_remove_users(&GroupId::TWO, vec!["3".to_string()])
177                .unwrap();
178            assert_eq!(deleted_users, 0usize);
179        })
180    }
181}