better error handling using anyhow
This commit is contained in:
parent
425ec50a5f
commit
ad3a235982
4 changed files with 66 additions and 51 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -20,6 +20,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.14.0"
|
||||
|
|
@ -812,6 +818,7 @@ checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
|||
name = "task_counter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"axum",
|
||||
"chrono",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.100"
|
||||
askama = "0.14.0"
|
||||
axum = "0.8.6"
|
||||
chrono = "0.4.42"
|
||||
|
|
|
|||
BIN
foods.db
BIN
foods.db
Binary file not shown.
109
src/main.rs
109
src/main.rs
|
|
@ -5,7 +5,7 @@ use axum::{
|
|||
Router,
|
||||
extract::{MatchedPath, Path, State},
|
||||
http::{Request, StatusCode},
|
||||
response::Html,
|
||||
response::{Html, IntoResponse, Response},
|
||||
routing::{get, post},
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
|
|
@ -80,7 +80,7 @@ impl Food {
|
|||
struct PreparedStatements {}
|
||||
|
||||
impl<'conn> PreparedStatements {
|
||||
fn check(conn: &Connection) -> rusqlite::Result<Self> {
|
||||
fn check(conn: &Connection) -> anyhow::Result<Self> {
|
||||
conn.prepare_cached(include_str!("increase.sql"))?;
|
||||
conn.prepare_cached(include_str!("decrease.sql"))?;
|
||||
conn.prepare_cached(include_str!("get_food.sql"))?;
|
||||
|
|
@ -121,10 +121,35 @@ impl<'conn> PreparedStatements {
|
|||
}
|
||||
}
|
||||
|
||||
// Make our own error that wraps `anyhow::Error`.
|
||||
struct AppError(anyhow::Error);
|
||||
|
||||
// Tell axum how to convert `AppError` into a response.
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {}", self.0),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
|
||||
// `Result<_, AppError>`. That way you don't need to do that manually.
|
||||
impl<E> From<E> for AppError
|
||||
where
|
||||
E: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(err: E) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
type ConnState = Arc<Mutex<Connection>>;
|
||||
|
||||
fn get_version(tx: &Transaction) -> rusqlite::Result<usize> {
|
||||
tx.query_one(include_str!("get_version.sql"), (), |row| row.get(0))
|
||||
fn get_version(tx: &Transaction) -> anyhow::Result<usize> {
|
||||
Ok(tx.query_one(include_str!("get_version.sql"), (), |row| row.get(0))?)
|
||||
}
|
||||
|
||||
fn get_migrations() -> [&'static str; 4] {
|
||||
|
|
@ -136,7 +161,7 @@ fn get_migrations() -> [&'static str; 4] {
|
|||
]
|
||||
}
|
||||
|
||||
fn do_migrations(conn: &mut Connection) -> rusqlite::Result<()> {
|
||||
fn do_migrations(conn: &mut Connection) -> anyhow::Result<()> {
|
||||
let migrations = get_migrations();
|
||||
let num_migrations = migrations.len();
|
||||
let tx = conn.transaction()?;
|
||||
|
|
@ -198,7 +223,7 @@ fn app(conn: Connection) -> axum::Router {
|
|||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), std::io::Error> {
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
tracing_subscriber::registry()
|
||||
.with(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||
|
|
@ -239,10 +264,11 @@ async fn main() -> Result<(), std::io::Error> {
|
|||
.local_addr()
|
||||
.expect("failed to get local listening address")
|
||||
);
|
||||
axum::serve(listener, app).await
|
||||
axum::serve(listener, app).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_foods(conn: &ConnState) -> rusqlite::Result<Vec<Food>> {
|
||||
fn get_foods(conn: &ConnState) -> anyhow::Result<Vec<Food>> {
|
||||
let conn = conn.lock();
|
||||
let mut stmt = PreparedStatements::get_foods(&conn);
|
||||
let foods: Vec<_> = stmt
|
||||
|
|
@ -252,7 +278,7 @@ fn get_foods(conn: &ConnState) -> rusqlite::Result<Vec<Food>> {
|
|||
Ok(foods)
|
||||
}
|
||||
|
||||
fn get_sum(conn: &Arc<Mutex<Connection>>) -> rusqlite::Result<Sum> {
|
||||
fn get_sum(conn: &Arc<Mutex<Connection>>) -> anyhow::Result<Sum> {
|
||||
let conn = conn.lock();
|
||||
let mut stmt = PreparedStatements::get_sum(&conn);
|
||||
let sum = stmt.query_one((), |row| {
|
||||
|
|
@ -272,22 +298,15 @@ fn get_date() -> String {
|
|||
date
|
||||
}
|
||||
|
||||
async fn root(State(conn): State<ConnState>) -> Result<Html<String>, StatusCode> {
|
||||
let foods = get_foods(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let sum = get_sum(&conn).map_err(|e| {
|
||||
error!(?e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
async fn root(State(conn): State<ConnState>) -> Result<Html<String>, AppError> {
|
||||
let foods = get_foods(&conn)?;
|
||||
let sum = get_sum(&conn)?;
|
||||
let date = get_date();
|
||||
let index = IndexTemplate { foods, sum, date };
|
||||
Ok(Html(
|
||||
index
|
||||
.render()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||
))
|
||||
Ok(Html(index.render()?))
|
||||
}
|
||||
|
||||
fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
||||
fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
||||
let conn = conn.lock();
|
||||
let mut stmt = PreparedStatements::increase(&conn);
|
||||
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
||||
|
|
@ -295,7 +314,7 @@ fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<Food> {
|
||||
fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<Food> {
|
||||
let conn = conn.lock();
|
||||
let mut stmt = PreparedStatements::get_food(&conn);
|
||||
let food = stmt.query_one((id,), Food::from_row)?;
|
||||
|
|
@ -306,20 +325,16 @@ fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<Food> {
|
|||
async fn increase(
|
||||
State(conn): State<Arc<Mutex<Connection>>>,
|
||||
Path(id): Path<i32>,
|
||||
) -> Result<Html<String>, StatusCode> {
|
||||
do_increase(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
) -> Result<Html<String>, AppError> {
|
||||
do_increase(&conn, id)?;
|
||||
let food = get_food(&conn, id)?;
|
||||
let sum = get_sum(&conn)?;
|
||||
let date = get_date();
|
||||
let update = FoodUpdateTemplate { food, sum, date };
|
||||
Ok(Html(
|
||||
update
|
||||
.render()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||
))
|
||||
Ok(Html(update.render()?))
|
||||
}
|
||||
|
||||
fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
||||
fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
||||
let conn = conn.lock();
|
||||
let mut stmt = PreparedStatements::decrease(&conn);
|
||||
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
||||
|
|
@ -330,20 +345,16 @@ fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
|||
async fn decrease(
|
||||
State(conn): State<Arc<Mutex<Connection>>>,
|
||||
Path(id): Path<i32>,
|
||||
) -> Result<Html<String>, StatusCode> {
|
||||
do_decrease(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
) -> Result<Html<String>, AppError> {
|
||||
do_decrease(&conn, id)?;
|
||||
let food = get_food(&conn, id)?;
|
||||
let sum = get_sum(&conn)?;
|
||||
let date = get_date();
|
||||
let update = FoodUpdateTemplate { food, sum, date };
|
||||
Ok(Html(
|
||||
update
|
||||
.render()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||
))
|
||||
Ok(Html(update.render()?))
|
||||
}
|
||||
|
||||
fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> rusqlite::Result<()> {
|
||||
fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> anyhow::Result<()> {
|
||||
let conn = conn.lock();
|
||||
let mut stmt = PreparedStatements::set(&conn);
|
||||
let new: i32 = stmt.query_one((id, amount), |row| row.get(0))?;
|
||||
|
|
@ -354,15 +365,11 @@ fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> rusqlite::Resu
|
|||
async fn set(
|
||||
State(conn): State<Arc<Mutex<Connection>>>,
|
||||
Path((id, amount)): Path<(i32, i32)>,
|
||||
) -> Result<Html<String>, StatusCode> {
|
||||
do_set(&conn, id, amount).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
) -> Result<Html<String>, AppError> {
|
||||
do_set(&conn, id, amount)?;
|
||||
let food = get_food(&conn, id)?;
|
||||
let sum = get_sum(&conn)?;
|
||||
let date = get_date();
|
||||
let update = FoodUpdateTemplate { food, sum, date };
|
||||
Ok(Html(
|
||||
update
|
||||
.render()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||
))
|
||||
Ok(Html(update.render()?))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue