Skip to content

Commit 490a95e

Browse files
authored
Merge pull request #10575 from Turbo87/owner-builder
Derive `bon::Builder` for `CrateOwner` struct and add `insert()` fn
2 parents 10241e3 + 6c2ddf4 commit 490a95e

File tree

7 files changed

+82
-85
lines changed

7 files changed

+82
-85
lines changed

src/controllers/krate/owners.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::controllers::krate::CratePath;
44
use crate::models::krate::OwnerRemoveError;
55
use crate::models::{
66
krate::NewOwnerInvite, token::EndpointScope, CrateOwner, NewCrateOwnerInvitation,
7-
NewCrateOwnerInvitationOutcome, OwnerKind,
7+
NewCrateOwnerInvitationOutcome,
88
};
99
use crate::models::{Crate, Owner, Rights, Team, User};
1010
use crate::util::errors::{bad_request, crate_not_found, custom, AppResult, BoxedAppError};
@@ -15,7 +15,6 @@ use axum::Json;
1515
use axum_extra::json;
1616
use axum_extra::response::ErasedJson;
1717
use chrono::Utc;
18-
use crates_io_database::schema::crate_owners;
1918
use crates_io_github::GitHubClient;
2019
use diesel::prelude::*;
2120
use diesel_async::scoped_futures::ScopedFutureExt;
@@ -342,18 +341,12 @@ async fn add_team_owner(
342341

343342
// Teams are added as owners immediately, since the above call ensures
344343
// the user is a team member.
345-
diesel::insert_into(crate_owners::table)
346-
.values(&CrateOwner {
347-
crate_id: krate.id,
348-
owner_id: team.id,
349-
created_by: req_user.id,
350-
owner_kind: OwnerKind::Team,
351-
email_notifications: true,
352-
})
353-
.on_conflict(crate_owners::table.primary_key())
354-
.do_update()
355-
.set(crate_owners::deleted.eq(false))
356-
.execute(conn)
344+
CrateOwner::builder()
345+
.crate_id(krate.id)
346+
.team_id(team.id)
347+
.created_by(req_user.id)
348+
.build()
349+
.insert(conn)
357350
.await?;
358351

359352
Ok(NewOwnerInvite::Team(team))

src/models/crate_owner_invitation.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl};
55
use secrecy::SecretString;
66

77
use crate::models::CrateOwner;
8-
use crate::schema::{crate_owner_invitations, crate_owners, crates};
8+
use crate::schema::{crate_owner_invitations, crates};
99

