Skip to content

Commit f8c7003

Browse files
committed
Merge remote-tracking branch 'upstream/master' into newBadgesAdd
2 parents 0e210ea + 63d3b30 commit f8c7003

File tree

8 files changed

+166
-236
lines changed

8 files changed

+166
-236
lines changed

src/app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@ impl App {
4949

5050
let db_config = r2d2::Config::builder()
5151
.pool_size(if config.env == ::Env::Production {10} else {1})
52+
.min_idle(if config.env == ::Env::Production {Some(5)} else {None})
5253
.helper_threads(if config.env == ::Env::Production {3} else {1})
5354
.build();
5455
let diesel_db_config = r2d2::Config::builder()
55-
.pool_size(if config.env == ::Env::Production {50} else {1})
56+
.pool_size(if config.env == ::Env::Production {30} else {1})
5657
.min_idle(if config.env == ::Env::Production {Some(5)} else {None})
5758
.helper_threads(if config.env == ::Env::Production {3} else {1})
5859
.build();

src/badge.rs

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use Model;
21
use krate::Crate;
32
use schema::badges;
43
use util::CargoResult;
54

65
use diesel::pg::{Pg, PgConnection};
76
use diesel::prelude::*;
8-
use pg::GenericConnection;
9-
use pg::rows::Row;
107
use serde_json;
118
use std::collections::HashMap;
129

@@ -59,17 +56,6 @@ impl Queryable<badges::SqlType, Pg> for Badge {
5956
}
6057
}
6158

62-
impl Model for Badge {
63-
fn from_row(row: &Row) -> Badge {
64-
let badge_type: String = row.get("badge_type");
65-
let attributes: serde_json::Value = row.get("attributes");
66-
let json = json!({"badge_type": badge_type, "attributes": attributes});
67-
serde_json::from_value(json)
68-
.expect("Invalid CI badge in the database")
69-
}
70-
fn table_name(_: Option<Badge>) -> &'static str { "badges" }
71-
}
72-
7359
impl Badge {
7460
pub fn encodable(self) -> EncodableBadge {
7561
serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
@@ -127,37 +113,4 @@ impl Badge {
127113
Ok(invalid_badges)
128114
})
129115
}
130-
131-
pub fn update_crate_old(conn: &GenericConnection,
132-
krate: &Crate,
133-
badges: HashMap<String, HashMap<String, String>>)
134-
-> CargoResult<Vec<String>> {
135-
136-
let mut invalid_badges = vec![];
137-
138-
let badges: Vec<Badge> = badges.into_iter().filter_map(|(k, v)| {
139-
let json = json!({"badge_type": k, "attributes": v});
140-
serde_json::from_value(json)
141-
.map_err(|_| invalid_badges.push(k))
142-
.ok()
143-
}).collect();
144-
145-
conn.execute("\
146-
DELETE FROM badges \
147-
WHERE crate_id = $1;",
148-
&[&krate.id]
149-
)?;
150-
151-
for badge in badges {
152-
let json = serde_json::to_value(badge)?;
153-
conn.execute("\
154-
INSERT INTO badges (crate_id, badge_type, attributes) \
155-
VALUES ($1, $2, $3) \
156-
ON CONFLICT (crate_id, badge_type) DO UPDATE \
157-
SET attributes = EXCLUDED.attributes;",
158-
&[&krate.id, &json["badge_type"].as_str(), &json["attributes"]]
159-
)?;
160-
}
161-
Ok(invalid_badges)
162-
}
163116
}

src/keyword.rs

Lines changed: 41 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
use std::ascii::AsciiExt;
2-
use std::collections::HashMap;
32
use time::Timespec;
43

54
use conduit::{Request, Response};
65
use conduit_router::RequestParams;
76
use diesel::pg::PgConnection;
87
use diesel::prelude::*;
98
use diesel;
10-
use pg::GenericConnection;
119
use pg::rows::Row;
1210

