Skip to content

Commit b88c110

Browse files
committed
models/category: Convert toplevel() and count_toplevel() to async fns
1 parent b25201e commit b88c110

File tree

3 files changed

+83
-70
lines changed

3 files changed

+83
-70
lines changed

src/controllers/category.rs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ use super::helpers::pagination::*;
22
use crate::app::AppState;
33
use crate::models::Category;
44
use crate::schema::categories;
5-
use crate::tasks::spawn_blocking;
65
use crate::util::errors::AppResult;
76
use crate::util::RequestUtils;
87
use crate::views::{EncodableCategory, EncodableCategoryWithSubcategories};
98
use axum::extract::Path;
109
use axum::Json;
1110
use diesel::QueryDsl;
12-
use diesel_async::async_connection_wrapper::AsyncConnectionWrapper;
11+
use diesel_async::RunQueryDsl;
1312
use http::request::Parts;
1413
use serde_json::Value;
1514

@@ -20,36 +19,30 @@ pub async fn index(app: AppState, req: Parts) -> AppResult<Json<Value>> {
2019
// to paginate this.
2120
let options = PaginationOptions::builder().gather(&req)?;
2221

23-
let conn = app.db_read().await?;
24-
spawn_blocking(move || {
25-
let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();
22+
let mut conn = app.db_read().await?;
2623

27-
let query = req.query();
28-
let sort = query.get("sort").map_or("alpha", String::as_str);
24+
let query = req.query();
25+
let sort = query.get("sort").map_or("alpha", String::as_str);
2926

30-
let offset = options.offset().unwrap_or_default();
27+
let offset = options.offset().unwrap_or_default();
3128

32-
let categories = Category::toplevel(conn, sort, options.per_page, offset)?;
33-
let categories = categories
34-
.into_iter()
35-
.map(Category::into)
36-
.collect::<Vec<EncodableCategory>>();
29+
let categories = Category::toplevel(&mut conn, sort, options.per_page, offset).await?;
30+
let categories = categories
31+
.into_iter()
32+
.map(Category::into)
33+
.collect::<Vec<EncodableCategory>>();
3734

38-
// Query for the total count of categories
39-
let total = Category::count_toplevel(conn)?;
35+
// Query for the total count of categories
36+
let total = Category::count_toplevel(&mut conn).await?;
4037

41-
Ok(Json(json!({
42-
"categories": categories,
43-
"meta": { "total": total },
44-
})))
45-
})
46-
.await
38+
Ok(Json(json!({
39+
"categories": categories,
40+
"meta": { "total": total },
41+
})))
4742
}
4843

