From 385b8810682fe9e068f80df531ec0ed3b99fa23d Mon Sep 17 00:00:00 2001 From: nym21 Date: Tue, 11 Feb 2025 23:38:01 +0100 Subject: [PATCH] server: added csv support to api --- server/Cargo.toml | 2 +- server/src/api/mod.rs | 88 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/server/Cargo.toml b/server/Cargo.toml index 4d209cafc..0fe82bc21 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -26,7 +26,7 @@ oxc = { version = "0.49.0", features = ["codegen", "minifier"] } regex = "1.11.1" reqwest = { version = "0.12.12", features = ["blocking", "json"] } serde = { workspace = true } -serde_json = "1.0.138" +serde_json = { version = "1.0.138", features = ["float_roundtrip"] } storable_vec = { workspace = true } struct_iterable = { workspace = true } tokio = { version = "1.43.0", features = ["full"] } diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 725129fa3..44a709288 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -10,6 +10,7 @@ use axum::{ use color_eyre::eyre::eyre; use reqwest::StatusCode; use serde::Deserialize; +use serde_json::Value; use structs::{Format, Index}; use crate::{log_result, traits::HeaderMapExtended}; @@ -84,23 +85,82 @@ fn req_to_response_res( return Err(eyre!("Unknown index")); } - let values = v + let ids = v .to_lowercase() .split(",") - .flat_map(|s| vecs.get(&s.replace("_", "-"))) - .flat_map(|i_to_v| i_to_v.get(indexes.first().unwrap())) - .map(|vec| vec.collect_range(from, to).unwrap()) + .map(|s| (s.to_owned(), vecs.get(&s.replace("_", "-")))) + .filter(|(_, opt)| opt.is_some()) + .map(|(id, vec)| (id, vec.unwrap())) .collect::>(); - if values.len() == 1 { - let values = values.first().unwrap(); - if values.len() == 1 { - let value = values.first().unwrap(); - Ok(Json(value).into_response()) - } else { - Ok(Json(values).into_response()) - } - } else { - Ok(Json(values).into_response()) + if ids.is_empty() { + return Ok(Json(()).into_response()); } + + let values = ids + .iter() + .flat_map(|(_, i_to_v)| i_to_v.get(indexes.first().unwrap())) + .map(|vec| -> storable_vec::Result> { vec.collect_range(from, to) }) + .collect::>>()?; + + if ids.is_empty() { + return Ok(Json(()).into_response()); + } + + let ids_last_i = ids.len() - 1; + + let mut response = match format { + Some(Format::CSV) => { + let mut csv = ids.into_iter().map(|(id, _)| id).collect::>().join(","); + csv.push('\n'); + + let values_len = values.first().unwrap().len(); + + (0..values_len).for_each(|i| { + let mut line = "".to_string(); + values.iter().enumerate().for_each(|(id_i, v)| { + line += &v.get(i).unwrap().to_string(); + if id_i == ids_last_i { + line.push('\n'); + } else { + line.push(','); + } + }); + csv += &line; + }); + + csv.into_response() + } + _ => { + if values.len() == 1 { + let values = values.first().unwrap(); + if values.len() == 1 { + let value = values.first().unwrap(); + Json(value).into_response() + } else { + Json(values).into_response() + } + } else { + Json(values).into_response() + } + } + }; + + let headers = response.headers_mut(); + + headers.insert_cors(); + // headers.insert_last_modified(date_modified); + + match format { + Some(format) => { + headers.insert_content_disposition_attachment(); + match format { + Format::CSV => headers.insert_content_type_text_csv(), + Format::JSON => headers.insert_content_type_application_json(), + } + } + _ => headers.insert_content_type_application_json(), + }; + + Ok(response) }