|
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