2022-07-17 17:04:48 -04:00
|
|
|
use rocket::fairing::{self, AdHoc};
|
2022-07-18 01:14:35 -04:00
|
|
|
use rocket::response::status::{Accepted, Created, NotFound};
|
2022-07-17 17:04:48 -04:00
|
|
|
use rocket::serde::json::Json;
|
|
|
|
|
use rocket::{Build, Rocket};
|
|
|
|
|
use rocket_db_pools::{Connection, Database};
|
|
|
|
|
|
|
|
|
|
use rocket::futures::stream::TryStreamExt;
|
|
|
|
|
|
2022-07-18 01:14:35 -04:00
|
|
|
use crate::place::Place;
|
2022-07-17 17:04:48 -04:00
|
|
|
type Result<T, E = rocket::response::Debug<sqlx::Error>> = std::result::Result<T, E>;
|
|
|
|
|
|
|
|
|
|
#[derive(Database)]
|
|
|
|
|
#[database("db")]
|
|
|
|
|
struct Db(rocket_db_pools::sqlx::SqlitePool);
|
|
|
|
|
|
|
|
|
|
#[get("/places")]
|
|
|
|
|
async fn get_places(mut db: Connection<Db>) -> Result<Json<Vec<Place>>> {
|
|
|
|
|
let places = rocket_db_pools::sqlx::query!(
|
2022-08-06 22:21:45 -04:00
|
|
|
"SELECT id, name, address, open_hours, icon, description," +
|
|
|
|
|
r#"longitude as "longitude: f64", latitude as "latitude: f64" FROM places WHERE active = TRUE"#
|
|
|
|
|
)
|
|
|
|
|
.fetch(&mut *db)
|
|
|
|
|
.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,
|
|
|
|
|
})
|
|
|
|
|
.try_collect::<Vec<_>>()
|
|
|
|
|
.await?;
|
2022-07-17 17:04:48 -04:00
|
|
|
|
|
|
|
|
Ok(Json(places))
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-18 01:14:35 -04:00
|
|
|
#[derive(Debug, Responder)]
|
|
|
|
|
enum UpsertResponse {
|
|
|
|
|
Created(Created<Json<Place>>),
|
|
|
|
|
Accepted(Accepted<Json<Place>>),
|
|
|
|
|
NotFound(NotFound<Json<Place>>),
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 22:03:16 -03:00
|
|
|
#[put("/places", format = "json", data = "<place>")]
|
2022-07-18 01:14:35 -04:00
|
|
|
async fn upsert_place(db: Connection<Db>, place: Json<Place>) -> Result<UpsertResponse> {
|
|
|
|
|
if place.id.is_some() {
|
|
|
|
|
update_place(db, place).await
|
|
|
|
|
} else {
|
|
|
|
|
insert_place(db, place).await
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Id {
|
|
|
|
|
id: i64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn insert_place(mut db: Connection<Db>, mut place: Json<Place>) -> Result<UpsertResponse> {
|
|
|
|
|
let i = ::sqlx::query_as!(
|
|
|
|
|
Id,
|
|
|
|
|
"INSERT INTO places (name, address, open_hours, icon, description, longitude, latitude)\
|
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)\
|
|
|
|
|
RETURNING id",
|
2022-07-17 17:04:48 -04:00
|
|
|
place.name,
|
|
|
|
|
place.address,
|
|
|
|
|
place.open_hours,
|
|
|
|
|
place.icon,
|
|
|
|
|
place.description,
|
|
|
|
|
place.longitude,
|
|
|
|
|
place.latitude
|
|
|
|
|
)
|
2022-07-18 01:14:35 -04:00
|
|
|
.fetch_one(&mut *db)
|
2022-07-17 17:04:48 -04:00
|
|
|
.await?;
|
|
|
|
|
|
2022-07-18 01:14:35 -04:00
|
|
|
place.id = Some(i.id);
|
|
|
|
|
Ok(UpsertResponse::Created(Created::new("/places").body(place)))
|
2022-07-17 17:04:48 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-18 01:14:35 -04:00
|
|
|
async fn update_place(mut db: Connection<Db>, place: Json<Place>) -> Result<UpsertResponse> {
|
|
|
|
|
let result = ::sqlx::query!(
|
2022-11-22 22:03:16 -03:00
|
|
|
"UPDATE places SET (name, address, open_hours, icon, description, longitude, latitude) = (?, ?, ?, ?, ?, ?, ?) 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,
|
|
|
|
|
place.id,
|
2022-07-18 01:14:35 -04:00
|
|
|
)
|
|
|
|
|
.execute(&mut *db)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if result.rows_affected() == 1 {
|
|
|
|
|
Ok(UpsertResponse::Accepted(Accepted(Some(place))))
|
|
|
|
|
} else {
|
|
|
|
|
Ok(UpsertResponse::NotFound(NotFound(place)))
|
|
|
|
|
}
|
2022-07-17 17:04:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[delete("/places/<id>")]
|
|
|
|
|
async fn delete_place(mut db: Connection<Db>, id: i64) -> Result<Option<()>> {
|
|
|
|
|
let result = ::sqlx::query!("UPDATE places SET active = FALSE WHERE id = ?", id)
|
|
|
|
|
.execute(&mut *db)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
Ok((result.rows_affected() == 1).then(|| ()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
|
|
|
|
match Db::fetch(&rocket) {
|
|
|
|
|
Some(db) => match ::sqlx::migrate!("./migrations").run(&**db).await {
|
|
|
|
|
Ok(_) => Ok(rocket),
|
|
|
|
|
Err(e) => {
|
|
|
|
|
error!("Failed to initialize SQLx database: {}", e);
|
|
|
|
|
Err(rocket)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
None => Err(rocket),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn stage() -> AdHoc {
|
|
|
|
|
AdHoc::on_ignite("SQLx Stage", |rocket| async {
|
|
|
|
|
rocket
|
|
|
|
|
.attach(Db::init())
|
|
|
|
|
.attach(AdHoc::try_on_ignite("SQLx Migrations", run_migrations))
|
2022-07-18 01:14:35 -04:00
|
|
|
.mount("/", routes![upsert_place, get_places, delete_place])
|
2022-07-17 17:04:48 -04:00
|
|
|
})
|
|
|
|
|
}
|