use super::CallableCache;
use crate::common::{deserialize_from_json, get_items, serialize_to_json};
use crate::constants::AccountKeys;
use cal_core::contact::Contact;
use redis::{AsyncCommands, RedisError};
use std::sync::Arc;
impl CallableCache {
pub async fn insert_contact(&self, contact: Contact) -> Result<(), RedisError> {
println!(
"[CallableCache::insert_contact] Inserting contact: {} for account: {}",
contact.id, contact.account.id
);
let mut con = self.redis_connection();
let hash_key = AccountKeys::contacts(&contact.account.id);
let value = serialize_to_json(&contact)?;
con.hset(&hash_key, &contact.id, value).await?;
let idents_key = AccountKeys::contact_idents(&contact.account.id);
con.hset(&idents_key, &contact.primary, &contact.id).await?;
if let Some(ref secondary) = contact.secondary {
con.hset(&idents_key, secondary, &contact.id).await?;
}
if let Some(ref tertiary) = contact.tertiary {
con.hset(&idents_key, tertiary, &contact.id).await?;
}
if let Some(ref email) = contact.email {
con.hset(&idents_key, email, &contact.id).await?;
}
println!("[CallableCache::insert_contact] Successfully inserted contact");
Ok(())
}
pub async fn get_contact_by_id(
&self,
account_id: &str,
contact_id: &str,
) -> Result<Option<Arc<Contact>>, RedisError> {
println!(
"[CallableCache::get_contact_by_id] Getting contact {} for account: {}",
contact_id, account_id
);
let con = self.redis_connection();
let hash_key = AccountKeys::contacts(account_id);
let value: Option<String> = con.clone().hget(&hash_key, contact_id).await?;
match value {
Some(json_str) => {
let contact: Contact = deserialize_from_json(&json_str)?;
println!("[CallableCache::get_contact_by_id] Found contact: {}", contact.name);
Ok(Some(Arc::new(contact)))
}
None => {
println!("[CallableCache::get_contact_by_id] Contact not found");
Ok(None)
}
}
}
pub async fn get_contact_by_ident(
&self,
account_id: &str,
identifier: &str,
) -> Result<Option<Arc<Contact>>, RedisError> {
println!(
"[CallableCache::get_contact_by_ident] Getting contact by identifier: {} for account: {}",
identifier, account_id
);
let con = self.redis_connection();
let idents_key = AccountKeys::contact_idents(account_id);
let contact_id: Option<String> = con.clone().hget(&idents_key, identifier).await?;
match contact_id {
Some(id) => {
self.get_contact_by_id(account_id, &id).await
}
None => {
println!("[CallableCache::get_contact_by_ident] No contact found for identifier");
Ok(None)
}
}
}
pub async fn get_contacts_by_account(
&self,
account_id: &str,
) -> Result<Vec<Arc<Contact>>, RedisError> {
println!(
"[CallableCache::get_contacts_by_account] Getting all contacts for account: {}",
account_id
);
let con = self.redis_connection();
let hash_key = AccountKeys::contacts(account_id);
let contacts: Vec<Contact> = get_items(con, &hash_key).await?;
let arc_contacts: Vec<Arc<Contact>> = contacts.into_iter().map(Arc::new).collect();
println!(
"[CallableCache::get_contacts_by_account] Found {} contacts",
arc_contacts.len()
);
Ok(arc_contacts)
}
pub async fn get_contacts_by_group(
&self,
account_id: &str,
group: &str,
) -> Result<Vec<Arc<Contact>>, RedisError> {
println!(
"[CallableCache::get_contacts_by_group] Getting contacts for group: {} in account: {}",
group, account_id
);
let all_contacts = self.get_contacts_by_account(account_id).await?;
let filtered: Vec<Arc<Contact>> = all_contacts
.into_iter()
.filter(|contact| contact.is_in_group(group))
.collect();
println!(
"[CallableCache::get_contacts_by_group] Found {} contacts in group",
filtered.len()
);
Ok(filtered)
}
pub async fn delete_contact(
&self,
account_id: &str,
contact_id: &str,
) -> Result<bool, RedisError> {
println!(
"[CallableCache::delete_contact] Deleting contact {} from account: {}",
contact_id, account_id
);
if let Some(contact) = self.get_contact_by_id(account_id, contact_id).await? {
let mut con = self.redis_connection();
let idents_key = AccountKeys::contact_idents(account_id);
con.hdel(&idents_key, &contact.primary).await?;
if let Some(ref secondary) = contact.secondary {
con.hdel(&idents_key, secondary).await?;
}
if let Some(ref tertiary) = contact.tertiary {
con.hdel(&idents_key, tertiary).await?;
}
if let Some(ref email) = contact.email {
con.hdel(&idents_key, email).await?;
}
let hash_key = AccountKeys::contacts(account_id);
let deleted: bool = con.hdel(&hash_key, contact_id).await?;
if deleted {
println!("[CallableCache::delete_contact] Successfully deleted contact");
}
Ok(deleted)
} else {
println!("[CallableCache::delete_contact] Contact not found");
Ok(false)
}
}
pub async fn insert_contacts(&self, contacts: Vec<Contact>) -> Result<(), RedisError> {
println!(
"[CallableCache::insert_contacts] Inserting {} contacts",
contacts.len()
);
if contacts.is_empty() {
return Ok(());
}
let mut con = self.redis_connection();
let mut pipe = redis::pipe();
let mut contacts_by_account: std::collections::HashMap<String, Vec<Contact>> = std::collections::HashMap::new();
for contact in contacts {
contacts_by_account
.entry(contact.account.id.clone())
.or_insert_with(Vec::new)
.push(contact);
}
for (account_id, account_contacts) in contacts_by_account {
let hash_key = AccountKeys::contacts(&account_id);
let idents_key = AccountKeys::contact_idents(&account_id);
for contact in account_contacts {
let value = serialize_to_json(&contact)?;
pipe.hset(&hash_key, &contact.id, &value);
pipe.hset(&idents_key, &contact.primary, &contact.id);
if let Some(ref secondary) = contact.secondary {
pipe.hset(&idents_key, secondary, &contact.id);
}
if let Some(ref tertiary) = contact.tertiary {
pipe.hset(&idents_key, tertiary, &contact.id);
}
if let Some(ref email) = contact.email {
pipe.hset(&idents_key, email, &contact.id);
}
}
}
pipe.query_async(&mut con).await?;
println!("[CallableCache::insert_contacts] Successfully inserted all contacts");
Ok(())
}
}