Renamed directories

This commit is contained in:
2023-09-22 16:56:57 -04:00
parent 02a4d840e0
commit 9cf92b8c1f
66 changed files with 11 additions and 28 deletions

View File

@@ -0,0 +1,5 @@
mod model;
mod routes;
pub use model::*;
pub use routes::init_routes;

View File

@@ -0,0 +1,108 @@
use crate::db;
use crate::error_handler::ServiceError;
use crate::schema::airports;
use diesel::prelude::*;
// use log::trace;
use postgis_diesel::types::*;
use postgis_diesel::functions::*;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, AsChangeset, Insertable)]
#[diesel(table_name = airports)]
pub struct InsertAirport {
pub icao: String,
pub category: String,
pub full_name: String,
pub elevation_ft: Option<i32>,
pub continent: String,
pub iso_country: String,
pub iso_region: String,
pub municipality: String,
pub gps_code: String,
pub iata_code: String,
pub local_code: String,
pub point: Point
}
#[derive(Serialize, Deserialize, Queryable, QueryableByName)]
#[diesel(table_name = airports)]
pub struct QueryAirport {
pub icao: String,
pub id: i32,
pub category: String,
pub full_name: String,
pub elevation_ft: Option<i32>,
pub continent: String,
pub iso_country: String,
pub iso_region: String,
pub municipality: String,
pub gps_code: String,
pub iata_code: String,
pub local_code: String,
pub point: Point
}
impl QueryAirport {
pub fn get_all(bounds: Option<Polygon<Point>>, category: Option<String>, filter: Option<String>, limit: Option<i32>, page: Option<i32>) -> Result<Vec<Self>, ServiceError> {
let mut conn = db::connection()?;
let limit = match limit {
Some(l) => l,
None => 100
};
let page = match page {
Some(p) => p,
None => 1
};
let mut query = airports::table
.limit(limit as i64)
.into_boxed();
query = query.filter(airports::id.gt(std::cmp::max(1, page - 1) * limit));
if let Some(bounds) = bounds {
query = query.filter(st_contains(bounds, airports::point));
}
if let Some(category) = category {
query = query.filter(airports::category.eq(category));
}
if let Some(filter) = filter {
query = query.filter(airports::icao
.ilike(format!("%{}%", filter))
.or(airports::full_name.ilike(format!("%{}%", filter)))
)
}
// let debug = diesel::debug_query::<diesel::pg::Pg, _>(&query);
// trace!("{}", debug);
let airports: Vec<QueryAirport> = query.order(airports::category.asc()).load::<QueryAirport>(&mut conn)?;
Ok(airports)
}
pub fn find(icao: String) -> Result<Self, ServiceError> {
let mut conn = db::connection()?;
let airport = airports::table.filter(airports::icao.eq(icao)).first(&mut conn)?;
Ok(airport)
}
pub fn create(airport: InsertAirport) -> Result<Self, ServiceError> {
let mut conn = db::connection()?;
let airport = InsertAirport::from(airport);
let airport = diesel::insert_into(airports::table)
.values(airport)
.get_result(&mut conn)?;
Ok(airport)
}
pub fn update(id: i32, airport: InsertAirport) -> Result<Self, ServiceError> {
let mut conn = db::connection()?;
let airport = diesel::update(airports::table)
.filter(airports::id.eq(id))
.set(airport)
.get_result(&mut conn)?;
Ok(airport)
}
pub fn delete(id: i32) -> Result<usize, ServiceError> {
let mut conn = db::connection()?;
let res = diesel::delete(airports::table.filter(airports::id.eq(id))).execute(&mut conn)?;
Ok(res)
}
}

View File

