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
98
99
100
|
use tracing::instrument;
use crate::types::user::{User, FOLLOWED, FOLLOWING, NO_RELATION};
use super::Database;
impl Database {
pub fn init_friends(&self) -> 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)
);
";
self.0.execute(sql, ())?;
Ok(())
}
#[instrument(skip(self))]
pub fn get_friend_status(&self, user_id_1: u64, user_id_2: u64) -> Result<u8, rusqlite::Error> {
tracing::trace!("Retrieving friend status");
let mut stmt = self.0.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(skip(self))]
pub fn get_friends(&self, user_id: u64) -> Result<Vec<User>, rusqlite::Error> {
tracing::trace!("Retrieving friends");
let mut stmt = self.0.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 = Self::user_from_row(row, true)?;
Ok(row)
})?;
Ok(row.into_iter().flatten().collect())
}
#[instrument(skip(self))]
pub fn set_following(&self, user_id_1: u64, user_id_2: u64) -> Result<bool, rusqlite::Error> {
tracing::trace!("Setting following");
let mut stmt = self
.0
.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(skip(self))]
pub fn remove_following(
&self,
user_id_1: u64,
user_id_2: u64,
) -> Result<bool, rusqlite::Error> {
tracing::trace!("Removing following");
let mut stmt = self
.0
.prepare("DELETE FROM friends WHERE follower_id = ? AND followee_id = ?")?;
let changes = stmt.execute([user_id_1, user_id_2])?;
Ok(changes == 1)
}
}
|