use axum::extract::{Json, Path, State}; use axum::http::StatusCode; use axum::routing::{delete, get}; use axum::Router; use futures::TryStreamExt; use sqlx::sqlite::SqlitePool; // use rocket::fairing::{self, AdHoc}; use crate::place::Place; type Result = std::result::Result; fn internal_error(err: E) -> (StatusCode, String) where E: std::error::Error, { (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) } async fn get_places(State(pool): State) -> Result>> { let places = ::sqlx::query!( "SELECT id, name, address, open_hours, icon, description, url," + r#"longitude as "longitude: f64", latitude as "latitude: f64" FROM places WHERE active = TRUE"# ) .fetch(&pool) .map_ok(|p| Place { id: Some(p.id), name: p.name, address: p.address, open_hours: p.open_hours, icon: p.icon, description: p.description, latitude: p.latitude, longitude: p.longitude, url: p.url, }) .try_collect::>() .await.map_err(internal_error)?; Ok(Json(places)) } async fn upsert_place( State(pool): State, Json(place): Json, ) -> Result> { if place.id.is_some() { update_place(pool, place).await } else { insert_place(pool, place).await } } struct Id { id: i64, } async fn insert_place(pool: SqlitePool, mut place: Place) -> Result> { let i = ::sqlx::query_as!( Id, "INSERT INTO places (name, address, open_hours, icon, description, longitude, latitude, url)\ VALUES (?, ?, ?, ?, ?, ?, ?, ?)\ RETURNING id", place.name, place.address, place.open_hours, place.icon, place.description, place.longitude, place.latitude, place.url ) .fetch_one(&pool) .await .map_err(internal_error)?; place.id = Some(i.id); Ok(Json(place)) } async fn update_place(pool: SqlitePool, place: Place) -> Result> { let result = ::sqlx::query!( "UPDATE places SET (name, address, open_hours, icon, description, longitude, latitude, url) = (?, ?, ?, ?, ?, ?, ?, ?) WHERE id = ?", place.name, place.address, place.open_hours, place.icon, place.description, place.longitude, place.latitude, place.url, place.id, ) .execute(&pool) .await .map_err(internal_error)?; if result.rows_affected() == 1 { Ok(Json(place)) } else { Err((StatusCode::NOT_FOUND, "".to_owned())) } } async fn delete_place(State(pool): State, Path(id): Path) -> Result<()> { let result = ::sqlx::query!("UPDATE places SET active = FALSE WHERE id = ?", id) .execute(&pool) .await .map_err(internal_error)?; if result.rows_affected() == 1 { Ok(()) } else { Err((StatusCode::NOT_FOUND, "".to_owned())) } } pub fn places_routes(pool: SqlitePool) -> Router { Router::new() .route("/", get(get_places).put(upsert_place)) .route("/:id", delete(delete_place)) .with_state(pool) }