@@ -0,0 +1,157 @@
use crate::{airports::{InsertAirport, QueryAirport}, db::{self, Metadata}};
use actix_web::{delete, get, post, put, web, HttpResponse, HttpRequest};
use log::{error, warn};
use postgis_diesel::types::{Polygon, Point};
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct GetAllParameters {
filter: Option<String>,
bounds: Option<String>,
category: Option<String>,
limit: Option<i32>,
page: Option<i32>
}
#[get("/import")]
async fn import() -> HttpResponse {
db::import_data();
HttpResponse::Ok().body({})
}
#[derive(Serialize, Deserialize)]
pub struct AirportsResponse {
pub data: Vec<QueryAirport>,
pub meta: Metadata
}
#[get("/airports")]
async fn get_all(req: HttpRequest) -> HttpResponse {
let params = web::Query::<GetAllParameters>::from_query(req.query_string()).unwrap();
let polygon: Option<Polygon<Point>> = match &params.bounds {
Some(b) => {
let bounds: Vec<&str> = b.split(",").collect();
if bounds.len() != 4 {
warn!("Expected 4 bounds, received {}: {}", bounds.len(), b);
return HttpResponse::UnprocessableEntity().body(format!("Received {}; expected NE_LAT,NE_LON,SW_LAT,SW_LON", b))
}
let ne_lat = match bounds[0].parse::<f64>() {
Ok(b) => b,
Err(err) => {
warn!("{}", err);
return HttpResponse::UnprocessableEntity().body(format!("{}", err))
}
};
let ne_lon = match bounds[1].parse::<f64>() {
Ok(b) => b,
Err(err) => {
warn!("{}", err);
return HttpResponse::UnprocessableEntity().body(format!("{}", err))
}
};
let sw_lat = match bounds[2].parse::<f64>() {
Ok(b) => b,
Err(err) => {
warn!("{}", err);
return HttpResponse::UnprocessableEntity().body(format!("{}", err))
}
};
let sw_lon = match bounds[3].parse::<f64>() {
Ok(b) => b,
Err(err) => {
warn!("{}", err);
return HttpResponse::UnprocessableEntity().body(format!("{}", err))
}
};
let mut polygon: Polygon<Point> = Polygon::new(Some(4326));
polygon.add_point(Point { x: sw_lon, y: sw_lat, srid: Some(4326) });
polygon.add_point(Point { x: ne_lon, y: sw_lat, srid: Some(4326) });
polygon.add_point(Point { x: ne_lon, y: ne_lat, srid: Some(4326) });
polygon.add_point(Point { x: sw_lon, y: ne_lat, srid: Some(4326) });
polygon.add_point(Point { x: sw_lon, y: sw_lat, srid: Some(4326) });
Some(polygon)
},
None => None
};
let category = match &params.category {
Some(c) => Some(c.to_string()),
None => None
};
let filter = match &params.filter {
Some(f) => Some(f.to_string()),
None => None
};
match web::block(move || QueryAirport::get_all(polygon, category, filter, params.limit, params.page)).await.unwrap() {
Ok(a) => HttpResponse::Ok().json(AirportsResponse {
data: a,
meta: Metadata { page: 0, limit: 0, pages: 0, total: 0 }
}),
Err(err) => {
error!("{}", err);
err.to_http_response()
}
}
}
#[derive(Serialize, Deserialize)]
pub struct AirportResponse {
pub data: QueryAirport,
pub meta: Metadata
}
#[get("/airports/{icao}")]
async fn get(icao: web::Path<String>) -> HttpResponse {
match QueryAirport::find(icao.into_inner()) {
Ok(a) => HttpResponse::Ok().json(AirportResponse {
data: a,
meta: Metadata { page: 0, limit: 0, pages: 0, total: 0 }
}),
Err(err) => {
error!("{}", err);
err.to_http_response()
}
}
}
#[post("/airports")]
async fn create(airport: web::Json<InsertAirport>) -> HttpResponse {
match QueryAirport::create(airport.into_inner()) {
Ok(a) => HttpResponse::Created().json(a),
Err(err) => {
error!("{}", err);
err.to_http_response()
}
}
}
#[put("/airports/{icao}")]
async fn update(icao: web::Path<i32>, airport: web::Json<InsertAirport>) -> HttpResponse {
match QueryAirport::update(icao.into_inner(), airport.into_inner()) {
Ok(a) => HttpResponse::Ok().json(a),
Err(err) => {
error!("{}", err);
err.to_http_response()
}
}
}
#[delete("/airports/{icao}")]
async fn delete(icao: web::Path<i32>) -> HttpResponse {
match QueryAirport::delete(icao.into_inner()) {
Ok(_) => HttpResponse::NoContent().finish(),
Err(err) => {
error!("{}", err);
err.to_http_response()
}
}
}
pub fn init_routes(config: &mut web::ServiceConfig) {
config.service(get_all);
config.service(get);
config.service(create);
config.service(update);
config.service(delete);
config.service(import);
}