diff --git a/async_db/Cargo.toml b/async_db/Cargo.toml index b994daae..4d8e44c6 100644 --- a/async_db/Cargo.toml +++ b/async_db/Cargo.toml @@ -14,7 +14,7 @@ failure = "0.1.1" futures = "0.3.1" num_cpus = "1.10.0" r2d2 = "0.8.2" -r2d2_sqlite = "0.8.0" -rusqlite = "0.16" +r2d2_sqlite = "0.10" +rusqlite = "0.18" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/async_db/src/db.rs b/async_db/src/db.rs index 65329601..252f55cb 100644 --- a/async_db/src/db.rs +++ b/async_db/src/db.rs @@ -3,12 +3,13 @@ use failure::Error; use futures::{Future, TryFutureExt}; use r2d2; use r2d2_sqlite; -use rusqlite::NO_PARAMS; +use rusqlite::{Statement, NO_PARAMS}; use serde::{Deserialize, Serialize}; use std::{thread::sleep, time::Duration}; pub type Pool = r2d2::Pool; pub type Connection = r2d2::PooledConnection; +type WeatherAggResult = Result, rusqlite::Error>; #[derive(Debug, Serialize, Deserialize)] pub enum WeatherAgg { @@ -28,115 +29,96 @@ pub fn execute( query: Queries, ) -> impl Future, AWError>> { let pool = pool.clone(); - web::block(move || match query { - Queries::GetTopTenHottestYears => get_hottest_years(pool.get()?), - Queries::GetTopTenColdestYears => get_coldest_years(pool.get()?), - Queries::GetTopTenHottestMonths => get_hottest_months(pool.get()?), - Queries::GetTopTenColdestMonths => get_coldest_months(pool.get()?), + web::block(move || { + // simulate an expensive query, see comments at top of main.rs + sleep(Duration::from_secs(2)); + + let result = match query { + Queries::GetTopTenHottestYears => get_hottest_years(pool.get()?), + Queries::GetTopTenColdestYears => get_coldest_years(pool.get()?), + Queries::GetTopTenHottestMonths => get_hottest_months(pool.get()?), + Queries::GetTopTenColdestMonths => get_coldest_months(pool.get()?), + }; + result.map_err(Error::from) }) .map_err(AWError::from) } -fn get_hottest_years(conn: Connection) -> Result, Error> { - let stmt = " +fn get_hottest_years(conn: Connection) -> WeatherAggResult { + let stmt = conn.prepare( + " SELECT cast(strftime('%Y', date) as int) as theyear, sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear - ORDER BY total DESC LIMIT 10;"; + ORDER BY total DESC LIMIT 10", + )?; - let mut prep_stmt = conn.prepare(stmt)?; - let annuals = prep_stmt - .query_map(NO_PARAMS, |row| WeatherAgg::AnnualAgg { - year: row.get(0), - total: row.get(1), - }) - .and_then(|mapped_rows| { - Ok(mapped_rows - .map(|row| row.unwrap()) - .collect::>()) - })?; - - sleep(Duration::from_secs(2)); //see comments at top of main.rs - - Ok(annuals) + get_rows_as_annual_agg(stmt) } -fn get_coldest_years(conn: Connection) -> Result, Error> { - let stmt = " +fn get_coldest_years(conn: Connection) -> WeatherAggResult { + let stmt = conn.prepare( + " SELECT cast(strftime('%Y', date) as int) as theyear, sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear - ORDER BY total ASC LIMIT 10;"; + ORDER BY total ASC LIMIT 10", + )?; - let mut prep_stmt = conn.prepare(stmt)?; - let annuals = prep_stmt - .query_map(NO_PARAMS, |row| WeatherAgg::AnnualAgg { - year: row.get(0), - total: row.get(1), - }) - .and_then(|mapped_rows| { - Ok(mapped_rows - .map(|row| row.unwrap()) - .collect::>()) - })?; - - sleep(Duration::from_secs(2)); //see comments at top of main.rs - - Ok(annuals) + get_rows_as_annual_agg(stmt) } -fn get_hottest_months(conn: Connection) -> Result, Error> { - let stmt = "SELECT cast(strftime('%Y', date) as int) as theyear, +fn get_rows_as_annual_agg(mut statement: Statement) -> WeatherAggResult { + statement + .query_map(NO_PARAMS, |row| { + Ok(WeatherAgg::AnnualAgg { + year: row.get(0)?, + total: row.get(1)?, + }) + }) + .and_then(Iterator::collect) +} + +fn get_hottest_months(conn: Connection) -> WeatherAggResult { + let stmt = conn.prepare( + "SELECT cast(strftime('%Y', date) as int) as theyear, cast(strftime('%m', date) as int) as themonth, sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear, themonth - ORDER BY total DESC LIMIT 10;"; + ORDER BY total DESC LIMIT 10", + )?; - let mut prep_stmt = conn.prepare(stmt)?; - let annuals = prep_stmt - .query_map(NO_PARAMS, |row| WeatherAgg::MonthAgg { - year: row.get(0), - month: row.get(1), - total: row.get(2), - }) - .and_then(|mapped_rows| { - Ok(mapped_rows - .map(|row| row.unwrap()) - .collect::>()) - })?; - - sleep(Duration::from_secs(2)); //see comments at top of main.rs - Ok(annuals) + get_rows_as_month_agg(stmt) } -fn get_coldest_months(conn: Connection) -> Result, Error> { - let stmt = "SELECT cast(strftime('%Y', date) as int) as theyear, +fn get_coldest_months(conn: Connection) -> WeatherAggResult { + let stmt = conn.prepare( + "SELECT cast(strftime('%Y', date) as int) as theyear, cast(strftime('%m', date) as int) as themonth, sum(tmax) as total FROM nyc_weather WHERE tmax <> 'TMAX' GROUP BY theyear, themonth - ORDER BY total ASC LIMIT 10;"; + ORDER BY total ASC LIMIT 10", + )?; - let mut prep_stmt = conn.prepare(stmt)?; - let annuals = prep_stmt - .query_map(NO_PARAMS, |row| WeatherAgg::MonthAgg { - year: row.get(0), - month: row.get(1), - total: row.get(2), - }) - .and_then(|mapped_rows| { - Ok(mapped_rows - .map(|row| row.unwrap()) - .collect::>()) - })?; - - sleep(Duration::from_secs(2)); //see comments at top of main.rs - Ok(annuals) + get_rows_as_month_agg(stmt) +} + +fn get_rows_as_month_agg(mut statement: Statement) -> WeatherAggResult { + statement + .query_map(NO_PARAMS, |row| { + Ok(WeatherAgg::MonthAgg { + year: row.get(0)?, + month: row.get(1)?, + total: row.get(2)?, + }) + }) + .and_then(Iterator::collect) } diff --git a/async_db/src/main.rs b/async_db/src/main.rs index 93443ad5..90a59562 100644 --- a/async_db/src/main.rs +++ b/async_db/src/main.rs @@ -1,6 +1,7 @@ /* Actix-Web Asynchronous Database Example -This project illustrates two examples: +This project illustrates expensive and blocking database requests that runs +in a thread-pool using `web::block` with two examples: 1. An asynchronous handler that executes 4 queries in *sequential order*, collecting the results and returning them as a single serialized json object diff --git a/r2d2/Cargo.toml b/r2d2/Cargo.toml index b3444c25..220d8fa8 100644 --- a/r2d2/Cargo.toml +++ b/r2d2/Cargo.toml @@ -13,5 +13,5 @@ env_logger = "0.6" uuid = { version = "0.8", features = ["v4"] } r2d2 = "0.8" -r2d2_sqlite = "0.8" -rusqlite = "0.16" +r2d2_sqlite = "0.10" +rusqlite = "0.18" diff --git a/r2d2/test.db b/r2d2/test.db deleted file mode 100644 index 3ea0c83d..00000000 Binary files a/r2d2/test.db and /dev/null differ