|
1 | 1 | use chrono::NaiveDateTime; |
2 | | -use diesel_async::AsyncPgConnection; |
| 2 | +use diesel_async::scoped_futures::ScopedFutureExt; |
| 3 | +use diesel_async::{AsyncConnection, AsyncPgConnection}; |
3 | 4 |
|
4 | 5 | use crate::models::Crate; |
5 | 6 | use crate::schema::*; |
@@ -38,6 +39,31 @@ impl Keyword { |
38 | 39 | .await |
39 | 40 | } |
40 | 41 |
|
| 42 | + pub async fn async_find_or_create_all( |
| 43 | + conn: &mut AsyncPgConnection, |
| 44 | + names: &[&str], |
| 45 | + ) -> QueryResult<Vec<Keyword>> { |
| 46 | + use diesel_async::RunQueryDsl; |
| 47 | + |
| 48 | + let lowercase_names: Vec<_> = names.iter().map(|s| s.to_lowercase()).collect(); |
| 49 | + |
| 50 | + let new_keywords: Vec<_> = lowercase_names |
| 51 | + .iter() |
| 52 | + .map(|s| keywords::keyword.eq(s)) |
| 53 | + .collect(); |
| 54 | + |
| 55 | + diesel::insert_into(keywords::table) |
| 56 | + .values(&new_keywords) |
| 57 | + .on_conflict_do_nothing() |
| 58 | + .execute(conn) |
| 59 | + .await?; |
| 60 | + |
| 61 | + keywords::table |
| 62 | + .filter(keywords::keyword.eq_any(&lowercase_names)) |
| 63 | + .load(conn) |
| 64 | + .await |
| 65 | + } |
| 66 | + |
41 | 67 | pub fn find_or_create_all(conn: &mut impl Conn, names: &[&str]) -> QueryResult<Vec<Keyword>> { |
42 | 68 | use diesel::RunQueryDsl; |
43 | 69 |
|
@@ -67,6 +93,42 @@ impl Keyword { |
67 | 93 | && chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '+') |
68 | 94 | } |
69 | 95 |
|
| 96 | + pub async fn async_update_crate( |
| 97 | + conn: &mut AsyncPgConnection, |
| 98 | + crate_id: i32, |
| 99 | + keywords: &[&str], |
| 100 | + ) -> QueryResult<()> { |
| 101 | + conn.transaction(|conn| { |
| 102 | + async move { |
| 103 | + use diesel_async::RunQueryDsl; |
| 104 | + |
| 105 | + let keywords = Keyword::async_find_or_create_all(conn, keywords).await?; |
| 106 | + |
| 107 | + diesel::delete(crates_keywords::table) |
| 108 | + .filter(crates_keywords::crate_id.eq(crate_id)) |
| 109 | + .execute(conn) |
| 110 | + .await?; |
| 111 | + |
| 112 | + let crate_keywords = keywords |
| 113 | + .into_iter() |
| 114 | + .map(|kw| CrateKeyword { |
| 115 | + crate_id, |
| 116 | + keyword_id: kw.id, |
| 117 | + }) |
| 118 | + .collect::<Vec<_>>(); |
| 119 | + |
| 120 | + diesel::insert_into(crates_keywords::table) |
| 121 | + .values(&crate_keywords) |
| 122 | + .execute(conn) |
| 123 | + .await?; |
| 124 | + |
| 125 | + Ok(()) |
| 126 | + } |
| 127 | + .scope_boxed() |
| 128 | + }) |
| 129 | + .await |
| 130 | + } |
| 131 | + |
70 | 132 | pub fn update_crate(conn: &mut impl Conn, crate_id: i32, keywords: &[&str]) -> QueryResult<()> { |
71 | 133 | conn.transaction(|conn| { |
72 | 134 | use diesel::RunQueryDsl; |
@@ -99,23 +161,27 @@ mod tests { |
99 | 161 | use super::*; |
100 | 162 | use crates_io_test_db::TestDatabase; |
101 | 163 |
|
102 | | - #[test] |
103 | | - fn dont_associate_with_non_lowercased_keywords() { |
104 | | - use diesel::RunQueryDsl; |
| 164 | + #[tokio::test] |
| 165 | + #[allow(clippy::iter_next_slice)] |
| 166 | + async fn dont_associate_with_non_lowercased_keywords() { |
| 167 | + use diesel_async::RunQueryDsl; |
105 | 168 |
|
106 | 169 | let test_db = TestDatabase::new(); |
107 | | - let conn = &mut test_db.connect(); |
| 170 | + let mut conn = test_db.async_connect().await; |
108 | 171 |
|
109 | 172 | // The code should be preventing lowercased keywords from existing, |
110 | 173 | // but if one happens to sneak in there, don't associate crates with it. |
111 | 174 |
|
112 | 175 | diesel::insert_into(keywords::table) |
113 | 176 | .values(keywords::keyword.eq("NO")) |
114 | | - .execute(conn) |
| 177 | + .execute(&mut conn) |
| 178 | + .await |
115 | 179 | .unwrap(); |
116 | 180 |
|
117 | | - let associated = Keyword::find_or_create_all(conn, &["no"]).unwrap(); |
| 181 | + let associated = Keyword::async_find_or_create_all(&mut conn, &["no"]) |
| 182 | + .await |
| 183 | + .unwrap(); |
118 | 184 | assert_eq!(associated.len(), 1); |
119 | | - assert_eq!(associated.first().unwrap().keyword, "no"); |
| 185 | + assert_eq!(associated.iter().next().unwrap().keyword, "no"); |
120 | 186 | } |
121 | 187 | } |
0 commit comments