From 59372e1bf097e5455e90944660adca33705ade14 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 20 Jan 2017 16:04:50 -0500 Subject: [PATCH] Show most popular keywords and categories on the home page --- app/styles/home.scss | 2 +- app/templates/components/category-list.hbs | 10 ++++ app/templates/components/keyword-list.hbs | 10 ++++ app/templates/index.hbs | 8 +++ src/category.rs | 63 ++++++++++++---------- src/keyword.rs | 37 ++++++++----- src/krate.rs | 14 +++++ 7 files changed, 102 insertions(+), 42 deletions(-) create mode 100644 app/templates/components/category-list.hbs create mode 100644 app/templates/components/keyword-list.hbs diff --git a/app/styles/home.scss b/app/styles/home.scss index 330287d2c9f..b94872b5c55 100644 --- a/app/styles/home.scss +++ b/app/styles/home.scss @@ -125,7 +125,7 @@ #home-crates { @include flex-wrap(wrap); - @include justify-content(center); + @include justify-content(left); > div { margin: 0; diff --git a/app/templates/components/category-list.hbs b/app/templates/components/category-list.hbs new file mode 100644 index 00000000000..f2dc5f7ca04 --- /dev/null +++ b/app/templates/components/category-list.hbs @@ -0,0 +1,10 @@ + diff --git a/app/templates/components/keyword-list.hbs b/app/templates/components/keyword-list.hbs new file mode 100644 index 00000000000..851295fe757 --- /dev/null +++ b/app/templates/components/keyword-list.hbs @@ -0,0 +1,10 @@ + diff --git a/app/templates/index.hbs b/app/templates/index.hbs index faf8164e255..e88ac9d6529 100644 --- a/app/templates/index.hbs +++ b/app/templates/index.hbs @@ -48,4 +48,12 @@

Just Updated

{{crate-list crates=model.just_updated}} +
+

