Skip to content

Commit 513c74a

Browse files
committed
Optionally represent versions as links
1 parent 3c27993 commit 513c74a

File tree

2 files changed

+24
-37
lines changed

2 files changed

+24
-37
lines changed

src/krate.rs

+21-34
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::hashmap::{HashMap, Occupied, Vacant};
1+
use std::collections::HashMap;
22
use std::sync::Arc;
33
use std::time::Duration;
44
use serialize::hex::ToHex;
@@ -39,8 +39,8 @@ pub struct Crate {
3939
pub struct EncodableCrate {
4040
pub id: String,
4141
pub name: String,
42-
pub versions: Vec<i32>,
4342
pub updated_at: String,
43+
pub versions: Option<Vec<i32>>,
4444
pub created_at: String,
4545
pub downloads: i32,
4646
pub max_version: String,
@@ -50,6 +50,7 @@ pub struct EncodableCrate {
5050
#[deriving(Encodable, Decodable)]
5151
pub struct CrateLinks {
5252
pub version_downloads: String,
53+
pub versions: Option<String>,
5354
}
5455

5556
impl Crate {
@@ -93,19 +94,24 @@ impl Crate {
9394
name.chars().all(|c| c.is_alphanumeric() || c == '_' || c == '-')
9495
}
9596

96-
fn encodable(self, versions: Vec<i32>) -> EncodableCrate {
97+
fn encodable(self, versions: Option<Vec<i32>>) -> EncodableCrate {
9798
let Crate { name, created_at, updated_at, downloads,
98-
max_version, .. } = self;
99+
max_version, .. } = self;
100+
let versions_link = match versions {
101+
Some(..) => None,
102+
None => Some(format!("/crates/{}/versions", name)),
103+
};
99104
EncodableCrate {
100105
id: name.clone(),
101106
name: name.clone(),
102-
versions: versions,
103107
updated_at: ::encode_time(updated_at),
104108
created_at: ::encode_time(created_at),
105109
downloads: downloads,
110+
versions: versions,
106111
max_version: max_version.to_string(),
107112
links: CrateLinks {
108113
version_downloads: format!("/crates/{}/downloads", name),
114+
versions: versions_link,
109115
},
110116
}
111117
}
@@ -121,29 +127,6 @@ impl Crate {
121127
format!("/pkg/{}/{}-{}.tar.gz", self.name, self.name, version)
122128
}
123129

124-
pub fn encode_many(conn: &Connection, crates: Vec<Crate>)
125-
-> CargoResult<Vec<EncodableCrate>> {
126-
if crates.len() == 0 { return Ok(Vec::new()) }
127-
128-
// TODO: can rust-postgres do this escaping?
129-
let crateids: Vec<i32> = crates.iter().map(|p| p.id).collect();
130-
let mut map = HashMap::new();
131-
let stmt = try!(conn.prepare(format!("SELECT id, crate_id FROM versions \
132-
WHERE crate_id IN({:#})",
133-
crateids).as_slice()));
134-
for row in try!(stmt.query(&[])) {
135-
match map.entry(row.get("crate_id")) {
136-
Occupied(e) => e.into_mut(),
137-
Vacant(e) => e.set(Vec::new()),
138-
}.push(row.get("id"));
139-
}
140-
141-
Ok(crates.into_iter().map(|p| {
142-
let id = p.id;
143-
p.encodable(map.pop(&id).unwrap())
144-
}).collect())
145-
}
146-
147130
pub fn add_version(&mut self, conn: &Connection, ver: &semver::Version,
148131
features: &HashMap<String, Vec<String>>)
149132
-> CargoResult<Version> {
@@ -256,9 +239,9 @@ pub fn index(req: &mut Request) -> CargoResult<Response> {
256239
let stmt = try!(conn.prepare(q.as_slice()));
257240
let mut crates = Vec::new();
258241
for row in try!(stmt.query(args.as_slice())) {
259-
crates.push(Model::from_row(&row));
242+
let krate: Crate = Model::from_row(&row);
243+
crates.push(krate.encodable(None));
260244
}
261-
let crates = try!(Crate::encode_many(conn, crates));
262245

263246
// Query for the total count of crates
264247
let stmt = try!(conn.prepare(cnt));
@@ -291,8 +274,11 @@ pub fn summary(req: &mut Request) -> CargoResult<Response> {
291274
};
292275

293276
let to_crates = |stmt: PostgresStatement| {
294-
let rows = try!(stmt.query([]));
295-
Crate::encode_many(tx, rows.map(|r| Model::from_row(&r)).collect())
277+
let rows = raw_try!(stmt.query([]));
278+
Ok(rows.map(|r| {
279+
let krate: Crate = Model::from_row(&r);
280+
krate.encodable(None)
281+
}).collect::<Vec<EncodableCrate>>())
296282
};
297283
let new_crates = try!(tx.prepare("SELECT * FROM crates \
298284
ORDER BY created_at DESC LIMIT 10"));
@@ -323,11 +309,12 @@ pub fn show(req: &mut Request) -> CargoResult<Response> {
323309
let conn = try!(req.tx());
324310
let krate = try!(Crate::find_by_name(&*conn, name.as_slice()));
325311
let versions = try!(krate.versions(&*conn));
312+
let ids = versions.iter().map(|v| v.id).collect();
326313

327314
#[deriving(Encodable)]
328315
struct R { krate: EncodableCrate, versions: Vec<EncodableVersion>, }
329316
Ok(req.json(&R {
330-
krate: krate.clone().encodable(versions.iter().map(|v| v.id).collect()),
317+
krate: krate.clone().encodable(Some(ids)),
331318
versions: versions.into_iter().map(|v| {
332319
v.encodable(krate.name.as_slice())
333320
}).collect(),
@@ -421,7 +408,7 @@ pub fn new(req: &mut Request) -> CargoResult<Response> {
421408

422409
#[deriving(Encodable)]
423410
struct R { krate: EncodableCrate }
424-
Ok(req.json(&R { krate: krate.encodable(Vec::new()) }))
411+
Ok(req.json(&R { krate: krate.encodable(None) }))
425412
}
426413

427414
fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> {

src/tests/krate.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ fn index() {
6767
assert_eq!(json.meta.total, 1);
6868
assert_eq!(json.crates[0].name, krate.name);
6969
assert_eq!(json.crates[0].id, krate.name);
70-
assert_eq!(json.crates[0].versions.len(), 1);
7170
}
7271

7372
#[test]
@@ -130,9 +129,10 @@ fn show() {
130129
let json: CrateResponse = ::json(&mut response);
131130
assert_eq!(json.krate.name, krate.name);
132131
assert_eq!(json.krate.id, krate.name);
133-
assert_eq!(json.krate.versions.len(), 1);
132+
let versions = json.krate.versions.as_ref().unwrap();
133+
assert_eq!(versions.len(), 1);
134134
assert_eq!(json.versions.len(), 1);
135-
assert_eq!(json.versions[0].id, json.krate.versions[0]);
135+
assert_eq!(json.versions[0].id, versions[0]);
136136
assert_eq!(json.versions[0].krate, json.krate.id);
137137
assert_eq!(json.versions[0].num, "1.0.0".to_string());
138138
let suffix = "/crates/foo/1.0.0/download";

0 commit comments

Comments
 (0)