From 67a57fa6221ed9bc6920a881784b308d4f5c3e6e Mon Sep 17 00:00:00 2001 From: batsumaru <> Date: Fri, 16 Oct 2026 15:47:04 +0900 Subject: Add csv export --- src/handlers.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'src/handlers.rs') diff --git a/src/handlers.rs b/src/handlers.rs index 5d31600..7067f3a 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -21,6 +21,40 @@ pub async fn list_measurements( State(pool): State, AppQuery(query): AppQuery, ) -> Result>, AppError> { + Ok(Json(fetch_measurements(&pool, &query).await?)) +} + +pub async fn export_measurements( + State(pool): State, + AppQuery(query): AppQuery, +) -> Result<([(HeaderName, &'static str); 2], Vec), AppError> { + let rows = fetch_measurements(&pool, &query).await?; + let mut writer = csv::WriterBuilder::new() + .has_headers(false) + .from_writer(Vec::new()); + writer.write_record(["id", "measured_at", "metric_type", "value", "unit"])?; + for row in &rows { + writer.serialize(row)?; + } + let csv = writer + .into_inner() + .map_err(|e| csv::Error::from(e.into_error()))?; + Ok(( + [ + (header::CONTENT_TYPE, "text/csv; charset=utf-8"), + ( + header::CONTENT_DISPOSITION, + "attachment; filename=\"measurements.csv\"", + ), + ], + csv, + )) +} + +async fn fetch_measurements( + pool: &PgPool, + query: &ListQuery, +) -> Result, AppError> { let limit = match query.limit { Some(x) if (x > 0) => Some(x), None => None, @@ -52,9 +86,9 @@ pub async fn list_measurements( matches!(query.order, Order::Desc), query.metric_type ) - .fetch_all(&pool) + .fetch_all(pool) .await?; - Ok(Json(rows)) + Ok(rows) } pub async fn create_measurement( -- cgit v1.3