use std::collections::{BTreeSet, HashMap, HashSet};
use crate::{
error::table::TableError,
tables::table::{
Cacheable, Deduplicate, Diagnostic, Table, CHAT_HANDLE_JOIN, CHAT_MESSAGE_JOIN,
},
util::output::{done_processing, processing},
};
use rusqlite::{Connection, Error, Result, Row, Statement};
pub struct ChatToHandle {
chat_id: i32,
handle_id: i32,
}
impl Table for ChatToHandle {
fn from_row(row: &Row) -> Result<ChatToHandle> {
Ok(ChatToHandle {
chat_id: row.get("chat_id")?,
handle_id: row.get("handle_id")?,
})
}
fn get(db: &Connection) -> Result<Statement, TableError> {
db.prepare(&format!("SELECT * FROM {}", CHAT_HANDLE_JOIN))
.map_err(TableError::ChatToHandle)
}
fn extract(chat_to_handle: Result<Result<Self, Error>, Error>) -> Result<Self, TableError> {
match chat_to_handle {
Ok(chat_to_handle) => match chat_to_handle {
Ok(c2h) => Ok(c2h),
Err(why) => Err(TableError::ChatToHandle(why)),
},
Err(why) => Err(TableError::ChatToHandle(why)),
}
}
}
impl Cacheable for ChatToHandle {
type K = i32;
type V = BTreeSet<i32>;
fn cache(db: &Connection) -> Result<HashMap<Self::K, Self::V>, TableError> {
let mut cache: HashMap<i32, BTreeSet<i32>> = HashMap::new();
let mut rows = ChatToHandle::get(db)?;
let mappings = rows
.query_map([], |row| Ok(ChatToHandle::from_row(row)))
.unwrap();
for mapping in mappings {
let joiner = ChatToHandle::extract(mapping)?;
match cache.get_mut(&joiner.chat_id) {
Some(handles) => {
handles.insert(joiner.handle_id);
}
None => {
let mut data_to_cache = BTreeSet::new();
data_to_cache.insert(joiner.handle_id);
cache.insert(joiner.chat_id, data_to_cache);
}
}
}
Ok(cache)
}
}
impl Deduplicate for ChatToHandle {
type T = BTreeSet<i32>;
fn dedupe(duplicated_data: &HashMap<i32, Self::T>) -> HashMap<i32, i32> {
let mut deduplicated_chats: HashMap<i32, i32> = HashMap::new();
let mut participants_to_unique_chat_id: HashMap<Self::T, i32> = HashMap::new();
let mut unique_chat_identifier = 0;
for (chat_id, participants) in duplicated_data {
match participants_to_unique_chat_id.get(participants) {
Some(id) => {
deduplicated_chats.insert(chat_id.to_owned(), id.to_owned());
}
None => {
participants_to_unique_chat_id
.insert(participants.to_owned(), unique_chat_identifier);
deduplicated_chats.insert(chat_id.to_owned(), unique_chat_identifier);
unique_chat_identifier += 1;
}
}
}
deduplicated_chats
}
}
impl Diagnostic for ChatToHandle {
fn run_diagnostic(db: &Connection) {
processing();
let mut statement_message_chats = db
.prepare(&format!("SELECT DISTINCT chat_id from {CHAT_MESSAGE_JOIN}"))
.unwrap();
let statement_message_chat_rows = statement_message_chats
.query_map([], |row: &Row| -> Result<i32> { row.get(0) })
.unwrap();
let mut unique_chats_from_messages: HashSet<i32> = HashSet::new();
statement_message_chat_rows.into_iter().for_each(|row| {
unique_chats_from_messages.insert(row.unwrap());
});
let mut statement_handle_chats = db
.prepare(&format!("SELECT DISTINCT chat_id from {CHAT_HANDLE_JOIN}"))
.unwrap();
let statement_handle_chat_rows = statement_handle_chats
.query_map([], |row: &Row| -> Result<i32> { row.get(0) })
.unwrap();
let mut unique_chats_from_handles: HashSet<i32> = HashSet::new();
statement_handle_chat_rows.into_iter().for_each(|row| {
unique_chats_from_handles.insert(row.unwrap());
});
done_processing();
let chats_with_no_handles = unique_chats_from_messages
.difference(&unique_chats_from_handles)
.count();
if chats_with_no_handles > 0 {
println!("\rChats with no handles: {chats_with_no_handles:?}");
}
}
}