18e381ea Andy McCall 1 month ago ↶
1
2
3
4
use super :: { now_ms, Pool} ;
5
use sqlx:: FromRow;
6
7
# [ derive ( Clone, Debug, FromRow ) ]
8
pub struct Notification {
9
pub id : i64 ,
10
pub account_id : i64 ,
11
pub at_ms : i64 ,
12
pub kind : String,
13
pub title : String,
14
pub url : String,
15
pub actor : String,
16
pub read : bool ,
17
}
18
19
pub async fn add ( pool : & Pool, account_id : i64 , kind : & str , title : & str , url : & str , actor : & str ) -> sqlx:: Result< ( ) > {
20
sqlx:: query( " INSERT INTO notifications (account_id, at_ms, kind, title, url, actor) VALUES (?, ?, ?, ?, ?, ?)" )
21
.bind ( account_id)
22
.bind ( now_ms ( ) )
23
.bind ( kind)
24
.bind ( title)
25
.bind ( url)
26
.bind ( actor)
27
.execute ( pool)
28
.await? ;
29
Ok ( ( ) )
30
}
31
32
pub async fn inbox ( pool : & Pool, account_id : i64 , limit : i64 ) -> sqlx:: Result< Vec< Notification> > {
33
sqlx:: query_as( " SELECT * FROM notifications WHERE account_id = ? ORDER BY read, at_ms DESC, id DESC LIMIT ?" )
34
.bind ( account_id)
35
.bind ( limit)
36
.fetch_all ( pool)
37
.await
38
}
39
40
pub async fn unread ( pool : & Pool, account_id : i64 ) -> sqlx:: Result< i64 > {
41
sqlx:: query_scalar( " SELECT COUNT(*) FROM notifications WHERE account_id = ? AND read = 0" ) .bind ( account_id) .fetch_one ( pool) .await
42
}
43
44
pub async fn mark_read ( pool : & Pool, account_id : i64 , id : Option< i64 > ) -> sqlx:: Result< ( ) > {
45
match id {
46
Some ( id) => {
47
sqlx:: query( " UPDATE notifications SET read = 1 WHERE account_id = ? AND id = ?" ) .bind ( account_id) .bind ( id) .execute ( pool) .await?
48
}
49
None => sqlx:: query( " UPDATE notifications SET read = 1 WHERE account_id = ?" ) .bind ( account_id) .execute ( pool) .await? ,
50
} ;
51
Ok ( ( ) )
52
}
53
54
55
56
pub async fn watching ( pool : & Pool, account_id : i64 , repo_id : i64 ) -> sqlx:: Result< bool > {
57
let n: i64 = sqlx:: query_scalar( " SELECT COUNT(*) FROM watches WHERE account_id = ? AND repo_id = ?" )
58
.bind ( account_id)
59
.bind ( repo_id)
60
.fetch_one ( pool)
61
.await? ;
62
Ok ( n > 0 )
63
}
64
65
pub async fn set_watch ( pool : & Pool, account_id : i64 , repo_id : i64 , on : bool ) -> sqlx:: Result< ( ) > {
66
if on {
67
sqlx:: query( " INSERT OR IGNORE INTO watches (account_id, repo_id) VALUES (?, ?)" )
68
.bind ( account_id)
69
.bind ( repo_id)
70
.execute ( pool)
71
.await? ;
72
} else {
73
sqlx:: query( " DELETE FROM watches WHERE account_id = ? AND repo_id = ?" ) .bind ( account_id) .bind ( repo_id) .execute ( pool) .await? ;
74
}
75
Ok ( ( ) )
76
}
77
78
pub async fn watchers ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< Vec< i64 > > {
79
sqlx:: query_scalar( " SELECT account_id FROM watches WHERE repo_id = ?" ) .bind ( repo_id) .fetch_all ( pool) .await
80
}
81
82
pub async fn subscribe ( pool : & Pool, account_id : i64 , kind : & str , target_id : i64 ) -> sqlx:: Result< ( ) > {
83
sqlx:: query( " INSERT OR IGNORE INTO subscriptions (account_id, kind, target_id) VALUES (?, ?, ?)" )
84
.bind ( account_id)
85
.bind ( kind)
86
.bind ( target_id)
87
.execute ( pool)
88
.await? ;
89
Ok ( ( ) )
90
}
91
92
pub async fn unsubscribe ( pool : & Pool, account_id : i64 , kind : & str , target_id : i64 ) -> sqlx:: Result< ( ) > {
93
sqlx:: query( " DELETE FROM subscriptions WHERE account_id = ? AND kind = ? AND target_id = ?" )
94
.bind ( account_id)
95
.bind ( kind)
96
.bind ( target_id)
97
.execute ( pool)
98
.await? ;
99
Ok ( ( ) )
100
}
101
102
pub async fn subscribed ( pool : & Pool, account_id : i64 , kind : & str , target_id : i64 ) -> sqlx:: Result< bool > {
103
let n: i64 = sqlx:: query_scalar( " SELECT COUNT(*) FROM subscriptions WHERE account_id = ? AND kind = ? AND target_id = ?" )
104
.bind ( account_id)
105
.bind ( kind)
106
.bind ( target_id)
107
.fetch_one ( pool)
108
.await? ;
109
Ok ( n > 0 )
110
}
111
112
pub async fn subscribers ( pool : & Pool, kind : & str , target_id : i64 ) -> sqlx:: Result< Vec< i64 > > {
113
sqlx:: query_scalar( " SELECT account_id FROM subscriptions WHERE kind = ? AND target_id = ?" )
114
.bind ( kind)
115
.bind ( target_id)
116
.fetch_all ( pool)
117
.await
118
}
119
120
121
122
# [ derive ( Clone, Debug, FromRow ) ]
123
pub struct Hit {
124
pub kind : String,
125
pub repo_id : i64 ,
126
pub target_id : i64 ,
127
pub number : i64 ,
128
pub title : String,
129
pub snippet : String,
130
}
131
132
133
pub async fn index ( pool : & Pool, kind : & str , repo_id : i64 , target_id : i64 , number : i64 , title : & str , body : & str ) -> sqlx:: Result< ( ) > {
134
sqlx:: query( " DELETE FROM search WHERE kind = ? AND target_id = ?" ) .bind ( kind) .bind ( target_id) .execute ( pool) .await? ;
135
sqlx:: query( " INSERT INTO search (kind, repo_id, target_id, number, title, body) VALUES (?, ?, ?, ?, ?, ?)" )
136
.bind ( kind)
137
.bind ( repo_id)
138
.bind ( target_id)
139
.bind ( number)
140
.bind ( title)
141
.bind ( body)
142
.execute ( pool)
143
.await? ;
144
Ok ( ( ) )
145
}
146
147
148
149
pub async fn search ( pool : & Pool, query : & str , repo_id : Option< i64 > , limit : i64 ) -> sqlx:: Result< Vec< Hit> > {
150
let terms: Vec< String> = query.split_whitespace ( ) .map ( | t | format! ( " \" {} \" " , t.replace ( ' "' , " " ) ) ) .collect ( ) ;
151
if terms.is_empty ( ) {
152
return Ok ( vec! [ ] ) ;
153
}
154
let q = terms.join ( " " ) ;
155
let sql = " SELECT kind, repo_id, target_id, number, title, snippet(search, 5, '<mark>', '</mark>', '…', 12) AS snippet FROM search WHERE search MATCH ? AND (? IS NULL OR repo_id = ?) ORDER BY rank LIMIT ?" ;
156
sqlx:: query_as( sql) .bind ( q) .bind ( repo_id) .bind ( repo_id) .bind ( limit) .fetch_all ( pool) .await
157
}