diff --git a/src/bin/cratesfyi.rs b/src/bin/cratesfyi.rs index bc6201bc7..509123203 100644 --- a/src/bin/cratesfyi.rs +++ b/src/bin/cratesfyi.rs @@ -371,10 +371,12 @@ impl BuildSubcommand { .pool()? .get() .context("failed to get a database connection")?; - let res = - conn.query("SELECT * FROM config WHERE name = 'rustc_version';", &[])?; + let res = conn.query_one( + "SELECT COUNT(*) > 1 FROM config WHERE name = 'rustc_version';", + &[], + )?; - if !res.is_empty() { + if res.get(0) { println!("update-toolchain was already called in the past, exiting"); return Ok(()); } diff --git a/src/build_queue.rs b/src/build_queue.rs index a5490abc6..876b34918 100644 --- a/src/build_queue.rs +++ b/src/build_queue.rs @@ -35,27 +35,27 @@ impl BuildQueue { } pub(crate) fn pending_count(&self) -> Result { - let res = self.db.get()?.query( + let res = self.db.get()?.query_one( "SELECT COUNT(*) FROM queue WHERE attempt < $1;", &[&self.max_attempts], )?; - Ok(res[0].get::<_, i64>(0) as usize) + Ok(res.get::<_, i64>(0) as usize) } pub(crate) fn prioritized_count(&self) -> Result { - let res = self.db.get()?.query( + let res = self.db.get()?.query_one( "SELECT COUNT(*) FROM queue WHERE attempt < $1 AND priority <= 0;", &[&self.max_attempts], )?; - Ok(res[0].get::<_, i64>(0) as usize) + Ok(res.get::<_, i64>(0) as usize) } pub(crate) fn failed_count(&self) -> Result { - let res = self.db.get()?.query( + let res = self.db.get()?.query_one( "SELECT COUNT(*) FROM queue WHERE attempt >= $1;", &[&self.max_attempts], )?; - Ok(res[0].get::<_, i64>(0) as usize) + Ok(res.get::<_, i64>(0) as usize) } pub(crate) fn queued_crates(&self) -> Result> { @@ -98,11 +98,11 @@ impl BuildQueue { } Err(e) => { // Increase attempt count - let rows = conn.query( + let rows = conn.query_one( "UPDATE queue SET attempt = attempt + 1 WHERE id = $1 RETURNING attempt;", &[&to_process.id], )?; - let attempt: i32 = rows[0].get(0); + let attempt: i32 = rows.get(0); if attempt >= self.max_attempts { crate::web::metrics::FAILED_BUILDS.inc(); diff --git a/src/db/add_package.rs b/src/db/add_package.rs index 2bc4062fb..c8cd8df28 100644 --- a/src/db/add_package.rs +++ b/src/db/add_package.rs @@ -137,7 +137,7 @@ pub(crate) fn add_build_into_database( res: &BuildResult, ) -> Result { debug!("Adding build into database"); - let rows = conn.query( + let row = conn.query_one( "INSERT INTO builds (rid, rustc_version, cratesfyi_version, build_status, output) @@ -151,19 +151,23 @@ pub(crate) fn add_build_into_database( &res.build_log, ], )?; - Ok(rows[0].get(0)) + Ok(row.get(0)) } fn initialize_package_in_database(conn: &mut Client, pkg: &MetadataPackage) -> Result { - let mut rows = conn.query("SELECT id FROM crates WHERE name = $1", &[&pkg.name])?; // insert crate into database if it is not exists - if rows.is_empty() { - rows = conn.query( - "INSERT INTO crates (name) VALUES ($1) RETURNING id", - &[&pkg.name], - )?; - } - Ok(rows[0].get(0)) + let row = conn + .query_opt("SELECT id FROM crates WHERE name = $1", &[&pkg.name]) + .transpose() + .unwrap_or_else(|| { + conn.query_one( + "INSERT INTO crates (name) + VALUES ($1) + RETURNING id", + &[&pkg.name], + ) + })?; + Ok(row.get(0)) } /// Convert dependencies into Vec<(String, String, String)> @@ -257,23 +261,26 @@ fn add_keywords_into_database( for keyword in &pkg.keywords { let slug = slugify(&keyword); let keyword_id: i32 = { - let rows = conn.query("SELECT id FROM keywords WHERE slug = $1", &[&slug])?; - if !rows.is_empty() { - rows[0].get(0) - } else { - conn.query( - "INSERT INTO keywords (name, slug) VALUES ($1, $2) RETURNING id", - &[&keyword, &slug], - )?[0] - .get(0) - } + conn.query_opt("SELECT id FROM keywords WHERE slug = $1", &[&slug]) + .transpose() + .unwrap_or_else(|| { + conn.query_one( + "INSERT INTO keywords (name, slug) + VALUES ($1, $2) + RETURNING id", + &[&keyword, &slug], + ) + })? + .get(0) }; - // add releationship - let _ = conn.query( - "INSERT INTO keyword_rels (rid, kid) VALUES ($1, $2)", + // add relationship + conn.execute( + "INSERT INTO keyword_rels (rid, kid) + VALUES ($1, $2) + ON CONFLICT DO NOTHING", &[&release_id, &keyword_id], - ); + )?; } Ok(()) @@ -301,24 +308,32 @@ fn add_authors_into_database( let slug = slugify(&author); let author_id: i32 = { - let rows = conn.query("SELECT id FROM authors WHERE slug = $1", &[&slug])?; - if !rows.is_empty() { - rows[0].get(0) - } else { - conn.query( - "INSERT INTO authors (name, email, slug) VALUES ($1, $2, $3) - RETURNING id", - &[&author, &email, &slug], - )?[0] - .get(0) - } + // TODO: If an author uses different email addresses per crate, or multiple authors + // have the same slugified name, this will flip-flop their name and email address + // on each crate publish. + // + // But, at least doing an upsert will result in their email/exact name rendering + // being updated if they change it in a new release. + conn.query_one( + "INSERT INTO authors (name, email, slug) + VALUES ($1, $2, $3) + ON CONFLICT (slug) DO UPDATE + SET + name = $1, + email = $2 + RETURNING id", + &[&author, &email, &slug], + )? + .get(0) }; // add relationship - let _ = conn.query( - "INSERT INTO author_rels (rid, aid) VALUES ($1, $2)", + conn.execute( + "INSERT INTO author_rels (rid, aid) + VALUES ($1, $2) + ON CONFLICT DO NOTHING", &[&release_id, &author_id], - ); + )?; } } @@ -331,7 +346,14 @@ pub fn update_crate_data_in_database( registry_data: &CrateData, ) -> Result<()> { info!("Updating crate data for {}", name); - let crate_id = conn.query("SELECT id FROM crates WHERE crates.name = $1", &[&name])?[0].get(0); + let crate_id = conn + .query_one( + "SELECT id + FROM crates + WHERE crates.name = $1", + &[&name], + )? + .get(0); update_owners_in_database(conn, ®istry_data.owners, crate_id)?; @@ -362,7 +384,7 @@ fn update_owners_in_database( // Update any existing owner data since it is mutable and could have changed since last // time we pulled it let owner_id: i32 = { - conn.query( + conn.query_one( " INSERT INTO owners (login, avatar, name, email) VALUES ($1, $2, $3, $4) @@ -374,12 +396,12 @@ fn update_owners_in_database( RETURNING id ", &[&owner.login, &owner.avatar, &owner.name, &owner.email], - )?[0] - .get(0) + )? + .get(0) }; // add relationship - conn.query( + conn.execute( "INSERT INTO owner_rels (cid, oid) VALUES ($1, $2) ON CONFLICT DO NOTHING", &[&crate_id, &owner_id], )?; @@ -391,7 +413,7 @@ fn update_owners_in_database( for login in to_remove { debug!("Removing owner relationship {}", login); // remove relationship - conn.query( + conn.execute( " DELETE FROM owner_rels USING owners @@ -417,7 +439,7 @@ where ON CONFLICT DO NOTHING;"; let prepared = conn.prepare(sql)?; for alg in algorithms { - conn.query(&prepared, &[&release_id, &(alg as i32)])?; + conn.execute(&prepared, &[&release_id, &(alg as i32)])?; } Ok(()) } diff --git a/src/db/blacklist.rs b/src/db/blacklist.rs index 56abfd031..5b7a52013 100644 --- a/src/db/blacklist.rs +++ b/src/db/blacklist.rs @@ -12,11 +12,11 @@ enum BlacklistError { /// Returns whether the given name is blacklisted. pub fn is_blacklisted(conn: &mut Client, name: &str) -> Result { - let rows = conn.query( + let row = conn.query_one( "SELECT COUNT(*) FROM blacklisted_crates WHERE crate_name = $1;", &[&name], )?; - let count: i64 = rows[0].get(0); + let count: i64 = row.get(0); Ok(count != 0) } diff --git a/src/db/delete.rs b/src/db/delete.rs index 0f354d3d3..5d2c5a8f5 100644 --- a/src/db/delete.rs +++ b/src/db/delete.rs @@ -39,8 +39,8 @@ pub fn delete_version( } fn get_id(conn: &mut Client, name: &str) -> Result { - let crate_id_res = conn.query("SELECT id FROM crates WHERE name = $1", &[&name])?; - if let Some(row) = crate_id_res.into_iter().next() { + let row = conn.query_opt("SELECT id FROM crates WHERE name = $1", &[&name])?; + if let Some(row) = row { Ok(row.get("id")) } else { Err(CrateDeletionError::MissingCrate(name.into()).into()) @@ -123,15 +123,15 @@ mod tests { use postgres::Client; fn crate_exists(conn: &mut Client, name: &str) -> Result { - Ok(!conn - .query("SELECT * FROM crates WHERE name = $1;", &[&name])? - .is_empty()) + Ok(conn + .query_one("SELECT COUNT(*) > 0 FROM crates WHERE name = $1;", &[&name])? + .get(0)) } fn release_exists(conn: &mut Client, id: i32) -> Result { - Ok(!conn - .query("SELECT * FROM releases WHERE id = $1;", &[&id])? - .is_empty()) + Ok(conn + .query_one("SELECT COUNT(*) > 0 FROM releases WHERE id = $1;", &[&id])? + .get(0)) } #[test] @@ -160,7 +160,7 @@ mod tests { let pkg1_id = &db .conn() - .query("SELECT id FROM crates WHERE name = 'package-1';", &[])?[0] + .query_one("SELECT id FROM crates WHERE name = 'package-1';", &[])? .get("id"); delete_crate_from_database(&mut db.conn(), "package-1", *pkg1_id)?; @@ -209,10 +209,7 @@ mod tests { assert!(release_exists(&mut db.conn(), v2)?); let crate_id = db .conn() - .query("SELECT crate_id FROM releases WHERE id = $1", &[&v1])? - .into_iter() - .next() - .unwrap() + .query_one("SELECT crate_id FROM releases WHERE id = $1", &[&v1])? .get(0); assert_eq!( authors(&mut db.conn(), crate_id)?, diff --git a/src/docbuilder/limits.rs b/src/docbuilder/limits.rs index 58f53a8ae..9673b2b15 100644 --- a/src/docbuilder/limits.rs +++ b/src/docbuilder/limits.rs @@ -28,12 +28,11 @@ impl Limits { pub(crate) fn for_crate(conn: &mut Client, name: &str) -> Result { let mut limits = Self::default(); - let res = conn.query( + let res = conn.query_opt( "SELECT * FROM sandbox_overrides WHERE crate_name = $1;", &[&name], )?; - if !res.is_empty() { - let row = &res[0]; + if let Some(row) = res { if let Some(memory) = row.get::<_, Option>("max_memory_bytes") { limits.memory = memory as usize; } @@ -84,7 +83,7 @@ mod test { let hexponent = Limits::for_crate(&mut db.conn(), krate)?; assert_eq!(hexponent, Limits::default()); - db.conn().query( + db.conn().execute( "INSERT INTO sandbox_overrides (crate_name, max_targets) VALUES ($1, 15)", &[&krate], )?; @@ -106,7 +105,7 @@ mod test { targets: 1, ..Limits::default() }; - db.conn().query( + db.conn().execute( "INSERT INTO sandbox_overrides (crate_name, max_memory_bytes, timeout_seconds, max_targets) VALUES ($1, $2, $3, $4)", &[&krate, &(limits.memory as i64), &(limits.timeout.as_secs() as i32), &(limits.targets as i32)] diff --git a/src/docbuilder/mod.rs b/src/docbuilder/mod.rs index ede7d2ac8..b49d2792a 100644 --- a/src/docbuilder/mod.rs +++ b/src/docbuilder/mod.rs @@ -68,7 +68,7 @@ impl DocBuilder { debug!("Loading database cache"); let mut conn = self.db.get()?; - for row in &mut conn.query( + for row in conn.query( "SELECT name, version FROM crates, releases \ WHERE crates.id = releases.crate_id", &[], diff --git a/src/docbuilder/rustwide_builder.rs b/src/docbuilder/rustwide_builder.rs index c975238c9..d1e3ff6cf 100644 --- a/src/docbuilder/rustwide_builder.rs +++ b/src/docbuilder/rustwide_builder.rs @@ -260,7 +260,7 @@ impl RustwideBuilder { } add_path_into_database(&self.storage, "", &dest)?; - conn.query( + conn.execute( "INSERT INTO config (name, value) VALUES ('rustc_version', $1) \ ON CONFLICT (name) DO UPDATE SET value = $1;", &[&Value::String(self.rustc_version.clone())], diff --git a/src/storage/database.rs b/src/storage/database.rs index 9d6343607..28fee1fa0 100644 --- a/src/storage/database.rs +++ b/src/storage/database.rs @@ -2,6 +2,7 @@ use super::{Blob, StorageTransaction}; use crate::db::Pool; use chrono::{DateTime, NaiveDateTime, Utc}; use failure::Error; +use log::debug; use postgres::Transaction; pub(crate) struct DatabaseBackend { @@ -14,9 +15,9 @@ impl DatabaseBackend { } pub(super) fn exists(&self, path: &str) -> Result { - let query = "SELECT COUNT(*) > 0 FROM files WHERE path = $1"; let mut conn = self.pool.get()?; - Ok(conn.query(query, &[&path])?[0].get(0)) + let row = conn.query_one("SELECT COUNT(*) > 0 FROM files WHERE path = $1", &[&path])?; + Ok(row.get(0)) } pub(super) fn get(&self, path: &str, max_size: usize) -> Result { @@ -28,41 +29,39 @@ impl DatabaseBackend { // The size limit is checked at the database level, to avoid receiving data altogether if // the limit is exceeded. - let rows = self.pool.get()?.query( - "SELECT + let row = self + .pool + .get()? + .query_opt( + "SELECT path, mime, date_updated, compression, (CASE WHEN LENGTH(content) <= $2 THEN content ELSE NULL END) AS content, (LENGTH(content) > $2) AS is_too_big FROM files WHERE path = $1;", - &[&path, &(max_size)], - )?; - - if rows.is_empty() { - Err(super::PathNotFoundError.into()) - } else { - let row = &rows[0]; - - if row.get("is_too_big") { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - crate::error::SizeLimitReached, - ) - .into()); - } - - let compression = row.get::<_, Option>("compression").map(|i| { - i.try_into() - .expect("invalid compression algorithm stored in database") - }); - Ok(Blob { - path: row.get("path"), - mime: row.get("mime"), - date_updated: DateTime::from_utc(row.get::<_, NaiveDateTime>("date_updated"), Utc), - content: row.get("content"), - compression, - }) + &[&path, &(max_size)], + )? + .ok_or_else(|| super::PathNotFoundError)?; + + if row.get("is_too_big") { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + crate::error::SizeLimitReached, + ) + .into()); } + + let compression = row.get::<_, Option>("compression").map(|i| { + i.try_into() + .expect("invalid compression algorithm stored in database") + }); + Ok(Blob { + path: row.get("path"), + mime: row.get("mime"), + date_updated: DateTime::from_utc(row.get::<_, NaiveDateTime>("date_updated"), Utc), + content: row.get("content"), + compression, + }) } pub(super) fn start_connection(&self) -> Result { @@ -106,10 +105,11 @@ impl<'a> StorageTransaction for DatabaseStorageTransaction<'a> { } fn delete_prefix(&mut self, prefix: &str) -> Result<(), Error> { - self.transaction.execute( + let deleted = self.transaction.execute( "DELETE FROM files WHERE path LIKE $1;", &[&format!("{}%", prefix.replace('%', "\\%"))], )?; + debug!("deleted {} files from prefix '{}'", deleted, prefix); Ok(()) } diff --git a/src/utils/queue.rs b/src/utils/queue.rs index 76ecb618c..aed91581d 100644 --- a/src/utils/queue.rs +++ b/src/utils/queue.rs @@ -8,13 +8,13 @@ const DEFAULT_PRIORITY: i32 = 0; /// Get the build queue priority for a crate pub fn get_crate_priority(conn: &mut Client, name: &str) -> Result { // Search the `priority` table for a priority where the crate name matches the stored pattern - let query = conn.query( + let row = conn.query_opt( "SELECT priority FROM crate_priorities WHERE $1 LIKE pattern LIMIT 1", &[&name], )?; // If no match is found, return the default priority - if let Some(row) = query.iter().next() { + if let Some(row) = row { Ok(row.get(0)) } else { Ok(DEFAULT_PRIORITY) @@ -27,7 +27,7 @@ pub fn get_crate_priority(conn: &mut Client, name: &str) -> Result { /// /// [`pattern`]: https://www.postgresql.org/docs/8.3/functions-matching.html pub fn set_crate_priority(conn: &mut Client, pattern: &str, priority: i32) -> Result<()> { - conn.query( + conn.execute( "INSERT INTO crate_priorities (pattern, priority) VALUES ($1, $2)", &[&pattern, &priority], )?; @@ -38,12 +38,12 @@ pub fn set_crate_priority(conn: &mut Client, pattern: &str, priority: i32) -> Re /// Remove a pattern from the priority table, returning the priority that it was associated with or `None` /// if nothing was removed pub fn remove_crate_priority(conn: &mut Client, pattern: &str) -> Result> { - let query = conn.query( + let row = conn.query_opt( "DELETE FROM crate_priorities WHERE pattern = $1 RETURNING priority", &[&pattern], )?; - Ok(query.iter().next().map(|row| row.get(0))) + Ok(row.map(|row| row.get(0))) } #[cfg(test)] diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 032ae5614..78ccc7d0e 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -102,13 +102,7 @@ impl CrateDetails { INNER JOIN crates ON releases.crate_id = crates.id WHERE crates.name = $1 AND releases.version = $2;"; - let rows = conn.query(query, &[&name, &version]).unwrap(); - - let krate = if rows.is_empty() { - return None; - } else { - &rows[0] - }; + let krate = conn.query_opt(query, &[&name, &version]).unwrap()?; let crate_id: i32 = krate.get("crate_id"); let release_id: i32 = krate.get("release_id"); @@ -242,8 +236,8 @@ impl CrateDetails { } fn map_to_release(conn: &mut Client, crate_id: i32, version: String) -> Release { - let rows = conn - .query( + let row = conn + .query_opt( "SELECT build_status, yanked, is_library @@ -253,14 +247,13 @@ fn map_to_release(conn: &mut Client, crate_id: i32, version: String) -> Release ) .unwrap(); - let (build_status, yanked, is_library) = - rows.iter().next().map_or_else(Default::default, |row| { - ( - row.get("build_status"), - row.get("yanked"), - row.get("is_library"), - ) - }); + let (build_status, yanked, is_library) = row.map_or_else(Default::default, |row| { + ( + row.get("build_status"), + row.get("yanked"), + row.get("is_library"), + ) + }); Release { version, diff --git a/src/web/mod.rs b/src/web/mod.rs index 2afa558ef..e93e4f9a1 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -306,9 +306,8 @@ fn match_version(conn: &mut Client, name: &str, version: Option<&str>) -> Option WHERE normalize_crate_name(name) = normalize_crate_name($1)"; let rows = conn.query(query, &[&name]).unwrap(); - let mut rows = rows.iter().peekable(); - if let Some(row) = rows.peek() { + if let Some(row) = rows.first() { let db_name = row.get(0); if db_name != name { @@ -316,7 +315,8 @@ fn match_version(conn: &mut Client, name: &str, version: Option<&str>) -> Option } }; - rows.map(|row| (row.get(1), row.get(2), row.get(3))) + rows.into_iter() + .map(|row| (row.get(1), row.get(2), row.get(3))) .collect() }; @@ -591,8 +591,8 @@ pub(crate) struct MetaData { impl MetaData { fn from_crate(conn: &mut Client, name: &str, version: &str) -> Option { - let rows = conn - .query( + let row = conn + .query_opt( "SELECT crates.name, releases.version, releases.description, @@ -604,9 +604,7 @@ impl MetaData { WHERE crates.name = $1 AND releases.version = $2", &[&name, &version], ) - .unwrap(); - - let row = rows.iter().next()?; + .unwrap()?; Some(MetaData { name: row.get(0), @@ -809,7 +807,7 @@ mod test { let release_id = release("0.3.0", env); let query = "UPDATE releases SET yanked = true WHERE id = $1 AND version = '0.3.0'"; - db.conn().query(query, &[&release_id]).unwrap(); + db.conn().execute(query, &[&release_id]).unwrap(); assert_eq!(version(None, db), None); assert_eq!(version(Some("0.3"), db), None); diff --git a/src/web/page/templates.rs b/src/web/page/templates.rs index c5eebac78..ce93abc3d 100644 --- a/src/web/page/templates.rs +++ b/src/web/page/templates.rs @@ -74,22 +74,20 @@ impl TemplateData { } fn load_rustc_resource_suffix(conn: &mut Client) -> Result { - let res = conn.query( - "SELECT value FROM config WHERE name = 'rustc_version';", - &[], - )?; - - if res.is_empty() { - failure::bail!("missing rustc version"); - } - - if let Ok(vers) = res[0].try_get::<_, Value>("value") { - if let Some(vers_str) = vers.as_str() { - return Ok(crate::utils::parse_rustc_version(vers_str)?); - } - } - - failure::bail!("failed to parse the rustc version"); + let row = conn + .query_opt( + "SELECT value FROM config WHERE name = 'rustc_version';", + &[], + )? + .ok_or_else(|| failure::err_msg("missing rustc version"))?; + + let vers: Value = row.get("value"); + let vers = vers + .as_str() + .ok_or_else(|| failure::err_msg("'rustc_version' wasn't a string"))?; + let vers = crate::utils::parse_rustc_version(vers)?; + + Ok(vers) } pub(super) fn load_templates(conn: &mut Client) -> Result { diff --git a/src/web/releases.rs b/src/web/releases.rs index 4f8e015fb..469909c9e 100644 --- a/src/web/releases.rs +++ b/src/web/releases.rs @@ -517,9 +517,9 @@ pub fn search_handler(req: &mut Request) -> IronResult { // FIXME: This is a fast query but using a constant // There are currently 280 crates with docs and 100+ // starts. This should be fine for a while. - let rows = ctry!( + let row = ctry!( req, - conn.query( + conn.query_one( "SELECT crates.name, releases.version, releases.target_name @@ -531,7 +531,6 @@ pub fn search_handler(req: &mut Request) -> IronResult { &[] ), ); - let row = rows.into_iter().next().unwrap(); let name: String = row.get("name"); let version: String = row.get("version"); @@ -564,9 +563,9 @@ pub fn search_handler(req: &mut Request) -> IronResult { // match_version should handle this instead of this code block. // This block is introduced to fix #163 let rustdoc_status = { - let rows = ctry!( + let row = ctry!( req, - conn.query( + conn.query_one( "SELECT rustdoc_status FROM releases WHERE releases.id = $1", @@ -574,10 +573,7 @@ pub fn search_handler(req: &mut Request) -> IronResult { ), ); - rows.into_iter() - .next() - .map(|r| r.get("rustdoc_status")) - .unwrap_or_default() + row.get("rustdoc_status") }; let url = if rustdoc_status { @@ -638,13 +634,11 @@ pub fn activity_handler(req: &mut Request) -> IronResult { let mut conn = extension!(req, Pool).get()?; let activity_data: Value = ctry!( req, - conn.query( + conn.query_opt( "SELECT value FROM config WHERE name = 'release_activity'", &[] ), ) - .iter() - .next() .map_or(Value::Null, |row| row.get("value")); ReleaseActivity { diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index 666a64089..9cd66d189 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -159,9 +159,9 @@ pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult { // get target name and whether it has docs // FIXME: This is a bit inefficient but allowing us to use less code in general let (target_name, has_docs): (String, bool) = { - let rows = ctry!( + let row = ctry!( req, - conn.query( + conn.query_one( "SELECT target_name, rustdoc_status FROM releases WHERE releases.id = $1", @@ -169,7 +169,7 @@ pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult { ), ); - (rows[0].get(0), rows[0].get(1)) + (row.get(0), row.get(1)) }; if target == Some("index.html") || target == Some(&target_name) { @@ -523,16 +523,16 @@ pub fn badge_handler(req: &mut Request) -> IronResult { let options = match match_version(&mut conn, &name, Some(&version)).and_then(|m| m.assume_exact()) { Some(MatchSemver::Exact((version, id))) => { - let rows = ctry!( + let row = ctry!( req, - conn.query( + conn.query_one( "SELECT rustdoc_status FROM releases WHERE releases.id = $1", &[&id] ), ); - if !rows.is_empty() && rows[0].get(0) { + if row.get(0) { BadgeOptions { subject: "docs".to_owned(), status: version, @@ -1440,8 +1440,8 @@ mod test { .version("0.13.0") .create()?; // https://stackoverflow.com/questions/18209625/how-do-i-modify-fields-inside-the-new-postgresql-json-datatype - db.conn().query( - r#"UPDATE releases SET dependencies = dependencies::jsonb #- '{0,2}' WHERE id = $1"#, + db.conn().execute( + "UPDATE releases SET dependencies = dependencies::jsonb #- '{0,2}' WHERE id = $1", &[&id], )?; let web = env.frontend(); diff --git a/src/web/sitemap.rs b/src/web/sitemap.rs index 46a751463..42c268aff 100644 --- a/src/web/sitemap.rs +++ b/src/web/sitemap.rs @@ -69,12 +69,11 @@ impl_webpage!(AboutBuilds = "core/about/builds.html"); pub fn about_builds_handler(req: &mut Request) -> IronResult { let mut conn = extension!(req, Pool).get()?; - let res = ctry!( + let rustc_version = ctry!( req, - conn.query("SELECT value FROM config WHERE name = 'rustc_version'", &[]), - ); - - let rustc_version = res.iter().next().and_then(|row| { + conn.query_opt("SELECT value FROM config WHERE name = 'rustc_version'", &[]), + ) + .and_then(|row| { if let Ok(Some(Value::String(version))) = row.try_get(0) { Some(version) } else { diff --git a/src/web/source.rs b/src/web/source.rs index 5294a4ab7..334a2ffe4 100644 --- a/src/web/source.rs +++ b/src/web/source.rs @@ -48,8 +48,8 @@ impl FileList { /// it will return list of files (and dirs) for root directory. req_path must be a /// directory or empty for root directory. fn from_path(conn: &mut Client, name: &str, version: &str, req_path: &str) -> Option { - let rows = conn - .query( + let row = conn + .query_opt( "SELECT crates.name, releases.version, releases.description, @@ -62,13 +62,9 @@ impl FileList { WHERE crates.name = $1 AND releases.version = $2", &[&name, &version], ) - .unwrap(); + .unwrap()?; - if rows.is_empty() { - return None; - } - - let files: Value = rows[0].try_get(5).ok()?; + let files: Value = row.try_get(5).ok()?; let mut file_list = Vec::new(); if let Some(files) = files.as_array() { @@ -127,12 +123,12 @@ impl FileList { Some(FileList { metadata: MetaData { - name: rows[0].get(0), - version: rows[0].get(1), - description: rows[0].get(2), - target_name: rows[0].get(3), - rustdoc_status: rows[0].get(4), - default_target: rows[0].get(6), + name: row.get(0), + version: row.get(1), + description: row.get(2), + target_name: row.get(3), + rustdoc_status: row.get(4), + default_target: row.get(6), }, files: file_list, })