cal_redis/cache/
contact.rs1use super::CallableCache;
4use crate::common::{deserialize_from_json, get_items, serialize_to_json};
5use crate::constants::AccountKeys;
6use cal_core::contact::Contact;
7use redis::{AsyncCommands, RedisError};
8use std::sync::Arc;
9
10impl CallableCache {
11 pub async fn insert_contact(&self, contact: Contact) -> Result<(), RedisError> {
19 println!(
20 "[CallableCache::insert_contact] Inserting contact: {} for account: {}",
21 contact.id, contact.account.id
22 );
23
24 let mut con = self.redis_connection();
25 let hash_key = AccountKeys::contacts(&contact.account.id);
26 let value = serialize_to_json(&contact)?;
27
28 con.hset(&hash_key, &contact.id, value).await?;
30
31 let idents_key = AccountKeys::contact_idents(&contact.account.id);
33
34 con.hset(&idents_key, &contact.primary, &contact.id).await?;
36
37 if let Some(ref secondary) = contact.secondary {
39 con.hset(&idents_key, secondary, &contact.id).await?;
40 }
41
42 if let Some(ref tertiary) = contact.tertiary {
44 con.hset(&idents_key, tertiary, &contact.id).await?;
45 }
46
47 if let Some(ref email) = contact.email {
49 con.hset(&idents_key, email, &contact.id).await?;
50 }
51
52 println!("[CallableCache::insert_contact] Successfully inserted contact");
53 Ok(())
54 }
55
56 pub async fn get_contact_by_id(
65 &self,
66 account_id: &str,
67 contact_id: &str,
68 ) -> Result<Option<Arc<Contact>>, RedisError> {
69 println!(
70 "[CallableCache::get_contact_by_id] Getting contact {} for account: {}",
71 contact_id, account_id
72 );
73
74 let con = self.redis_connection();
75 let hash_key = AccountKeys::contacts(account_id);
76
77 let value: Option<String> = con.clone().hget(&hash_key, contact_id).await?;
78
79 match value {
80 Some(json_str) => {
81 let contact: Contact = deserialize_from_json(&json_str)?;
82 println!("[CallableCache::get_contact_by_id] Found contact: {}", contact.name);
83 Ok(Some(Arc::new(contact)))
84 }
85 None => {
86 println!("[CallableCache::get_contact_by_id] Contact not found");
87 Ok(None)
88 }
89 }
90 }
91
92 pub async fn get_contact_by_ident(
101 &self,
102 account_id: &str,
103 identifier: &str,
104 ) -> Result<Option<Arc<Contact>>, RedisError> {
105 println!(
106 "[CallableCache::get_contact_by_ident] Getting contact by identifier: {} for account: {}",
107 identifier, account_id
108 );
109
110 let con = self.redis_connection();
111 let idents_key = AccountKeys::contact_idents(account_id);
112
113 let contact_id: Option<String> = con.clone().hget(&idents_key, identifier).await?;
115
116 match contact_id {
117 Some(id) => {
118 self.get_contact_by_id(account_id, &id).await
120 }
121 None => {
122 println!("[CallableCache::get_contact_by_ident] No contact found for identifier");
123 Ok(None)
124 }
125 }
126 }
127
128 pub async fn get_contacts_by_account(
136 &self,
137 account_id: &str,
138 ) -> Result<Vec<Arc<Contact>>, RedisError> {
139 println!(
140 "[CallableCache::get_contacts_by_account] Getting all contacts for account: {}",
141 account_id
142 );
143
144 let con = self.redis_connection();
145 let hash_key = AccountKeys::contacts(account_id);
146
147 let contacts: Vec<Contact> = get_items(con, &hash_key).await?;
148 let arc_contacts: Vec<Arc<Contact>> = contacts.into_iter().map(Arc::new).collect();
149
150 println!(
151 "[CallableCache::get_contacts_by_account] Found {} contacts",
152 arc_contacts.len()
153 );
154 Ok(arc_contacts)
155 }
156
157 pub async fn get_contacts_by_group(
166 &self,
167 account_id: &str,
168 group: &str,
169 ) -> Result<Vec<Arc<Contact>>, RedisError> {
170 println!(
171 "[CallableCache::get_contacts_by_group] Getting contacts for group: {} in account: {}",
172 group, account_id
173 );
174
175 let all_contacts = self.get_contacts_by_account(account_id).await?;
176
177 let filtered: Vec<Arc<Contact>> = all_contacts
178 .into_iter()
179 .filter(|contact| contact.is_in_group(group))
180 .collect();
181
182 println!(
183 "[CallableCache::get_contacts_by_group] Found {} contacts in group",
184 filtered.len()
185 );
186 Ok(filtered)
187 }
188
189 pub async fn delete_contact(
198 &self,
199 account_id: &str,
200 contact_id: &str,
201 ) -> Result<bool, RedisError> {
202 println!(
203 "[CallableCache::delete_contact] Deleting contact {} from account: {}",
204 contact_id, account_id
205 );
206
207 if let Some(contact) = self.get_contact_by_id(account_id, contact_id).await? {
209 let mut con = self.redis_connection();
210 let idents_key = AccountKeys::contact_idents(account_id);
211
212 con.hdel(&idents_key, &contact.primary).await?;
214
215 if let Some(ref secondary) = contact.secondary {
216 con.hdel(&idents_key, secondary).await?;
217 }
218
219 if let Some(ref tertiary) = contact.tertiary {
220 con.hdel(&idents_key, tertiary).await?;
221 }
222
223 if let Some(ref email) = contact.email {
224 con.hdel(&idents_key, email).await?;
225 }
226
227 let hash_key = AccountKeys::contacts(account_id);
229 let deleted: bool = con.hdel(&hash_key, contact_id).await?;
230
231 if deleted {
232 println!("[CallableCache::delete_contact] Successfully deleted contact");
233 }
234
235 Ok(deleted)
236 } else {
237 println!("[CallableCache::delete_contact] Contact not found");
238 Ok(false)
239 }
240 }
241
242 pub async fn insert_contacts(&self, contacts: Vec<Contact>) -> Result<(), RedisError> {
250 println!(
251 "[CallableCache::insert_contacts] Inserting {} contacts",
252 contacts.len()
253 );
254
255 if contacts.is_empty() {
256 return Ok(());
257 }
258
259 let mut con = self.redis_connection();
260 let mut pipe = redis::pipe();
261
262 let mut contacts_by_account: std::collections::HashMap<String, Vec<Contact>> = std::collections::HashMap::new();
264
265 for contact in contacts {
266 contacts_by_account
267 .entry(contact.account.id.clone())
268 .or_insert_with(Vec::new)
269 .push(contact);
270 }
271
272 for (account_id, account_contacts) in contacts_by_account {
274 let hash_key = AccountKeys::contacts(&account_id);
275 let idents_key = AccountKeys::contact_idents(&account_id);
276
277 for contact in account_contacts {
278 let value = serialize_to_json(&contact)?;
279 pipe.hset(&hash_key, &contact.id, &value);
280
281 pipe.hset(&idents_key, &contact.primary, &contact.id);
283
284 if let Some(ref secondary) = contact.secondary {
285 pipe.hset(&idents_key, secondary, &contact.id);
286 }
287
288 if let Some(ref tertiary) = contact.tertiary {
289 pipe.hset(&idents_key, tertiary, &contact.id);
290 }
291
292 if let Some(ref email) = contact.email {
293 pipe.hset(&idents_key, email, &contact.id);
294 }
295 }
296 }
297
298 pipe.query_async(&mut con).await?;
299
300 println!("[CallableCache::insert_contacts] Successfully inserted all contacts");
301 Ok(())
302 }
303}