4944
/// Handles the `GET /categories/:category_id` route.
5045
pub async fn show(state: AppState, Path(slug): Path<String>) -> AppResult<Json<Value>> {
51-
use diesel_async::RunQueryDsl;
52-
5346
let mut conn = state.db_read().await?;
5447

5548
let cat: Category = Category::by_slug(&slug).first(&mut conn).await?;
@@ -83,8 +76,6 @@ pub async fn show(state: AppState, Path(slug): Path<String>) -> AppResult<Json<V
8376

8477
/// Handles the `GET /category_slugs` route.
8578
pub async fn slugs(state: AppState) -> AppResult<Json<Value>> {
86-
use diesel_async::RunQueryDsl;
87-
8879
let mut conn = state.db_read().await?;
8980

9081
let slugs: Vec<Slug> = categories::table

src/controllers/summary.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@ use serde_json::Value;
1414

1515
/// Handles the `GET /summary` route.
1616
pub async fn summary(state: AppState) -> AppResult<Json<Value>> {
17-
let conn = state.db_read().await?;
17+
let mut conn = state.db_read().await?;
18+
19+
let popular_categories = Category::toplevel(&mut conn, "crates", 10, 0)
20+
.await?
21+
.into_iter()
22+
.map(Category::into)
23+
.collect::<Vec<EncodableCategory>>();
24+
1825
spawn_blocking(move || {
1926
let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();
2027

@@ -116,11 +123,6 @@ pub async fn summary(state: AppState) -> AppResult<Json<Value>> {
116123
.map(Keyword::into)
117124
.collect::<Vec<EncodableKeyword>>();
118125

119-
let popular_categories = Category::toplevel(conn, "crates", 10, 0)?
120-
.into_iter()
121-
.map(Category::into)
122-
.collect::<Vec<EncodableCategory>>();
123-
124126
Ok(Json(json!({
125127
"num_downloads": num_downloads,
126128
"num_crates": num_crates,

src/models/category.rs

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,23 @@ impl Category {
8181
})
8282
}
8383

84-
pub fn count_toplevel(conn: &mut impl Conn) -> QueryResult<i64> {
85-
use diesel::RunQueryDsl;
84+
pub async fn count_toplevel(conn: &mut AsyncPgConnection) -> QueryResult<i64> {
85+
use diesel_async::RunQueryDsl;
8686
categories::table
8787
.filter(categories::category.not_like("%::%"))
8888
.count()
8989
.get_result(conn)
90+
.await
9091
}
9192

92-
pub fn toplevel(
93-
conn: &mut impl Conn,
93+
pub async fn toplevel(
94+
conn: &mut AsyncPgConnection,
9495
sort: &str,
9596
limit: i64,
9697
offset: i64,
9798
) -> QueryResult<Vec<Category>> {
9899
use diesel::sql_types::Int8;
99-
use diesel::RunQueryDsl;
100+
use diesel_async::RunQueryDsl;
100101

101102
let sort_sql = match sort {
102103
"crates" => "ORDER BY crates_cnt DESC",
@@ -109,6 +110,7 @@ impl Category {
109110
.bind::<Int8, _>(limit)
110111
.bind::<Int8, _>(offset)
111112
.load(conn)
113+
.await
112114
}
113115

114116
pub async fn subcategories(&self, conn: &mut AsyncPgConnection) -> QueryResult<Vec<Category>> {
@@ -152,15 +154,17 @@ pub struct NewCategory<'a> {
152154
#[cfg(test)]
153155
mod tests {
154156
use super::*;
155-
use crate::test_util::test_db_connection;
156157
use crates_io_test_db::TestDatabase;
157158
use diesel_async::AsyncConnection;
159+
use diesel_async::RunQueryDsl;
158160

159-
#[test]
160-
fn category_toplevel_excludes_subcategories() {
161+
#[tokio::test]
162+
async fn category_toplevel_excludes_subcategories() {
161163
use self::categories;
162-
use diesel::RunQueryDsl;
163-
let (_test_db, conn) = &mut test_db_connection();
164+
165+
let test_db = TestDatabase::new();
166+
let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap();
167+
164168
insert_into(categories::table)
165169
.values(&vec![
166170
(
@@ -176,10 +180,12 @@ mod tests {
176180
categories::slug.eq("cat1::sub"),
177181
),
178182
])
179-
.execute(conn)
183+
.execute(&mut conn)
184+
.await
180185
.unwrap();
181186

182-
let cats = Category::toplevel(conn, "", 10, 0)
187+
let cats = Category::toplevel(&mut conn, "", 10, 0)
188+
.await
183189
.unwrap()
184190
.into_iter()
185191
.map(|c| c.category)
@@ -188,10 +194,9 @@ mod tests {
188194
assert_eq!(expected, cats);
189195
}
190196

191-
#[test]
192-
fn category_toplevel_orders_by_crates_cnt_when_sort_given() {
197+
#[tokio::test]
198+
async fn category_toplevel_orders_by_crates_cnt_when_sort_given() {
193199
use self::categories;
194-
use diesel::RunQueryDsl;
195200

196201
let new_cat = |category, slug, crates_cnt| {
197202
(
@@ -201,17 +206,21 @@ mod tests {
201206
)
202207
};
203208

204-
let (_test_db, conn) = &mut test_db_connection();
209+
let test_db = TestDatabase::new();
210+
let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap();
211+
205212
insert_into(categories::table)
206213
.values(&vec![
207214
new_cat("Cat 1", "cat1", 0),
208215
new_cat("Cat 2", "cat2", 2),
209216
new_cat("Cat 3", "cat3", 1),
210217
])
211-
.execute(conn)
218+
.execute(&mut conn)
219+
.await
212220
.unwrap();
213221

214-
let cats = Category::toplevel(conn, "crates", 10, 0)
222+
let cats = Category::toplevel(&mut conn, "crates", 10, 0)
223+
.await
215224
.unwrap()
216225
.into_iter()
217226
.map(|c| c.category)
@@ -224,11 +233,13 @@ mod tests {
224233
assert_eq!(expected, cats);
225234
}
226235

227-
#[test]
228-
fn category_toplevel_applies_limit_and_offset() {
236+
#[tokio::test]
237+
async fn category_toplevel_applies_limit_and_offset() {
229238
use self::categories;
230-
use diesel::RunQueryDsl;
231-
let (_test_db, conn) = &mut test_db_connection();
239+
240+
let test_db = TestDatabase::new();
241+
let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap();
242+
232243
insert_into(categories::table)
233244
.values(&vec![
234245
(
@@ -240,18 +251,21 @@ mod tests {
240251
categories::slug.eq("cat2"),
241252
),
242253
])
243-
.execute(conn)
254+
.execute(&mut conn)
255+
.await
244256
.unwrap();
245257

246-
let cats = Category::toplevel(conn, "", 1, 0)
258+
let cats = Category::toplevel(&mut conn, "", 1, 0)
259+
.await
247260
.unwrap()
248261
.into_iter()
249262
.map(|c| c.category)
250263
.collect::<Vec<_>>();
251264
let expected = vec!["Cat 1".to_string()];
252265
assert_eq!(expected, cats);
253266

254-
let cats = Category::toplevel(conn, "", 1, 1)
267+
let cats = Category::toplevel(&mut conn, "", 1, 1)
268+
.await
255269
.unwrap()
256270
.into_iter()
257271
.map(|c| c.category)
@@ -260,10 +274,9 @@ mod tests {
260274
assert_eq!(expected, cats);
261275
}
262276

263-
#[test]
264-
fn category_toplevel_includes_subcategories_in_crate_cnt() {
277+
#[tokio::test]
278+
async fn category_toplevel_includes_subcategories_in_crate_cnt() {
265279
use self::categories;
266-
use diesel::RunQueryDsl;
267280

268281
let new_cat = |category, slug, crates_cnt| {
269282
(
@@ -273,7 +286,9 @@ mod tests {
273286
)
274287
};
275288

276-
let (_test_db, conn) = &mut test_db_connection();
289+
let test_db = TestDatabase::new();
290+
let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap();
291+
277292
insert_into(categories::table)
278293
.values(&vec![
279294
new_cat("Cat 1", "cat1", 1),
@@ -283,10 +298,12 @@ mod tests {
283298
new_cat("Cat 2::Sub 2", "cat2::sub2", 5),
284299
new_cat("Cat 3", "cat3", 6),
285300
])
286-
.execute(conn)
301+
.execute(&mut conn)
302+
.await
287303
.unwrap();
288304

289-
let cats = Category::toplevel(conn, "crates", 10, 0)
305+
let cats = Category::toplevel(&mut conn, "crates", 10, 0)
306+
.await
290307
.unwrap()
291308
.into_iter()
292309
.map(|c| (c.category, c.crates_cnt))
@@ -299,10 +316,9 @@ mod tests {
299316
assert_eq!(expected, cats);
300317
}
301318

302-
#[test]
303-
fn category_toplevel_applies_limit_and_offset_after_grouping() {
319+
#[tokio::test]
320+
async fn category_toplevel_applies_limit_and_offset_after_grouping() {
304321
use self::categories;
305-
use diesel::RunQueryDsl;
306322

307323
let new_cat = |category, slug, crates_cnt| {
308324
(
@@ -312,7 +328,9 @@ mod tests {
312328
)
313329
};
314330

315-
let (_test_db, conn) = &mut test_db_connection();
331+
let test_db = TestDatabase::new();
332+
let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap();
333+
316334
insert_into(categories::table)
317335
.values(&vec![
318336
new_cat("Cat 1", "cat1", 1),
@@ -322,18 +340,21 @@ mod tests {
322340
new_cat("Cat 2::Sub 2", "cat2::sub2", 5),
323341
new_cat("Cat 3", "cat3", 6),
324342
])
325-
.execute(conn)
343+
.execute(&mut conn)
344+
.await
326345
.unwrap();
327346

328-
let cats = Category::toplevel(conn, "crates", 2, 0)
347+
let cats = Category::toplevel(&mut conn, "crates", 2, 0)
348+
.await
329349
.unwrap()
330350
.into_iter()
331351
.map(|c| (c.category, c.crates_cnt))
332352
.collect::<Vec<_>>();
333353
let expected = vec![("Cat 2".to_string(), 12), ("Cat 3".to_string(), 6)];
334354
assert_eq!(expected, cats);
335355

336-
let cats = Category::toplevel(conn, "crates", 2, 1)
356+
let cats = Category::toplevel(&mut conn, "crates", 2, 1)
357+
.await
337358
.unwrap()
338359
.into_iter()
339360
.map(|c| (c.category, c.crates_cnt))
@@ -345,7 +366,6 @@ mod tests {
345366
#[tokio::test]
346367
async fn category_parent_categories_includes_path_to_node_with_count() {
347368
use self::categories;
348-
use diesel_async::RunQueryDsl;
349369

350370
let new_cat = |category, slug, crates_cnt| {
351371
(

0 commit comments

Comments
 (0)