use axum::extract::Path;
use axum::http::StatusCode;
use axum::{Extension, Form, Json};
use chrono::NaiveDate;
use log::{debug, error};
use serde::{Deserialize, Serialize};
use sqlx::types::Uuid;
use sqlx::{PgPool, Row};
use crate::http::food::Food;
#[derive(Debug, Deserialize, Serialize)]
pub struct FormAddFood {
name: String,
expiration_date: NaiveDate,
}
pub async fn get_food(
db: Extension<PgPool>,
Path(food_id): Path<Uuid>,
) -> Result<Json<Food>, StatusCode> {
debug!("get food: {food_id}");
let response = sqlx::query_as(
r#"
SELECT id, name, expiration_date FROM food
WHERE id = $1::UUID
"#,
)
.bind(food_id.to_string())
.fetch_one(&*db)
.await;
match response {
Ok(food) => Ok(Json(food)),
Err(e) => {
error!("Query error: {e}");
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
}
}
pub async fn list_food(db: Extension<PgPool>) -> Result<Json<Vec<Food>>, StatusCode> {
debug!("Food listed");
let response = sqlx::query(
r#"
SELECT id, name, expiration_date FROM food ORDER BY expiration_date
"#,
)
.fetch_all(&*db)
.await;
match response {
Ok(rows) => {
let mut fridge = Vec::with_capacity(rows.len());
rows.iter().for_each(|r| {
fridge.push(Food::new(
r.get::<Uuid, _>("id"),
r.get::<String, _>("name"),
r.try_get::<NaiveDate, _>("expiration_date")
.unwrap_or(NaiveDate::MAX),
));
});
Ok(Json(fridge))
}
Err(e) => {
error!("Query error: {e}");
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
}
}
pub async fn add_food(db: Extension<PgPool>, Form(form): Form<FormAddFood>) -> StatusCode {
debug!("Food added: {}", form.name.as_str());
let food_name = form.name.as_str();
let expiration_date = form.expiration_date;
let response = sqlx::query(
r#"
INSERT INTO food (name, expiration_date)
VALUES ($1, $2)
RETURNING id, name, expiration_date
"#,
)
.bind(food_name)
.bind(expiration_date)
.fetch_one(&*db)
.await;
match response {
Ok(_) => StatusCode::NO_CONTENT, Err(e) => {
error!("Query error: {e}");
StatusCode::INTERNAL_SERVER_ERROR
}
}
}
pub async fn delete_food(db: Extension<PgPool>, Path(food_id): Path<Uuid>) -> StatusCode {
debug!("Food deleted: {}", food_id);
let response = sqlx::query(
r#"
DELETE FROM "food"
WHERE id = $1::UUID
"#,
)
.bind(food_id)
.execute(&*db)
.await;
match response {
Ok(_) => StatusCode::NO_CONTENT, Err(e) => {
error!("Query error: {e}");
StatusCode::INTERNAL_SERVER_ERROR
}
}
}