1010
#[derive(Debug)]
1111
pub enum NewCrateOwnerInvitationOutcome {
@@ -101,13 +101,7 @@ impl CrateOwnerInvitation {
101101

102102
conn.transaction(|conn| {
103103
async move {
104-
diesel::insert_into(crate_owners::table)
105-
.values(CrateOwner::from_invite(&self))
106-
.on_conflict(crate_owners::table.primary_key())
107-
.do_update()
108-
.set(crate_owners::deleted.eq(false))
109-
.execute(conn)
110-
.await?;
104+
CrateOwner::from_invite(&self).insert(conn).await?;
111105

112106
diesel::delete(&self).execute(conn).await?;
113107

src/models/krate.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,12 @@ impl NewCrate<'_> {
128128
.get_result(conn)
129129
.await?;
130130

131-
let owner = CrateOwner {
132-
crate_id: krate.id,
133-
owner_id: user_id,
134-
created_by: user_id,
135-
owner_kind: OwnerKind::User,
136-
email_notifications: true,
137-
};
138-
139-
diesel::insert_into(crate_owners::table)
140-
.values(&owner)
141-
.execute(conn)
131+
CrateOwner::builder()
132+
.crate_id(krate.id)
133+
.user_id(user_id)
134+
.created_by(user_id)
135+
.build()
136+
.insert(conn)
142137
.await?;
143138

144139
Ok(krate)

src/models/owner.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
use bon::Builder;
12
use diesel::pg::Pg;
23
use diesel::prelude::*;
4+
use diesel_async::{AsyncPgConnection, RunQueryDsl};
35

6+
use self::crate_owner_builder::{SetOwnerId, SetOwnerKind};
47
use crate::models::{Crate, CrateOwnerInvitation, Team, User};
58
use crate::schema::crate_owners;
69
use crates_io_diesel_helpers::pg_enum;
710

8-
#[derive(Insertable, Associations, Identifiable, Debug, Clone, Copy)]
11+
#[derive(Insertable, Associations, Identifiable, Debug, Clone, Copy, Builder)]
912
#[diesel(
1013
table_name = crate_owners,
1114
check_for_backend(diesel::pg::Pg),
@@ -16,12 +19,33 @@ use crates_io_diesel_helpers::pg_enum;
1619
)]
1720
pub struct CrateOwner {
1821
pub crate_id: i32,
22+
#[builder(setters(vis = "pub(self)"))]
1923
pub owner_id: i32,
2024
pub created_by: i32,
25+
#[builder(setters(vis = "pub(self)"))]
2126
pub owner_kind: OwnerKind,
27+
#[builder(default = true)]
2228
pub email_notifications: bool,
2329
}
2430

31+
impl<S: crate_owner_builder::State> CrateOwnerBuilder<S> {
32+
pub fn team_id(self, team_id: i32) -> CrateOwnerBuilder<SetOwnerId<SetOwnerKind<S>>>
33+
where
34+
S::OwnerId: crate_owner_builder::IsUnset,
35+
S::OwnerKind: crate_owner_builder::IsUnset,
36+
{
37+
self.owner_kind(OwnerKind::Team).owner_id(team_id)
38+
}
39+
40+
pub fn user_id(self, user_id: i32) -> CrateOwnerBuilder<SetOwnerId<SetOwnerKind<S>>>
41+
where
42+
S::OwnerId: crate_owner_builder::IsUnset,
43+
S::OwnerKind: crate_owner_builder::IsUnset,
44+
{
45+
self.owner_kind(OwnerKind::User).owner_id(user_id)
46+
}
47+
}
48+
2549
type BoxedQuery<'a> = crate_owners::BoxedQuery<'a, Pg, crate_owners::SqlType>;
2650

2751
impl CrateOwner {
@@ -35,13 +59,24 @@ impl CrateOwner {
3559
}
3660

3761
pub fn from_invite(invite: &CrateOwnerInvitation) -> Self {
38-
Self {
39-
crate_id: invite.crate_id,
40-
owner_id: invite.invited_user_id,
41-
created_by: invite.invited_by_user_id,
42-
owner_kind: OwnerKind::User,
43-
email_notifications: true,
44-
}
62+
CrateOwner::builder()
63+
.crate_id(invite.crate_id)
64+
.user_id(invite.invited_user_id)
65+
.created_by(invite.invited_by_user_id)
66+
.build()
67+
}
68+
69+
/// Inserts the crate owner into the database, or removes the `deleted` flag
70+
/// if the record already exists.
71+
pub async fn insert(&self, conn: &mut AsyncPgConnection) -> QueryResult<()> {
72+
diesel::insert_into(crate_owners::table)
73+
.values(self)
74+
.on_conflict(crate_owners::table.primary_key())
75+
.do_update()
76+
.set(crate_owners::deleted.eq(false))
77+
.execute(conn)
78+
.await
79+
.map(|_| ())
4580
}
4681
}
4782

src/tests/issues/issue2736.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use crate::models::{CrateOwner, OwnerKind};
1+
use crate::models::CrateOwner;
22
use crate::tests::builders::CrateBuilder;
33
use crate::tests::util::{RequestHelper, TestApp};
4-
use crates_io_database::schema::{crate_owners, users};
4+
use crates_io_database::schema::users;
55
use diesel::prelude::*;
66
use diesel_async::RunQueryDsl;
77
use http::StatusCode;
@@ -23,15 +23,12 @@ async fn test_issue_2736() -> anyhow::Result<()> {
2323
.expect_build(&mut conn)
2424
.await;
2525

26-
diesel::insert_into(crate_owners::table)
27-
.values(CrateOwner {
28-
crate_id: krate.id,
29-
owner_id: foo1.as_model().id,
30-
created_by: someone_else.as_model().id,
31-
owner_kind: OwnerKind::User,
32-
email_notifications: true,
33-
})
34-
.execute(&mut conn)
26+
CrateOwner::builder()
27+
.crate_id(krate.id)
28+
.user_id(foo1.as_model().id)
29+
.created_by(someone_else.as_model().id)
30+
.build()
31+
.insert(&mut conn)
3532
.await?;
3633

3734
// - `foo` deleted their GitHub account (but crates.io has no real knowledge of this)

src/tests/mod.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use crate::models::{Crate, CrateOwner, NewCategory, NewTeam, NewUser, OwnerKind, Team, User};
2-
use crate::schema::crate_owners;
1+
use crate::models::{Crate, CrateOwner, NewCategory, NewTeam, NewUser, Team, User};
32
use crate::tests::util::{RequestHelper, TestApp};
43
use crate::views::{
54
EncodableCategory, EncodableCategoryWithSubcategories, EncodableCrate, EncodableKeyword,
@@ -8,7 +7,7 @@ use crate::views::{
87

98
use crate::tests::util::github::next_gh_id;
109
use diesel::prelude::*;
11-
use diesel_async::{AsyncPgConnection, RunQueryDsl};
10+
use diesel_async::AsyncPgConnection;
1211

1312
mod account_lock;
1413
mod authentication;
@@ -114,23 +113,13 @@ pub async fn add_team_to_crate(
114113
u: &User,
115114
conn: &mut AsyncPgConnection,
116115
) -> QueryResult<()> {
117-
let crate_owner = CrateOwner {
118-
crate_id: krate.id,
119-
owner_id: t.id,
120-
created_by: u.id,
121-
owner_kind: OwnerKind::Team,
122-
email_notifications: true,
123-
};
124-
125-
diesel::insert_into(crate_owners::table)
126-
.values(&crate_owner)
127-
.on_conflict(crate_owners::table.primary_key())
128-
.do_update()
129-
.set(crate_owners::deleted.eq(false))
130-
.execute(conn)
131-
.await?;
132-
133-
Ok(())
116+
CrateOwner::builder()
117+
.crate_id(krate.id)
118+
.team_id(t.id)
119+
.created_by(u.id)
120+
.build()
121+
.insert(conn)
122+
.await
134123
}
135124

136125
fn new_category<'a>(category: &'a str, slug: &'a str, description: &'a str) -> NewCategory<'a> {

src/tests/routes/crates/owners/remove.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::models::{CrateOwner, OwnerKind};
1+
use crate::models::CrateOwner;
22
use crate::tests::builders::CrateBuilder;
33
use crate::tests::util::{RequestHelper, TestApp};
4-
use crates_io_database::schema::crate_owners;
54
use crates_io_github::{GitHubOrganization, GitHubTeam, GitHubTeamMembership, MockGitHubClient};
65
use http::StatusCode;
76
use insta::assert_snapshot;
@@ -83,8 +82,6 @@ async fn test_unknown_team() {
8382

8483
#[tokio::test(flavor = "multi_thread")]
8584
async fn test_remove_uppercase_user() {
86-
use diesel_async::RunQueryDsl;
87-
8885
let (app, _, cookie) = TestApp::full().with_user().await;
8986
let user2 = app.db_new_user("user2").await;
9087
let mut conn = app.db_conn().await;
@@ -93,15 +90,12 @@ async fn test_remove_uppercase_user() {
9390
.expect_build(&mut conn)
9491
.await;
9592

96-
diesel::insert_into(crate_owners::table)
97-
.values(CrateOwner {
98-
crate_id: krate.id,
99-
owner_id: user2.as_model().id,
100-
created_by: cookie.as_model().id,
101-
owner_kind: OwnerKind::User,
102-
email_notifications: true,
103-
})
104-
.execute(&mut conn)
93+
CrateOwner::builder()
94+
.crate_id(krate.id)
95+
.user_id(user2.as_model().id)
96+
.created_by(cookie.as_model().id)
97+
.build()
98+
.insert(&mut conn)
10599
.await
106100
.unwrap();
107101

0 commit comments

Comments
 (0)