summaryrefslogtreecommitdiff
path: root/src/database/friends.rs
blob: 0b7848818cd1e437e7238b5fe1daf0f3c99881b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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<u8, rusqlite::Error> {
    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<u64> = 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<Vec<User>, 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<bool, rusqlite::Error> {
    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<bool, rusqlite::Error> {
    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)
}