Skip to content

Commit 94e3e1b

Browse files
committed
Port /crates/new and /crates/show to use Diesel
This is probably the single largest endpoint in the entire app. It had a bit more churn than I'd like, since we're now explicitly wrapping the whole thing in a database transaction. I've also ported over the `/crates/show` endpoint as there were several tests that needed both to be ported over. There were a large number of tests that needed even more endpoints ported over in order to be valid. These tests are important, but I want to keep this commit at least somewhat manageble so I've set them to ignore for now.
1 parent 2772cbc commit 94e3e1b

14 files changed

+602
-274
lines changed

src/badge.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use krate::Crate;
33
use schema::badges;
44
use util::CargoResult;
55

6-
use diesel::pg::Pg;
6+
use diesel::pg::{Pg, PgConnection};
77
use diesel::prelude::*;
88
use pg::GenericConnection;
99
use pg::rows::Row;
@@ -67,7 +67,48 @@ impl Badge {
6767
}
6868
}
6969

70-
pub fn update_crate(conn: &GenericConnection,
70+
pub fn update_crate<'a>(conn: &PgConnection,
71+
krate: &Crate,
72+
badges: Option<&'a HashMap<String, HashMap<String, String>>>)
73+
-> CargoResult<Vec<&'a str>> {
74+
use diesel::{insert, delete};
75+
76+
#[derive(Insertable)]
77+
#[table_name="badges"]
78+
struct NewBadge<'a> {
79+
crate_id: i32,
80+
badge_type: &'a str,
81+
attributes: serde_json::Value,
82+
}
83+
84+
let mut invalid_badges = vec![];
85+
let mut new_badges = vec![];
86+
87+
if let Some(badges) = badges {
88+
for (k, v) in badges {
89+
let attributes_json = serde_json::to_value(v).unwrap();
90+
91+
let json = json!({"badge_type": k, "attributes": attributes_json});
92+
if serde_json::from_value::<Badge>(json).is_ok() {
93+
new_badges.push(NewBadge {
94+
crate_id: krate.id,
95+
badge_type: &**k,
96+
attributes: attributes_json,
97+
});
98+
} else {
99+
invalid_badges.push(&**k);
100+
}
101+
}
102+
}
103+
104+
conn.transaction(|| {
105+
delete(badges::table.filter(badges::crate_id.eq(krate.id))).execute(conn)?;
106+
insert(&new_badges).into(badges::table).execute(conn)?;
107+
Ok(invalid_badges)
108+
})
109+
}
110+
111+
pub fn update_crate_old(conn: &GenericConnection,
71112
krate: &Crate,
72113
badges: HashMap<String, HashMap<String, String>>)
73114
-> CargoResult<Vec<String>> {

src/bin/transfer-crates.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ fn transfer(tx: &postgres::transaction::Transaction) {
4242
let from = User::find_by_login(tx, &from).unwrap();
4343
let to = User::find_by_login(tx, &to).unwrap();
4444

45-
if from.avatar != to.avatar {
45+
if from.gh_avatar != to.gh_avatar {
4646
println!("====================================================");
4747
println!("WARNING");
4848
println!("");
4949
println!("this may not be the same github user, different avatar urls");
5050
println!("");
51-
println!("from: {:?}", from.avatar);
52-
println!("to: {:?}", to.avatar);
51+
println!("from: {:?}", from.gh_avatar);
52+
println!("to: {:?}", to.gh_avatar);
5353

5454
get_confirm("continue?");
5555
}
@@ -68,7 +68,7 @@ fn transfer(tx: &postgres::transaction::Transaction) {
6868
let id: i32 = row.get("id");
6969
let krate = Crate::find(tx, row.get("crate_id")).unwrap();
7070
println!("transferring {}", krate.name);
71-
let owners = krate.owners(tx).unwrap();
71+
let owners = krate.owners_old(tx).unwrap();
7272
if owners.len() != 1 {
7373
println!("warning: not exactly one owner for {}", krate.name);
7474
}

src/category.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub struct Category {
3030
#[belongs_to(Crate)]
3131
#[table_name="crates_categories"]
3232
#[primary_key(crate_id, category_id)]
33-
struct CrateCategory {
33+
pub struct CrateCategory {
3434
crate_id: i32,
3535
category_id: i32,
3636
}

src/dependency.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
use diesel::prelude::*;
2+
use diesel::pg::{Pg, PgConnection};
13
use pg::GenericConnection;
24
use pg::rows::Row;
35
use semver;
46

57
use Model;
68
use git;
7-
use util::{CargoResult};
9+
use krate::{Crate, canon_crate_name};
10+
use schema::*;
11+
use util::{CargoResult, human};
812

913
pub struct Dependency {
1014
pub id: i32,
@@ -47,6 +51,19 @@ pub enum Kind {
4751
// if you add a kind here, be sure to update `from_row` below.
4852
}
4953

54+
#[derive(Insertable)]
55+
#[table_name="dependencies"]
56+
struct NewDependency<'a> {
57+
version_id: i32,
58+
crate_id: i32,
59+
req: String,
60+
optional: bool,
61+
default_features: bool,
62+
features: Vec<&'a str>,
63+
target: Option<&'a str>,
64+
kind: i32,
65+
}
66+
5067
impl Dependency {
5168
// FIXME: Encapsulate this in a `NewDependency` struct
5269
#[cfg_attr(feature = "clippy", allow(too_many_arguments))]
@@ -102,6 +119,73 @@ impl ReverseDependency {
102119
}
103120
}
104121

122+
pub fn add_dependencies(
123+
conn: &PgConnection,
124+
deps: &[::upload::CrateDependency],
125+
version_id: i32,
126+
) -> CargoResult<Vec<Dependency>> {
127+
use diesel::insert;
128+
use diesel::expression::dsl::any;
129+
130+
let crate_names = deps.iter().map(|d| &*d.name).collect::<Vec<_>>();
131+
let crates = Crate::all()
132+
.filter(canon_crate_name(crates::name).eq(any(crate_names)))
133+
.load::<Crate>(conn)?;
134+
135+
let new_dependencies = deps.iter().map(|dep| {
136+
let krate = crates.iter().find(|c| dep.name == c.name)
137+
.map(Ok)
138+
.unwrap_or_else(|| {
139+
Err(human(&format_args!("no known crate named `{}`", &*dep.name)))
140+
})?;
141+
if dep.version_req == semver::VersionReq::parse("*").unwrap() {
142+
return Err(human("wildcard (`*`) dependency constraints are not allowed \
143+
on crates.io. See http://doc.crates.io/faq.html#can-\
144+
libraries-use--as-a-version-for-their-dependencies for more \
145+
information"));
146+
}
147+
let features = dep.features.iter().map(|s| &**s).collect();
148+
Ok(NewDependency {
149+
version_id: version_id,
150+
crate_id: krate.id,
151+
req: dep.version_req.to_string(),
152+
kind: dep.kind.unwrap_or(Kind::Normal) as i32,
153+
optional: dep.optional,
154+
default_features: dep.default_features,
155+
features: features,
156+
target: dep.target.as_ref().map(|s| &**s),
157+
})
158+
}).collect::<Result<Vec<_>, _>>()?;
159+
160+
insert(&new_dependencies).into(dependencies::table)
161+
.get_results(conn)
162+
.map_err(Into::into)
163+
}
164+
165+
impl Queryable<dependencies::SqlType, Pg> for Dependency {
166+
type Row = (i32, i32, i32, String, bool, bool, Vec<String>, Option<String>,
167+
i32);
168+
169+
fn build(row: Self::Row) -> Self {
170+
Dependency {
171+
id: row.0,
172+
version_id: row.1,
173+
crate_id: row.2,
174+
req: semver::VersionReq::parse(&row.3).unwrap(),
175+
optional: row.4,
176+
default_features: row.5,
177+
features: row.6,
178+
target: row.7,
179+
kind: match row.8 {
180+
0 => Kind::Normal,
181+
1 => Kind::Build,
182+
2 => Kind::Dev,
183+
n => panic!("unknown kind: {}", n),
184+
}
185+
}
186+
}
187+
}
188+
105189
impl Model for Dependency {
106190
fn from_row(row: &Row) -> Dependency {
107191
let req: String = row.get("req");

src/keyword.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct Keyword {
2929
#[belongs_to(Crate)]
3030
#[table_name="crates_keywords"]
3131
#[primary_key(crate_id, keyword_id)]
32-
struct CrateKeyword {
32+
pub struct CrateKeyword {
3333
crate_id: i32,
3434
keyword_id: i32,
3535
}
@@ -66,8 +66,11 @@ impl Keyword {
6666
.map(|s| (s.to_lowercase(), NewKeyword { keyword: *s }))
6767
.unzip();
6868

69-
diesel::insert(&new_keywords.on_conflict_do_nothing()).into(keywords::table)
70-
.execute(conn)?;
69+
// https://github.com/diesel-rs/diesel/issues/797
70+
if !new_keywords.is_empty() {
71+
diesel::insert(&new_keywords.on_conflict_do_nothing()).into(keywords::table)
72+
.execute(conn)?;
73+
}
7174
keywords::table.filter(lower(keywords::keyword).eq(any(lowercase_names)))
7275
.load(conn)
7376
}

0 commit comments

Comments
 (0)