2023-04-01 23:16:36 -04:00
|
|
|
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;
|
2022-07-17 17:04:48 -04:00
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
// use rocket::fairing::{self, AdHoc};
|
2022-07-17 17:04:48 -04:00
|
|
|
|
2022-07-18 01:14:35 -04:00
|
|
|
use crate::place::Place;
|
2023-04-01 23:16:36 -04:00
|
|
|
type Result<T, E = (StatusCode, String)> = std::result::Result<T, E>;
|
2022-07-17 17:04:48 -04:00
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
fn internal_error<E>(err: E) -> (StatusCode, String)
|
|
|
|
|
where
|
|
|
|
|
E: std::error::Error,
|
|
|
|
|
{
|
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
|
|
|
|
|
}
|
2022-07-17 17:04:48 -04:00
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
async fn get_places(State(pool): State<SqlitePool>) -> Result<Json<Vec<Place>>> {
|
|
|
|
|
let places = ::sqlx::query!(
|
2023-03-28 02:01:09 -03:00
|
|
|
"SELECT id, name, address, open_hours, icon, description, url," +
|
2022-08-06 22:21:45 -04:00
|
|
|
r#"longitude as "longitude: f64", latitude as "latitude: f64" FROM places WHERE active = TRUE"#
|
|
|
|
|
)
|
2023-04-01 23:16:36 -04:00
|
|
|
.fetch(&pool)
|
2022-08-06 22:21:45 -04:00
|
|
|
.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,
|
2023-03-28 02:01:09 -03:00
|
|
|
url: p.url,
|
2022-08-06 22:21:45 -04:00
|
|
|
})
|
|
|
|
|
.try_collect::<Vec<_>>()
|
2023-04-01 23:16:36 -04:00
|
|
|
.await.map_err(internal_error)?;
|
2022-07-17 17:04:48 -04:00
|
|
|
|
|
|
|
|
Ok(Json(places))
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
async fn upsert_place(
|
|
|
|
|
State(pool): State<SqlitePool>,
|
|
|
|
|
Json(place): Json<Place>,
|
|
|
|
|
) -> Result<Json<Place>> {
|
2022-07-18 01:14:35 -04:00
|
|
|
if place.id.is_some() {
|
2023-04-01 23:16:36 -04:00
|
|
|
update_place(pool, place).await
|
2022-07-18 01:14:35 -04:00
|
|
|
} else {
|
2023-04-01 23:16:36 -04:00
|
|
|
insert_place(pool, place).await
|
2022-07-18 01:14:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Id {
|
|
|
|
|
id: i64,
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
async fn insert_place(pool: SqlitePool, mut place: Place) -> Result<Json<Place>> {
|
2022-07-18 01:14:35 -04:00
|
|
|
let i = ::sqlx::query_as!(
|
|
|
|
|
Id,
|
2023-03-28 02:01:09 -03:00
|
|
|
"INSERT INTO places (name, address, open_hours, icon, description, longitude, latitude, url)\
|
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)\
|
2022-07-18 01:14:35 -04:00
|
|
|
RETURNING id",
|
2022-07-17 17:04:48 -04:00
|
|
|
place.name,
|
|
|
|
|
place.address,
|
|
|
|
|
place.open_hours,
|
|
|
|
|
place.icon,
|
|
|
|
|
place.description,
|
|
|
|
|
place.longitude,
|
2023-03-28 02:01:09 -03:00
|
|
|
place.latitude,
|
|
|
|
|
place.url
|
2022-07-17 17:04:48 -04:00
|
|
|
)
|
2023-04-01 23:16:36 -04:00
|
|
|
.fetch_one(&pool)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(internal_error)?;
|
2022-07-17 17:04:48 -04:00
|
|
|
|
2022-07-18 01:14:35 -04:00
|
|
|
place.id = Some(i.id);
|
2023-04-01 23:16:36 -04:00
|
|
|
Ok(Json(place))
|
2022-07-17 17:04:48 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
async fn update_place(pool: SqlitePool, place: Place) -> Result<Json<Place>> {
|
2022-07-18 01:14:35 -04:00
|
|
|
let result = ::sqlx::query!(
|
2023-03-28 02:01:09 -03:00
|
|
|
"UPDATE places SET (name, address, open_hours, icon, description, longitude, latitude, url) = (?, ?, ?, ?, ?, ?, ?, ?) WHERE id = ?",
|
2022-07-18 01:14:35 -04:00
|
|
|
place.name,
|
|
|
|
|
place.address,
|
|
|
|
|
place.open_hours,
|
|
|
|
|
place.icon,
|
|
|
|
|
place.description,
|
|
|
|
|
place.longitude,
|
2022-11-22 22:03:16 -03:00
|
|
|
place.latitude,
|
2023-03-28 02:01:09 -03:00
|
|
|
place.url,
|
2022-11-22 22:03:16 -03:00
|
|
|
place.id,
|
2022-07-18 01:14:35 -04:00
|
|
|
)
|
2023-04-01 23:16:36 -04:00
|
|
|
.execute(&pool)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(internal_error)?;
|
2022-07-18 01:14:35 -04:00
|
|
|
|
|
|
|
|
if result.rows_affected() == 1 {
|
2023-04-01 23:16:36 -04:00
|
|
|
Ok(Json(place))
|
2022-07-18 01:14:35 -04:00
|
|
|
} else {
|
2023-04-01 23:16:36 -04:00
|
|
|
Err((StatusCode::NOT_FOUND, "".to_owned()))
|
2022-07-18 01:14:35 -04:00
|
|
|
}
|
2022-07-17 17:04:48 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
async fn delete_place(State(pool): State<SqlitePool>, Path(id): Path<i64>) -> Result<()> {
|
2022-07-17 17:04:48 -04:00
|
|
|
let result = ::sqlx::query!("UPDATE places SET active = FALSE WHERE id = ?", id)
|
2023-04-01 23:16:36 -04:00
|
|
|
.execute(&pool)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(internal_error)?;
|
2022-07-17 17:04:48 -04:00
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
if result.rows_affected() == 1 {
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
|
Err((StatusCode::NOT_FOUND, "".to_owned()))
|
2022-07-17 17:04:48 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 23:16:36 -04:00
|
|
|
pub fn places_routes(pool: SqlitePool) -> Router {
|
|
|
|
|
Router::new()
|
|
|
|
|
.route("/", get(get_places).put(upsert_place))
|
|
|
|
|
.route("/:id", delete(delete_place))
|
|
|
|
|
.with_state(pool)
|
2022-07-17 17:04:48 -04:00
|
|
|
}
|