18e381ea Andy McCall 1 month ago ↶
1
2
3
use super :: { now_ms, Pool} ;
4
use sqlx:: FromRow;
5
6
# [ derive ( Clone, Debug, FromRow ) ]
7
pub struct IssueRow {
8
pub id : i64 ,
9
pub repo_id : i64 ,
10
pub number : i64 ,
11
pub title : String,
12
pub body : String,
13
pub author_id : Option< i64 > ,
14
pub author : String,
15
pub state : String,
16
pub reason : String,
17
pub locked : bool ,
18
pub pinned : bool ,
19
pub milestone_id : Option< i64 > ,
20
pub created_ms : i64 ,
21
pub updated_ms : i64 ,
22
pub closed_ms : Option< i64 > ,
23
}
24
25
# [ derive ( Clone, Debug, FromRow ) ]
26
pub struct IssueComment {
27
pub id : i64 ,
28
pub issue_id : i64 ,
29
pub author_id : Option< i64 > ,
30
pub author : String,
31
pub body : String,
32
pub created_ms : i64 ,
33
pub edited_ms : Option< i64 > ,
34
}
35
36
# [ derive ( Clone, Debug, FromRow ) ]
37
pub struct IssueEvent {
38
pub id : i64 ,
39
pub at_ms : i64 ,
40
pub actor : String,
41
pub event : String,
42
pub detail : String,
43
}
44
45
# [ derive ( Clone, Debug, FromRow, PartialEq, Eq ) ]
46
pub struct Label {
47
pub id : i64 ,
48
pub repo_id : i64 ,
49
pub name : String,
50
pub colour : String,
51
pub description : String,
52
}
53
54
# [ derive ( Clone, Debug, FromRow ) ]
55
pub struct Milestone {
56
pub id : i64 ,
57
pub repo_id : i64 ,
58
pub title : String,
59
pub description : String,
60
pub due_ms : Option< i64 > ,
61
pub state : String,
62
}
63
64
pub struct NewIssue < 'a > {
65
pub repo_id : i64 ,
66
pub title : & 'a str ,
67
pub body : & 'a str ,
68
pub author_id : Option< i64 > ,
69
pub author : & 'a str ,
70
}
71
72
pub async fn create ( pool : & Pool, i : NewIssue< '_ > ) -> sqlx:: Result< IssueRow> {
73
let number = super :: proposals:: next_number( pool, i.repo_id) .await? ;
74
let now = now_ms ( ) ;
5d90e0e0 Andy McCall 20 days ago
75
sqlx:: query_as( " INSERT INTO issues (repo_id, number, title, body, author_id, author, created_ms, updated_ms) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *" )
18e381ea Andy McCall 1 month ago ↶
76
.bind ( i.repo_id)
77
.bind ( number)
78
.bind ( i.title)
79
.bind ( i.body)
80
.bind ( i.author_id)
81
.bind ( i.author)
82
.bind ( now)
83
.bind ( now)
84
.fetch_one ( pool)
85
.await
86
}
87
88
pub async fn get ( pool : & Pool, repo_id : i64 , number : i64 ) -> sqlx:: Result< Option< IssueRow> > {
5d90e0e0 Andy McCall 20 days ago
89
sqlx:: query_as( " SELECT * FROM issues WHERE repo_id = $1 AND number = $2" ) .bind ( repo_id) .bind ( number) .fetch_optional ( pool) .await
18e381ea Andy McCall 1 month ago ↶
90
}
91
92
pub async fn get_by_id ( pool : & Pool, id : i64 ) -> sqlx:: Result< Option< IssueRow> > {
5d90e0e0 Andy McCall 20 days ago
93
sqlx:: query_as( " SELECT * FROM issues WHERE id = $1" ) .bind ( id) .fetch_optional ( pool) .await
18e381ea Andy McCall 1 month ago ↶
94
}
95
96
pub async fn list ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< Vec< IssueRow> > {
5d90e0e0 Andy McCall 20 days ago
97
sqlx:: query_as( " SELECT * FROM issues WHERE repo_id = $1 ORDER BY pinned DESC, number DESC" ) .bind ( repo_id) .fetch_all ( pool) .await
18e381ea Andy McCall 1 month ago ↶
98
}
99
100
101
pub async fn numbers ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< ( Vec< i64 > , Vec< i64 > ) > {
5d90e0e0 Andy McCall 20 days ago
102
let issues: Vec< i64 > = sqlx:: query_scalar( " SELECT number FROM issues WHERE repo_id = $1" ) .bind ( repo_id) .fetch_all ( pool) .await? ;
103
let proposals: Vec< i64 > = sqlx:: query_scalar( " SELECT number FROM proposals WHERE repo_id = $1" ) .bind ( repo_id) .fetch_all ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
104
Ok ( ( issues, proposals) )
105
}
106
107
pub async fn assigned_to ( pool : & Pool, account_id : i64 ) -> sqlx:: Result< Vec< IssueRow> > {
5d90e0e0 Andy McCall 20 days ago
108
sqlx:: query_as( " SELECT i.* FROM issues i JOIN issue_assignees a ON a.issue_id = i.id WHERE a.account_id = $1 AND i.state = 'open' ORDER BY i.updated_ms DESC" )
18e381ea Andy McCall 1 month ago ↶
109
.bind ( account_id)
110
.fetch_all ( pool)
111
.await
112
}
113
114
pub async fn edit ( pool : & Pool, id : i64 , title : & str , body : & str ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
115
sqlx:: query( " UPDATE issues SET title = $1, body = $2, updated_ms = $3 WHERE id = $4" )
18e381ea Andy McCall 1 month ago ↶
116
.bind ( title)
117
.bind ( body)
118
.bind ( now_ms ( ) )
119
.bind ( id)
120
.execute ( pool)
121
.await? ;
122
Ok ( ( ) )
123
}
124
125
pub async fn set_state ( pool : & Pool, id : i64 , state : & str , reason : & str ) -> sqlx:: Result< ( ) > {
126
let now = now_ms ( ) ;
127
let closed: Option< i64 > = if state = = " closed" { Some ( now) } else { None } ;
5d90e0e0 Andy McCall 20 days ago
128
sqlx:: query( " UPDATE issues SET state = $1, reason = $2, closed_ms = $3, updated_ms = $4 WHERE id = $5" )
18e381ea Andy McCall 1 month ago ↶
129
.bind ( state)
130
.bind ( reason)
131
.bind ( closed)
132
.bind ( now)
133
.bind ( id)
134
.execute ( pool)
135
.await? ;
1000b40a Andy McCall 10 days ago ↶
136
if state = = " closed" {
137
finished ( pool, " issues" , id) .await? ;
138
}
18e381ea Andy McCall 1 month ago ↶
139
Ok ( ( ) )
1000b40a Andy McCall 10 days ago ↶
140
}
141
142
143
pub ( super ) async fn finished ( pool : & Pool, table : & str , id : i64 ) -> sqlx:: Result< ( ) > {
144
let at: Option< ( i64 , i64 ) > =
145
sqlx:: query_as( & format! ( " SELECT repo_id, number FROM {table} WHERE id = $1" ) ) .bind ( id) .fetch_optional ( pool) .await? ;
146
match at {
147
Some ( ( repo, number) ) => super :: projects:: finished( pool, repo, number) .await,
148
None => Ok ( ( ) ) ,
149
}
18e381ea Andy McCall 1 month ago ↶
150
}
151
152
pub async fn set_flags ( pool : & Pool, id : i64 , locked : Option< bool > , pinned : Option< bool > ) -> sqlx:: Result< ( ) > {
153
if let Some ( l) = locked {
5d90e0e0 Andy McCall 20 days ago
154
sqlx:: query( " UPDATE issues SET locked = $1 WHERE id = $2" ) .bind ( l) .bind ( id) .execute ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
155
}
156
if let Some ( p) = pinned {
5d90e0e0 Andy McCall 20 days ago
157
sqlx:: query( " UPDATE issues SET pinned = $1 WHERE id = $2" ) .bind ( p) .bind ( id) .execute ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
158
}
159
Ok ( ( ) )
160
}
161
162
pub async fn set_milestone ( pool : & Pool, id : i64 , milestone_id : Option< i64 > ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
163
sqlx:: query( " UPDATE issues SET milestone_id = $1, updated_ms = $2 WHERE id = $3" )
18e381ea Andy McCall 1 month ago ↶
164
.bind ( milestone_id)
165
.bind ( now_ms ( ) )
166
.bind ( id)
167
.execute ( pool)
168
.await? ;
169
Ok ( ( ) )
170
}
171
172
pub async fn touch ( pool : & Pool, id : i64 ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
173
sqlx:: query( " UPDATE issues SET updated_ms = $1 WHERE id = $2" ) .bind ( now_ms ( ) ) .bind ( id) .execute ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
174
Ok ( ( ) )
175
}
176
177
pub async fn comments ( pool : & Pool, issue_id : i64 ) -> sqlx:: Result< Vec< IssueComment> > {
5d90e0e0 Andy McCall 20 days ago
178
sqlx:: query_as( " SELECT * FROM issue_comments WHERE issue_id = $1 ORDER BY created_ms, id" ) .bind ( issue_id) .fetch_all ( pool) .await
18e381ea Andy McCall 1 month ago ↶
179
}
180
181
pub async fn add_comment ( pool : & Pool, issue_id : i64 , author_id : Option< i64 > , author : & str , body : & str ) -> sqlx:: Result< IssueComment> {
5d90e0e0 Andy McCall 20 days ago
182
let row = sqlx:: query_as(
183
" INSERT INTO issue_comments (issue_id, author_id, author, body, created_ms) VALUES ($1, $2, $3, $4, $5) RETURNING *" ,
184
)
185
.bind ( issue_id)
186
.bind ( author_id)
187
.bind ( author)
188
.bind ( body)
189
.bind ( now_ms ( ) )
190
.fetch_one ( pool)
191
.await? ;
18e381ea Andy McCall 1 month ago ↶
192
touch ( pool, issue_id) .await? ;
193
Ok ( row)
194
}
195
196
pub async fn edit_comment ( pool : & Pool, id : i64 , author_id : i64 , body : & str ) -> sqlx:: Result< bool > {
5d90e0e0 Andy McCall 20 days ago
197
let n = sqlx:: query( " UPDATE issue_comments SET body = $1, edited_ms = $2 WHERE id = $3 AND author_id = $4" )
18e381ea Andy McCall 1 month ago ↶
198
.bind ( body)
199
.bind ( now_ms ( ) )
200
.bind ( id)
201
.bind ( author_id)
202
.execute ( pool)
203
.await? ;
204
Ok ( n.rows_affected ( ) > 0 )
205
}
206
207
pub async fn delete_comment ( pool : & Pool, id : i64 ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
208
sqlx:: query( " DELETE FROM issue_comments WHERE id = $1" ) .bind ( id) .execute ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
209
Ok ( ( ) )
210
}
211
212
pub async fn events ( pool : & Pool, issue_id : i64 ) -> sqlx:: Result< Vec< IssueEvent> > {
5d90e0e0 Andy McCall 20 days ago
213
sqlx:: query_as( " SELECT id, at_ms, actor, event, detail FROM issue_events WHERE issue_id = $1 ORDER BY at_ms, id" )
18e381ea Andy McCall 1 month ago ↶
214
.bind ( issue_id)
215
.fetch_all ( pool)
216
.await
217
}
218
8bb7baeb Andy McCall 10 days ago ↶
219
220
221
pub async fn referenced_by ( pool : & Pool, issue_id : i64 , hash : & str ) -> sqlx:: Result< bool > {
222
let n: i64 = sqlx:: query_scalar(
223
" SELECT COUNT(*) FROM issue_events WHERE issue_id = $1 AND event = 'referenced by change' AND (detail = $2 OR detail LIKE $3)" ,
224
)
225
.bind ( issue_id)
226
.bind ( hash)
227
.bind ( format! ( " {hash} %" ) )
228
.fetch_one ( pool)
229
.await? ;
230
Ok ( n > 0 )
231
}
232
18e381ea Andy McCall 1 month ago ↶
233
pub async fn add_event ( pool : & Pool, issue_id : i64 , actor : & str , event : & str , detail : & str ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
234
sqlx:: query( " INSERT INTO issue_events (issue_id, at_ms, actor, event, detail) VALUES ($1, $2, $3, $4, $5)" )
18e381ea Andy McCall 1 month ago ↶
235
.bind ( issue_id)
236
.bind ( now_ms ( ) )
237
.bind ( actor)
238
.bind ( event)
239
.bind ( detail)
240
.execute ( pool)
241
.await? ;
242
Ok ( ( ) )
243
}
244
245
246
247
pub async fn labels ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< Vec< Label> > {
5d90e0e0 Andy McCall 20 days ago
248
sqlx:: query_as( " SELECT * FROM labels WHERE repo_id = $1 ORDER BY name" ) .bind ( repo_id) .fetch_all ( pool) .await
18e381ea Andy McCall 1 month ago ↶
249
}
250
251
pub async fn label_by_name ( pool : & Pool, repo_id : i64 , name : & str ) -> sqlx:: Result< Option< Label> > {
5d90e0e0 Andy McCall 20 days ago
252
sqlx:: query_as( " SELECT * FROM labels WHERE repo_id = $1 AND name = $2" ) .bind ( repo_id) .bind ( name) .fetch_optional ( pool) .await
18e381ea Andy McCall 1 month ago ↶
253
}
254
255
pub async fn upsert_label ( pool : & Pool, repo_id : i64 , name : & str , colour : & str , description : & str ) -> sqlx:: Result< Label> {
5d90e0e0 Andy McCall 20 days ago
256
sqlx:: query_as( " INSERT INTO labels (repo_id, name, colour, description) VALUES ($1, $2, $3, $4) ON CONFLICT (repo_id, name) DO UPDATE SET colour = excluded.colour, description = excluded.description RETURNING *" )
18e381ea Andy McCall 1 month ago ↶
257
.bind ( repo_id)
258
.bind ( name)
259
.bind ( colour)
260
.bind ( description)
261
.fetch_one ( pool)
262
.await
263
}
264
265
pub async fn delete_label ( pool : & Pool, id : i64 ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
266
sqlx:: query( " DELETE FROM labels WHERE id = $1" ) .bind ( id) .execute ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
267
Ok ( ( ) )
268
}
269
270
pub async fn issue_labels ( pool : & Pool, issue_id : i64 ) -> sqlx:: Result< Vec< Label> > {
5d90e0e0 Andy McCall 20 days ago
271
sqlx:: query_as( " SELECT l.* FROM labels l JOIN issue_labels il ON il.label_id = l.id WHERE il.issue_id = $1 ORDER BY l.name" )
18e381ea Andy McCall 1 month ago ↶
272
.bind ( issue_id)
273
.fetch_all ( pool)
274
.await
275
}
276
277
pub async fn set_issue_label ( pool : & Pool, issue_id : i64 , label_id : i64 , on : bool ) -> sqlx:: Result< ( ) > {
278
if on {
d1bf2d69 Andy McCall 20 days ago ↶
279
sqlx:: query( " INSERT INTO issue_labels (issue_id, label_id) VALUES ($1, $2) ON CONFLICT DO NOTHING" )
18e381ea Andy McCall 1 month ago ↶
280
.bind ( issue_id)
281
.bind ( label_id)
282
.execute ( pool)
283
.await? ;
284
} else {
5d90e0e0 Andy McCall 20 days ago
285
sqlx:: query( " DELETE FROM issue_labels WHERE issue_id = $1 AND label_id = $2" ) .bind ( issue_id) .bind ( label_id) .execute ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
286
}
287
Ok ( ( ) )
288
}
289
290
1ac84c62 Andy McCall 1 month ago ↶
291
292
pub async fn labels_by_proposal ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< Vec< ( i64 , Label) > > {
293
let rows: Vec< ( i64 , i64 , i64 , String, String, String) > = sqlx:: query_as(
5d90e0e0 Andy McCall 20 days ago
294
" SELECT pl.proposal_id, l.id, l.repo_id, l.name, l.colour, l.description FROM proposal_labels pl JOIN labels l ON l.id = pl.label_id JOIN proposals p ON p.id = pl.proposal_id WHERE p.repo_id = $1 ORDER BY l.name" ,
1ac84c62 Andy McCall 1 month ago ↶
295
)
296
.bind ( repo_id)
297
.fetch_all ( pool)
298
.await? ;
299
Ok ( rows
300
.into_iter ( )
301
.map ( | ( proposal_id , id , repo_id , name , colour , description ) | ( proposal_id, Label { id, repo_id, name, colour, description } ) )
302
.collect ( ) )
303
}
304
18e381ea Andy McCall 1 month ago ↶
305
pub async fn labels_by_issue ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< Vec< ( i64 , Label) > > {
306
let rows: Vec< ( i64 , i64 , i64 , String, String, String) > = sqlx:: query_as(
5d90e0e0 Andy McCall 20 days ago
307
" SELECT il.issue_id, l.id, l.repo_id, l.name, l.colour, l.description FROM issue_labels il JOIN labels l ON l.id = il.label_id JOIN issues i ON i.id = il.issue_id WHERE i.repo_id = $1 ORDER BY l.name" ,
18e381ea Andy McCall 1 month ago ↶
308
)
309
.bind ( repo_id)
310
.fetch_all ( pool)
311
.await? ;
312
Ok ( rows
313
.into_iter ( )
314
.map ( | ( issue_id , id , repo_id , name , colour , description ) | ( issue_id, Label { id, repo_id, name, colour, description } ) )
315
.collect ( ) )
316
}
317
318
pub async fn proposal_labels ( pool : & Pool, proposal_id : i64 ) -> sqlx:: Result< Vec< Label> > {
5d90e0e0 Andy McCall 20 days ago
319
sqlx:: query_as( " SELECT l.* FROM labels l JOIN proposal_labels pl ON pl.label_id = l.id WHERE pl.proposal_id = $1 ORDER BY l.name" )
18e381ea Andy McCall 1 month ago ↶
320
.bind ( proposal_id)
321
.fetch_all ( pool)
322
.await
323
}
324
325
pub async fn set_proposal_label ( pool : & Pool, proposal_id : i64 , label_id : i64 , on : bool ) -> sqlx:: Result< ( ) > {
326
if on {
d1bf2d69 Andy McCall 20 days ago ↶
327
sqlx:: query( " INSERT INTO proposal_labels (proposal_id, label_id) VALUES ($1, $2) ON CONFLICT DO NOTHING" )
18e381ea Andy McCall 1 month ago ↶
328
.bind ( proposal_id)
329
.bind ( label_id)
330
.execute ( pool)
331
.await? ;
332
} else {
5d90e0e0 Andy McCall 20 days ago
333
sqlx:: query( " DELETE FROM proposal_labels WHERE proposal_id = $1 AND label_id = $2" )
18e381ea Andy McCall 1 month ago ↶
334
.bind ( proposal_id)
335
.bind ( label_id)
336
.execute ( pool)
337
.await? ;
338
}
339
Ok ( ( ) )
340
}
341
342
343
344
pub async fn assignees ( pool : & Pool, issue_id : i64 ) -> sqlx:: Result< Vec< String> > {
345
sqlx:: query_scalar(
5d90e0e0 Andy McCall 20 days ago
346
" SELECT a.username FROM accounts a JOIN issue_assignees ia ON ia.account_id = a.id WHERE ia.issue_id = $1 ORDER BY a.username" ,
18e381ea Andy McCall 1 month ago ↶
347
)
348
.bind ( issue_id)
349
.fetch_all ( pool)
350
.await
351
}
352
353
pub async fn set_assignee ( pool : & Pool, issue_id : i64 , account_id : i64 , on : bool ) -> sqlx:: Result< ( ) > {
354
if on {
d1bf2d69 Andy McCall 20 days ago ↶
355
sqlx:: query( " INSERT INTO issue_assignees (issue_id, account_id) VALUES ($1, $2) ON CONFLICT DO NOTHING" )
18e381ea Andy McCall 1 month ago ↶
356
.bind ( issue_id)
357
.bind ( account_id)
358
.execute ( pool)
359
.await? ;
360
} else {
5d90e0e0 Andy McCall 20 days ago
361
sqlx:: query( " DELETE FROM issue_assignees WHERE issue_id = $1 AND account_id = $2" )
18e381ea Andy McCall 1 month ago ↶
362
.bind ( issue_id)
363
.bind ( account_id)
364
.execute ( pool)
365
.await? ;
366
}
367
Ok ( ( ) )
368
}
369
370
371
pub async fn assignees_by_issue ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< Vec< ( i64 , String) > > {
5d90e0e0 Andy McCall 20 days ago
372
sqlx:: query_as( " SELECT ia.issue_id, a.username FROM issue_assignees ia JOIN accounts a ON a.id = ia.account_id JOIN issues i ON i.id = ia.issue_id WHERE i.repo_id = $1" )
18e381ea Andy McCall 1 month ago ↶
373
.bind ( repo_id)
374
.fetch_all ( pool)
375
.await
376
}
377
378
379
380
pub async fn milestones ( pool : & Pool, repo_id : i64 ) -> sqlx:: Result< Vec< Milestone> > {
5d90e0e0 Andy McCall 20 days ago
381
sqlx:: query_as( " SELECT * FROM milestones WHERE repo_id = $1 ORDER BY state, due_ms, title" ) .bind ( repo_id) .fetch_all ( pool) .await
18e381ea Andy McCall 1 month ago ↶
382
}
383
384
pub async fn milestone ( pool : & Pool, id : i64 ) -> sqlx:: Result< Option< Milestone> > {
5d90e0e0 Andy McCall 20 days ago
385
sqlx:: query_as( " SELECT * FROM milestones WHERE id = $1" ) .bind ( id) .fetch_optional ( pool) .await
18e381ea Andy McCall 1 month ago ↶
386
}
387
388
pub async fn upsert_milestone ( pool : & Pool, repo_id : i64 , title : & str , description : & str , due_ms : Option< i64 > ) -> sqlx:: Result< Milestone> {
5d90e0e0 Andy McCall 20 days ago
389
sqlx:: query_as( " INSERT INTO milestones (repo_id, title, description, due_ms) VALUES ($1, $2, $3, $4) ON CONFLICT (repo_id, title) DO UPDATE SET description = excluded.description, due_ms = excluded.due_ms RETURNING *" )
18e381ea Andy McCall 1 month ago ↶
390
.bind ( repo_id)
391
.bind ( title)
392
.bind ( description)
393
.bind ( due_ms)
394
.fetch_one ( pool)
395
.await
396
}
397
5ea4872f Andy McCall 1 month ago ↶
398
399
pub async fn update_milestone ( pool : & Pool, id : i64 , title : & str , description : & str , due_ms : Option< i64 > ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
400
sqlx:: query( " UPDATE milestones SET title = $1, description = $2, due_ms = $3 WHERE id = $4" )
5ea4872f Andy McCall 1 month ago ↶
401
.bind ( title)
402
.bind ( description)
403
.bind ( due_ms)
404
.bind ( id)
405
.execute ( pool)
406
.await? ;
407
Ok ( ( ) )
408
}
409
18e381ea Andy McCall 1 month ago ↶
410
pub async fn set_milestone_state ( pool : & Pool, id : i64 , state : & str ) -> sqlx:: Result< ( ) > {
5d90e0e0 Andy McCall 20 days ago
411
sqlx:: query( " UPDATE milestones SET state = $1 WHERE id = $2" ) .bind ( state) .bind ( id) .execute ( pool) .await? ;
18e381ea Andy McCall 1 month ago ↶
412
Ok ( ( ) )
413
}
414
415
416
pub async fn milestone_counts ( pool : & Pool, milestone_id : i64 ) -> sqlx:: Result< ( i64 , i64 ) > {
5d90e0e0 Andy McCall 20 days ago
417
let open: i64 = sqlx:: query_scalar( " SELECT COUNT(*) FROM issues WHERE milestone_id = $1 AND state = 'open'" )
18e381ea Andy McCall 1 month ago ↶
418
.bind ( milestone_id)
419
.fetch_one ( pool)
420
.await? ;
5d90e0e0 Andy McCall 20 days ago
421
let closed: i64 = sqlx:: query_scalar( " SELECT COUNT(*) FROM issues WHERE milestone_id = $1 AND state = 'closed'" )
18e381ea Andy McCall 1 month ago ↶
422
.bind ( milestone_id)
423
.fetch_one ( pool)
424
.await? ;
425
Ok ( ( open, closed) )
426
}