Skip to content

Commit 89bc5dd

Browse files
committed
Require hyphens and underscores don't clash
1 parent 3506971 commit 89bc5dd

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

src/bin/migrate.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,28 @@ fn migrations() -> Vec<Migration> {
418418
crate_owners_unique_user_per_crate", &[]));
419419
Ok(())
420420
}),
421+
Migration::new(20150319224700, |tx| {
422+
try!(tx.execute("
423+
CREATE FUNCTION canon_crate_name(text) RETURNS text AS $$
424+
SELECT replace(lower($1), '-', '_')
425+
$$ LANGUAGE SQL
426+
", &[]));
427+
Ok(())
428+
}, |tx| {
429+
try!(tx.execute("DROP FUNCTION canon_crate_name(text)", &[]));
430+
Ok(())
431+
}),
432+
Migration::new(20150319224701, |tx| {
433+
try!(tx.execute("DROP INDEX index_crates_name", &[]));
434+
try!(tx.execute("CREATE UNIQUE INDEX index_crates_name \
435+
ON crates (canon_crate_name(name))", &[]));
436+
Ok(())
437+
}, |tx| {
438+
try!(tx.execute("DROP INDEX index_crates_name", &[]));
439+
try!(tx.execute("CREATE UNIQUE INDEX index_crates_name \
440+
ON crates (lower(name))", &[]));
441+
Ok(())
442+
}),
421443
];
422444
// NOTE: Generate a new id via `date +"%Y%m%d%H%M%S"`
423445

src/krate.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ impl Crate {
8484

8585
pub fn find_by_name(conn: &Connection, name: &str) -> CargoResult<Crate> {
8686
let stmt = try!(conn.prepare("SELECT * FROM crates \
87-
WHERE lower(name) = lower($1) LIMIT 1"));
87+
WHERE canon_crate_name(name) =
88+
canon_crate_name($1) LIMIT 1"));
8889
let row = try!(stmt.query(&[&name as &ToSql])).into_iter().next();
8990
let row = try!(row.chain_error(|| NotFound));
9091
Ok(Model::from_row(&row))
@@ -136,7 +137,8 @@ impl Crate {
136137
keywords = $5,
137138
license = $6,
138139
repository = $7
139-
WHERE lower(name) = lower($8)
140+
WHERE canon_crate_name(name) =
141+
canon_crate_name($8)
140142
RETURNING *"));
141143
let rows = try!(stmt.query(&[&documentation, &homepage,
142144
&description, &readme, &keywords,
@@ -448,9 +450,10 @@ pub fn index(req: &mut Request) -> CargoResult<Response> {
448450
pattern = format!("{}%", letter.as_slice().char_at(0)
449451
.to_lowercase().collect::<String>());
450452
needs_pattern = true;
451-
(format!("SELECT * FROM crates WHERE lower(name) LIKE $1 {}
452-
LIMIT $2 OFFSET $3", sort_sql),
453-
"SELECT COUNT(*) FROM crates WHERE lower(name) LIKE $1".to_string())
453+
(format!("SELECT * FROM crates WHERE canon_crate_name(name) \
454+
LIKE $1 {} LIMIT $2 OFFSET $3", sort_sql),
455+
"SELECT COUNT(*) FROM crates WHERE canon_crate_name(name) \
456+
LIKE $1".to_string())
454457
})
455458
}).or_else(|| {
456459
query.get("keyword").map(|kw| {
@@ -789,7 +792,8 @@ pub fn download(req: &mut Request) -> CargoResult<Response> {
789792
FROM crates
790793
INNER JOIN versions ON
791794
crates.id = versions.crate_id
792-
WHERE lower(crates.name) = lower($1)
795+
WHERE canon_crate_name(crates.name) =
796+
canon_crate_name($1)
793797
AND versions.num = $2
794798
LIMIT 1"));
795799
let rows = try!(stmt.query(&[&crate_name as &ToSql, &version as &ToSql]));

src/tests/krate.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,28 @@ fn new_crate_similar_name() {
401401
"{:?}", json.errors);
402402
}
403403

404+
#[test]
405+
fn new_crate_similar_name_hyphen() {
406+
{
407+
let (_b, app, middle) = ::app();
408+
let mut req = new_req(app, "foo-bar", "1.1.0");
409+
::mock_user(&mut req, ::user("foo"));
410+
::mock_crate(&mut req, ::krate("foo_bar"));
411+
let json = bad_resp!(middle.call(&mut req));
412+
assert!(json.errors[0].detail.as_slice().contains("previously named"),
413+
"{:?}", json.errors);
414+
}
415+
{
416+
let (_b, app, middle) = ::app();
417+
let mut req = new_req(app, "foo_bar", "1.1.0");
418+
::mock_user(&mut req, ::user("foo"));
419+
::mock_crate(&mut req, ::krate("foo-bar"));
420+
let json = bad_resp!(middle.call(&mut req));
421+
assert!(json.errors[0].detail.as_slice().contains("previously named"),
422+
"{:?}", json.errors);
423+
}
424+
}
425+
404426
#[test]
405427
fn new_krate_git_upload() {
406428
let (_b, app, middle) = ::app();

0 commit comments

Comments
 (0)