use tracing::instrument; use crate::{ database::{self, users::user_from_row}, types::user::{User, FOLLOWED, FOLLOWING, NO_RELATION}, }; pub fn init() -> Result<(), rusqlite::Error> { let sql = " CREATE TABLE IF NOT EXISTS friends ( follower_id INTEGER NOT NULL, followee_id INTEGER NOT NULL, FOREIGN KEY(follower_id) REFERENCES users(user_id), FOREIGN KEY(followee_id) REFERENCES users(user_id), PRIMARY KEY (follower_id, followee_id) ); "; let conn = database::connect()?; conn.execute(sql, ())?; Ok(()) } #[instrument()] pub fn get_friend_status(user_id_1: u64, user_id_2: u64) -> Result { tracing::trace!("Retrieving friend status"); let conn = database::connect()?; let mut stmt = conn.prepare("SELECT * FROM friends WHERE (follower_id = ? AND followee_id = ?) OR (follower_id = ? AND followee_id = ?);")?; let mut status = NO_RELATION; let rows: Vec = stmt .query_map([user_id_1, user_id_2, user_id_2, user_id_1], |row| { let id: u64 = row.get(0)?; Ok(id) })? .into_iter() .flatten() .collect(); for follower in rows { if follower == user_id_1 { status |= FOLLOWING; } if follower == user_id_2 { status |= FOLLOWED; } } Ok(status) } #[instrument()] pub fn get_friends(user_id: u64) -> Result, rusqlite::Error> { tracing::trace!("Retrieving friends"); let conn = database::connect()?; let mut stmt = conn.prepare( " SELECT * FROM users u WHERE EXISTS ( SELECT NULL FROM friends f WHERE u.user_id = f.follower_id AND f.followee_id = ? ) AND EXISTS ( SELECT NULL FROM friends f WHERE u.user_id = f.followee_id AND f.follower_id = ? ) ", )?; let row = stmt.query_map([user_id, user_id], |row| { let row = user_from_row(row, true)?; Ok(row) })?; Ok(row.into_iter().flatten().collect()) } #[instrument()] pub fn set_following(user_id_1: u64, user_id_2: u64) -> Result { tracing::trace!("Setting following"); let conn = database::connect()?; let mut stmt = conn.prepare("INSERT OR REPLACE INTO friends (follower_id, followee_id) VALUES (?,?)")?; let changes = stmt.execute([user_id_1, user_id_2])?; Ok(changes == 1) } #[instrument()] pub fn remove_following(user_id_1: u64, user_id_2: u64) -> Result { tracing::trace!("Removing following"); let conn = database::connect()?; let mut stmt = conn.prepare("DELETE FROM friends WHERE follower_id = ? AND followee_id = ?")?; let changes = stmt.execute([user_id_1, user_id_2])?; Ok(changes == 1) }