Popular Keywords {{#link-to 'keywords'}}(see all){{/link-to}}

+ {{keyword-list keywords=model.popular_keywords}} +
+
+

Popular Categories {{#link-to 'categories'}}(see all){{/link-to}}

+ {{category-list categories=model.popular_categories}} +
diff --git a/src/category.rs b/src/category.rs index 97cbde9ed48..49920dfeb3c 100644 --- a/src/category.rs +++ b/src/category.rs @@ -144,6 +144,40 @@ impl Category { Ok(rows.iter().next().unwrap().get("count")) } + pub fn toplevel(conn: &GenericConnection, + sort: &str, + limit: i64, + offset: i64) -> CargoResult> { + + let sort_sql = match sort { + "crates" => "ORDER BY crates_cnt DESC", + _ => "ORDER BY category ASC", + }; + + // Collect all the top-level categories and sum up the crates_cnt of + // the crates in all subcategories + let stmt = try!(conn.prepare(&format!( + "SELECT c.id, c.category, c.slug, c.description, c.created_at, \ + COALESCE (( \ + SELECT sum(c2.crates_cnt)::int \ + FROM categories as c2 \ + WHERE c2.slug = c.slug \ + OR c2.slug LIKE c.slug || '::%' \ + ), 0) as crates_cnt \ + FROM categories as c \ + WHERE c.category NOT LIKE '%::%' {} \ + LIMIT $1 OFFSET $2", + sort_sql + ))); + + let categories: Vec<_> = try!(stmt.query(&[&limit, &offset])) + .iter() + .map(|row| Model::from_row(&row)) + .collect(); + + Ok(categories) + } + pub fn subcategories(&self, conn: &GenericConnection) -> CargoResult> { let stmt = try!(conn.prepare("\ @@ -183,34 +217,9 @@ pub fn index(req: &mut Request) -> CargoResult { let (offset, limit) = try!(req.pagination(10, 100)); let query = req.query(); let sort = query.get("sort").map_or("alpha", String::as_str); - let sort_sql = match sort { - "crates" => "ORDER BY crates_cnt DESC", - _ => "ORDER BY category ASC", - }; - // Collect all the top-level categories and sum up the crates_cnt of - // the crates in all subcategories - let stmt = try!(conn.prepare(&format!( - "SELECT c.id, c.category, c.slug, c.description, c.created_at, \ - COALESCE (( \ - SELECT sum(c2.crates_cnt)::int \ - FROM categories as c2 \ - WHERE c2.slug = c.slug \ - OR c2.slug LIKE c.slug || '::%' \ - ), 0) as crates_cnt \ - FROM categories as c \ - WHERE c.category NOT LIKE '%::%' {} \ - LIMIT $1 OFFSET $2", - sort_sql - ))); - - let categories: Vec<_> = try!(stmt.query(&[&limit, &offset])) - .iter() - .map(|row| { - let category: Category = Model::from_row(&row); - category.encodable() - }) - .collect(); + let categories = try!(Category::toplevel(conn, sort, limit, offset)); + let categories = categories.into_iter().map(Category::encodable).collect(); // Query for the total count of categories let total = try!(Category::count_toplevel(conn)); diff --git a/src/keyword.rs b/src/keyword.rs index dfdd6bf176c..f82615c6fb2 100644 --- a/src/keyword.rs +++ b/src/keyword.rs @@ -54,6 +54,26 @@ impl Keyword { })))) } + pub fn all(conn: &GenericConnection, sort: &str, limit: i64, offset: i64) + -> CargoResult> { + + let sort_sql = match sort { + "crates" => "ORDER BY crates_cnt DESC", + _ => "ORDER BY keyword ASC", + }; + + let stmt = try!(conn.prepare(&format!("SELECT * FROM keywords {} + LIMIT $1 OFFSET $2", + sort_sql))); + + let keywords: Vec<_> = try!(stmt.query(&[&limit, &offset])) + .iter() + .map(|row| Model::from_row(&row)) + .collect(); + + Ok(keywords) + } + pub fn valid_name(name: &str) -> bool { if name.len() == 0 { return false } name.chars().next().unwrap().is_alphanumeric() && @@ -131,20 +151,9 @@ pub fn index(req: &mut Request) -> CargoResult { let (offset, limit) = try!(req.pagination(10, 100)); let query = req.query(); let sort = query.get("sort").map(|s| &s[..]).unwrap_or("alpha"); - let sort_sql = match sort { - "crates" => "ORDER BY crates_cnt DESC", - _ => "ORDER BY keyword ASC", - }; - - // Collect all the keywords - let stmt = try!(conn.prepare(&format!("SELECT * FROM keywords {} - LIMIT $1 OFFSET $2", - sort_sql))); - let mut keywords = Vec::new(); - for row in try!(stmt.query(&[&limit, &offset])).iter() { - let keyword: Keyword = Model::from_row(&row); - keywords.push(keyword.encodable()); - } + + let keywords = try!(Keyword::all(conn, sort, limit, offset)); + let keywords = keywords.into_iter().map(Keyword::encodable).collect(); // Query for the total count of keywords let total = try!(Keyword::count(conn)); diff --git a/src/krate.rs b/src/krate.rs index 1fc5a486a79..c627ff7823f 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -650,6 +650,16 @@ pub fn summary(req: &mut Request) -> CargoResult { let most_downloaded = try!(tx.prepare("SELECT * FROM crates \ ORDER BY downloads DESC LIMIT 10")); + let popular_keywords = try!(Keyword::all(tx, "crates", 10, 0)); + let popular_keywords = popular_keywords.into_iter() + .map(Keyword::encodable) + .collect(); + + let popular_categories = try!(Category::toplevel(tx, "crates", 10, 0)); + let popular_categories = popular_categories.into_iter() + .map(Category::encodable) + .collect(); + #[derive(RustcEncodable)] struct R { num_downloads: i64, @@ -657,6 +667,8 @@ pub fn summary(req: &mut Request) -> CargoResult { new_crates: Vec, most_downloaded: Vec, just_updated: Vec, + popular_keywords: Vec, + popular_categories: Vec, } Ok(req.json(&R { num_downloads: num_downloads, @@ -664,6 +676,8 @@ pub fn summary(req: &mut Request) -> CargoResult { new_crates: try!(to_crates(new_crates)), most_downloaded: try!(to_crates(most_downloaded)), just_updated: try!(to_crates(just_updated)), + popular_keywords: popular_keywords, + popular_categories: popular_categories, })) }