1311
use {Model, Crate};
1412
use db::RequestTransaction;
1513
use schema::*;
16-
use util::{RequestUtils, CargoResult, ChainError, internal};
17-
use util::errors::NotFound;
14+
use util::{RequestUtils, CargoResult};
1815

1916
#[derive(Clone, Identifiable, Queryable)]
2017
pub struct Keyword {
@@ -43,12 +40,11 @@ pub struct EncodableKeyword {
4340
}
4441

4542
impl Keyword {
46-
pub fn find_by_keyword(conn: &GenericConnection, name: &str)
47-
-> CargoResult<Option<Keyword>> {
48-
let stmt = conn.prepare("SELECT * FROM keywords \
49-
WHERE keyword = LOWER($1)")?;
50-
let rows = stmt.query(&[&name])?;
51-
Ok(rows.iter().next().map(|r| Model::from_row(&r)))
43+
pub fn find_by_keyword(conn: &PgConnection, name: &str)
44+
-> QueryResult<Keyword> {
45+
keywords::table
46+
.filter(keywords::keyword.eq(::lower(name)))
47+
.first(&*conn)
5248
}
5349

5450
pub fn find_or_create_all(conn: &PgConnection, names: &[&str]) -> QueryResult<Vec<Keyword>> {
@@ -60,58 +56,26 @@ impl Keyword {
6056
struct NewKeyword<'a> {
6157
keyword: &'a str,
6258
}
63-
sql_function!(lower, lower_t, (x: ::diesel::types::Text) -> ::diesel::types::Text);
6459

65-
let (lowercase_names, new_keywords): (Vec<_>, Vec<_>) = names.iter()
66-
.map(|s| (s.to_lowercase(), NewKeyword { keyword: *s }))
67-
.unzip();
60+
let lowercase_names: Vec<_> = names.iter()
61+
.map(|s| s.to_lowercase())
62+
.collect();
63+
64+
let new_keywords: Vec<_> = lowercase_names.iter()
65+
.map(|s| NewKeyword { keyword: s })
66+
.collect();
6867

6968
// https://github.com/diesel-rs/diesel/issues/797
7069
if !new_keywords.is_empty() {
71-
diesel::insert(&new_keywords.on_conflict_do_nothing()).into(keywords::table)
70+
diesel::insert(&new_keywords.on_conflict_do_nothing())
71+
.into(keywords::table)
7272
.execute(conn)?;
7373
}
74-
keywords::table.filter(lower(keywords::keyword).eq(any(lowercase_names)))
74+
keywords::table
75+
.filter(::lower(keywords::keyword).eq(any(&lowercase_names)))
7576
.load(conn)
7677
}
7778

78-
pub fn find_or_insert(conn: &GenericConnection, name: &str)
79-
-> CargoResult<Keyword> {
80-
// TODO: racy (the select then insert is not atomic)
81-
let stmt = conn.prepare("SELECT * FROM keywords
82-
WHERE keyword = LOWER($1)")?;
83-
for row in stmt.query(&[&name])?.iter() {
84-
return Ok(Model::from_row(&row))
85-
}
86-
87-
let stmt = conn.prepare("INSERT INTO keywords (keyword) VALUES (LOWER($1))
88-
RETURNING *")?;
89-
let rows = stmt.query(&[&name])?;
90-
Ok(Model::from_row(&rows.iter().next().chain_error(|| {
91-
internal("no version returned")
92-
})?))
93-
}
94-
95-
pub fn all(conn: &GenericConnection, sort: &str, limit: i64, offset: i64)
96-
-> CargoResult<Vec<Keyword>> {
97-
98-
let sort_sql = match sort {
99-
"crates" => "ORDER BY crates_cnt DESC",
100-
_ => "ORDER BY keyword ASC",
101-
};
102-
103-
let stmt = conn.prepare(&format!("SELECT * FROM keywords {}
104-
LIMIT $1 OFFSET $2",
105-
sort_sql))?;
106-
107-
let keywords: Vec<_> = stmt.query(&[&limit, &offset])?
108-
.iter()
109-
.map(|row| Model::from_row(&row))
110-
.collect();
111-
112-
Ok(keywords)
113-
}
114-
11579
pub fn valid_name(name: &str) -> bool {
11680
if name.is_empty() { return false }
11781
name.chars().next().unwrap().is_alphanumeric() &&
@@ -144,47 +108,6 @@ impl Keyword {
144108
Ok(())
145109
})
146110
}
147-
148-
pub fn update_crate_old(conn: &GenericConnection,
149-
krate: &Crate,
150-
keywords: &[String]) -> CargoResult<()> {
151-
let old_kws = krate.keywords(conn)?;
152-
let old_kws = old_kws.iter().map(|kw| {
153-
(&kw.keyword[..], kw)
154-
}).collect::<HashMap<_, _>>();
155-
let new_kws = keywords.iter().map(|k| {
156-
let kw = Keyword::find_or_insert(conn, k)?;
157-
Ok((k.as_str(), kw))
158-
}).collect::<CargoResult<HashMap<_, _>>>()?;
159-
160-
let to_rm = old_kws.iter().filter(|&(kw, _)| {
161-
!new_kws.contains_key(kw)
162-
}).map(|(_, v)| v.id).collect::<Vec<_>>();
163-
let to_add = new_kws.iter().filter(|&(kw, _)| {
164-
!old_kws.contains_key(kw)
165-
}).map(|(_, v)| v.id).collect::<Vec<_>>();
166-
167-
if !to_rm.is_empty() {
168-
conn.execute("DELETE FROM crates_keywords
169-
WHERE keyword_id = ANY($1)
170-
AND crate_id = $2",
171-
&[&to_rm, &krate.id])?;
172-
}
173-
174-
if !to_add.is_empty() {
175-
let insert = to_add.iter().map(|id| {
176-
let crate_id: i32 = krate.id;
177-
let id: i32 = *id;
178-
format!("({}, {})", crate_id, id)
179-
}).collect::<Vec<_>>().join(", ");
180-
conn.execute(&format!("INSERT INTO crates_keywords
181-
(crate_id, keyword_id) VALUES {}",
182-
insert),
183-
&[])?;
184-
}
185-
186-
Ok(())
187-
}
188111
}
189112

190113
impl Model for Keyword {
@@ -201,34 +124,49 @@ impl Model for Keyword {
201124

202125
/// Handles the `GET /keywords` route.
203126
pub fn index(req: &mut Request) -> CargoResult<Response> {
204-
let conn = req.tx()?;
127+
use diesel::expression::dsl::sql;
128+
use diesel::types::BigInt;
129+
use schema::keywords;
130+
131+
let conn = req.db_conn()?;
205132
let (offset, limit) = req.pagination(10, 100)?;
206133
let query = req.query();
207134
let sort = query.get("sort").map(|s| &s[..]).unwrap_or("alpha");
208135

209-
let keywords = Keyword::all(conn, sort, limit, offset)?;
210-
let keywords = keywords.into_iter().map(Keyword::encodable).collect();
136+
let mut query = keywords::table
137+
.select((keywords::all_columns, sql::<BigInt>("COUNT(*) OVER ()")))
138+
.limit(limit)
139+
.offset(offset)
140+
.into_boxed();
211141

212-
// Query for the total count of keywords
213-
let total = Keyword::count(conn)?;
142+
if sort == "crates" {
143+
query = query.order(keywords::crates_cnt.desc());
144+
} else {
145+
query = query.order(keywords::keyword.asc());
146+
}
147+
148+
let data = query.load::<(Keyword, i64)>(&*conn)?;
149+
let total = data.get(0).map(|&(_, t)| t).unwrap_or(0);
150+
let kws = data.into_iter()
151+
.map(|(k, _)| k.encodable()).collect::<Vec<_>>();
214152

215153
#[derive(RustcEncodable)]
216154
struct R { keywords: Vec<EncodableKeyword>, meta: Meta }
217155
#[derive(RustcEncodable)]
218156
struct Meta { total: i64 }
219157

220158
Ok(req.json(&R {
221-
keywords: keywords,
159+
keywords: kws,
222160
meta: Meta { total: total },
223161
}))
224162
}
225163

226164
/// Handles the `GET /keywords/:keyword_id` route.
227165
pub fn show(req: &mut Request) -> CargoResult<Response> {
228166
let name = &req.params()["keyword_id"];
229-
let conn = req.tx()?;
230-
let kw = Keyword::find_by_keyword(conn, name)?;
231-
let kw = kw.chain_error(|| NotFound)?;
167+
let conn = req.db_conn()?;
168+
169+
let kw = Keyword::find_by_keyword(&conn, name)?;
232170

233171
#[derive(RustcEncodable)]
234172
struct R { keyword: EncodableKeyword }

src/krate.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -609,11 +609,8 @@ impl Crate {
609609
Ok(rows.iter().map(|r| Model::from_row(&r)).collect())
610610
}
611611

612-
pub fn badges(&self, conn: &GenericConnection) -> CargoResult<Vec<Badge>> {
613-
let stmt = conn.prepare("SELECT badges.* from badges \
614-
WHERE badges.crate_id = $1")?;
615-
let rows = stmt.query(&[&self.id])?;
616-
Ok(rows.iter().map(|r| Model::from_row(&r)).collect())
612+
pub fn badges(&self, conn: &PgConnection) -> QueryResult<Vec<Badge>> {
613+
badges::table.filter(badges::crate_id.eq(self.id)).load(conn)
617614
}
618615

619616
/// Returns (dependency, dependent crate name, dependent crate downloads)
@@ -709,7 +706,7 @@ pub fn index(req: &mut Request) -> CargoResult<Response> {
709706
query = query.filter(crates::id.eq_any(
710707
crates_keywords::table.select(crates_keywords::crate_id)
711708
.inner_join(keywords::table)
712-
.filter(lower(keywords::keyword).eq(lower(kw)))
709+
.filter(::lower(keywords::keyword).eq(::lower(kw)))
713710
));
714711
} else if let Some(letter) = params.get("letter") {
715712
let pattern = format!("{}%", letter.chars().next().unwrap()
@@ -1303,4 +1300,3 @@ pub fn reverse_dependencies(req: &mut Request) -> CargoResult<Response> {
13031300

13041301
use diesel::types::Text;
13051302
sql_function!(canon_crate_name, canon_crate_name_t, (x: Text) -> Text);
1306-
sql_function!(lower, lower_t, (x: Text) -> Text);

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,5 @@ pub fn env(s: &str) -> String {
227227
panic!("must have `{}` defined", s)
228228
})
229229
}
230+
231+
sql_function!(lower, lower_t, (x: ::diesel::types::Text) -> ::diesel::types::Text);

src/tests/all.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use cargo_registry::krate::NewCrate;
3232
use cargo_registry::upload as u;
3333
use cargo_registry::user::NewUser;
3434
use cargo_registry::version::NewVersion;
35-
use cargo_registry::{User, Crate, Version, Keyword, Dependency, Category, Model, Replica};
35+
use cargo_registry::{User, Crate, Version, Dependency, Category, Model, Replica};
3636
use conduit::{Request, Method};
3737
use conduit_test::MockRequest;
3838
use diesel::pg::PgConnection;
@@ -296,10 +296,6 @@ fn mock_dep(req: &mut Request, version: &Version, krate: &Crate,
296296
&target.map(|s| s.to_string())).unwrap()
297297
}
298298

299-
fn mock_keyword(req: &mut Request, name: &str) -> Keyword {
300-
Keyword::find_or_insert(req.tx().unwrap(), name).unwrap()
301-
}
302-
303299
fn new_category<'a>(category: &'a str, slug: &'a str) -> NewCategory<'a> {
304300
NewCategory { category: category, slug: slug, ..NewCategory::default() }
305301
}

0 commit comments

Comments
 (0)