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 pub group_id: GroupId,
27 pub inbox_id: String,
29 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}