|
1 | 1 | use bon::Builder; |
2 | 2 | use chrono::NaiveDateTime; |
| 3 | +use diesel::dsl::sql; |
3 | 4 | use diesel::prelude::*; |
| 5 | +use diesel::sql_types::Integer; |
| 6 | +use diesel::upsert::excluded; |
4 | 7 | use diesel_async::scoped_futures::ScopedFutureExt; |
5 | 8 | use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl}; |
6 | 9 |
|
@@ -119,39 +122,42 @@ pub struct NewUser<'a> { |
119 | 122 |
|
120 | 123 | impl<'a> NewUser<'a> { |
121 | 124 | /// Inserts the user into the database, or updates an existing one. |
| 125 | + pub async fn insert_or_update(&self, conn: &mut AsyncPgConnection) -> QueryResult<User> { |
| 126 | + diesel::insert_into(users::table) |
| 127 | + .values(self) |
| 128 | + // We need the `WHERE gh_id > 0` condition here because `gh_id` set |
| 129 | + // to `-1` indicates that we were unable to find a GitHub ID for |
| 130 | + // the associated GitHub login at the time that we backfilled |
| 131 | + // GitHub IDs. Therefore, there are multiple records in production |
| 132 | + // that have a `gh_id` of `-1` so we need to exclude those when |
| 133 | + // considering uniqueness of `gh_id` values. The `> 0` condition isn't |
| 134 | + // necessary for most fields in the database to be used as a conflict |
| 135 | + // target :) |
| 136 | + .on_conflict(sql::<Integer>("(gh_id) WHERE gh_id > 0")) |
| 137 | + .do_update() |
| 138 | + .set(( |
| 139 | + users::gh_login.eq(excluded(users::gh_login)), |
| 140 | + users::name.eq(excluded(users::name)), |
| 141 | + users::gh_avatar.eq(excluded(users::gh_avatar)), |
| 142 | + users::gh_access_token.eq(excluded(users::gh_access_token)), |
| 143 | + )) |
| 144 | + .get_result(conn) |
| 145 | + .await |
| 146 | + } |
| 147 | + |
| 148 | + /// Inserts the user into the database, or updates an existing one. |
| 149 | + /// |
| 150 | + /// This method also inserts the email address into the `emails` table |
| 151 | + /// and sends a confirmation email to the user. |
122 | 152 | pub async fn create_or_update( |
123 | 153 | &self, |
124 | 154 | email: Option<&'a str>, |
125 | 155 | emails: &Emails, |
126 | 156 | conn: &mut AsyncPgConnection, |
127 | 157 | ) -> QueryResult<User> { |
128 | | - use diesel::dsl::sql; |
129 | | - use diesel::insert_into; |
130 | | - use diesel::pg::upsert::excluded; |
131 | | - use diesel::sql_types::Integer; |
132 | | - |
133 | 158 | conn.transaction(|conn| { |
134 | 159 | async move { |
135 | | - let user: User = insert_into(users::table) |
136 | | - .values(self) |
137 | | - // We need the `WHERE gh_id > 0` condition here because `gh_id` set |
138 | | - // to `-1` indicates that we were unable to find a GitHub ID for |
139 | | - // the associated GitHub login at the time that we backfilled |
140 | | - // GitHub IDs. Therefore, there are multiple records in production |
141 | | - // that have a `gh_id` of `-1` so we need to exclude those when |
142 | | - // considering uniqueness of `gh_id` values. The `> 0` condition isn't |
143 | | - // necessary for most fields in the database to be used as a conflict |
144 | | - // target :) |
145 | | - .on_conflict(sql::<Integer>("(gh_id) WHERE gh_id > 0")) |
146 | | - .do_update() |
147 | | - .set(( |
148 | | - users::gh_login.eq(excluded(users::gh_login)), |
149 | | - users::name.eq(excluded(users::name)), |
150 | | - users::gh_avatar.eq(excluded(users::gh_avatar)), |
151 | | - users::gh_access_token.eq(excluded(users::gh_access_token)), |
152 | | - )) |
153 | | - .get_result(conn) |
154 | | - .await?; |
| 160 | + let user = self.insert_or_update(conn).await?; |
155 | 161 |
|
156 | 162 | // To send the user an account verification email |
157 | 163 | if let Some(user_email) = email { |
|
0 commit comments