diff options
Diffstat (limited to 'src/handlers.rs')
| -rw-r--r-- | src/handlers.rs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/handlers.rs b/src/handlers.rs new file mode 100644 index 0000000..3f815a5 --- /dev/null +++ b/src/handlers.rs @@ -0,0 +1,94 @@ +use axum::{ + extract::{Query, State}, + http::StatusCode, + response::Json, +}; +use chrono::NaiveTime; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::error::AppError; +use crate::models::{DateQuery, MeasurementData, MeasurementView, Unit}; + +pub async fn index() -> &'static str { + "Hello World!" +} + +pub async fn all(State(pool): State<PgPool>) -> Result<Json<Vec<MeasurementView>>, AppError> { + let rows = sqlx::query_as!( + MeasurementView, + "SELECT id, measured_at, metric_type, value, unit FROM measurement" + ) + .fetch_all(&pool) + .await?; + Ok(Json(rows)) +} + +pub async fn add( + State(pool): State<PgPool>, + Json(data): Json<MeasurementData>, +) -> Result<(StatusCode, Json<Uuid>), AppError> { + let rec = sqlx::query!( + " + INSERT INTO measurement (id, measured_at, metric_type, value, unit) + VALUES ($1, $2, $3, $4, $5) + RETURNING id + ", + Uuid::now_v7(), + data.measured_at, + data.metric_type, + data.value, + data.unit + ) + .fetch_one(&pool) + .await?; + Ok((StatusCode::CREATED, Json(rec.id))) +} + +pub async fn search( + State(pool): State<PgPool>, + Query(date_query): Query<DateQuery>, +) -> Result<Json<Vec<MeasurementView>>, AppError> { + let (from, to) = match (date_query.date, date_query.from, date_query.to) { + (Some(date), None, None) => (Some(date), Some(date)), + (None, from, to) => (from, to), + _ => return Err(AppError::BadRequest), + }; + if from.is_none() && to.is_none() { + return Err(AppError::BadRequest); + } + if let (Some(from), Some(to)) = (from, to) + && from > to + { + return Err(AppError::BadRequest); + } + let start = from.map(|from| from.and_time(NaiveTime::MIN).and_utc()); + let end = match to { + Some(to) => { + let Some(next_day) = to.succ_opt() else { + return Err(AppError::BadRequest); + }; + Some(next_day.and_time(NaiveTime::MIN).and_utc()) + } + None => None, + }; + let rows = sqlx::query_as!( + MeasurementView, + "SELECT id, measured_at, metric_type, value, unit FROM measurement + WHERE ($1::timestamptz IS NULL OR measured_at >= $1) + AND ($2::timestamptz IS NULL OR measured_at < $2)", + start, + end + ) + .fetch_all(&pool) + .await?; + Ok(Json(rows)) +} + +pub async fn units(State(pool): State<PgPool>) -> Result<Json<Vec<Unit>>, AppError> { + Ok(Json( + sqlx::query_scalar("SELECT enum_range(NULL::unit)") + .fetch_one(&pool) + .await?, + )) +} |
