haystack_server/ops/
data.rs1use axum::extract::State;
4use axum::http::HeaderMap;
5use axum::response::{IntoResponse, Response};
6
7use haystack_core::data::{HCol, HDict, HGrid};
8use haystack_core::kinds::{Kind, Number};
9
10use crate::content;
11use crate::error::HaystackError;
12use crate::state::SharedState;
13
14pub async fn handle_export(
16 State(state): State<SharedState>,
17 headers: HeaderMap,
18) -> Result<Response, HaystackError> {
19 let accept = headers
20 .get("Accept")
21 .and_then(|v| v.to_str().ok())
22 .unwrap_or("");
23
24 let grid = state
25 .graph
26 .read(|g| g.to_grid(""))
27 .map_err(|e| HaystackError::internal(format!("export failed: {e}")))?;
28
29 let (encoded, ct) = content::encode_response_grid(&grid, accept)
30 .map_err(|e| HaystackError::internal(format!("encoding error: {e}")))?;
31
32 Ok(([(axum::http::header::CONTENT_TYPE, ct)], encoded).into_response())
33}
34
35pub async fn handle_import(
37 State(state): State<SharedState>,
38 headers: HeaderMap,
39 body: String,
40) -> Result<Response, HaystackError> {
41 let content_type = headers
42 .get("Content-Type")
43 .and_then(|v| v.to_str().ok())
44 .unwrap_or("");
45 let accept = headers
46 .get("Accept")
47 .and_then(|v| v.to_str().ok())
48 .unwrap_or("");
49
50 let request_grid = content::decode_request_grid(&body, content_type)
51 .map_err(|e| HaystackError::bad_request(format!("failed to decode request: {e}")))?;
52
53 let mut count: usize = 0;
54
55 for row in &request_grid.rows {
56 let ref_val = match row.id() {
57 Some(r) => r.val.clone(),
58 None => {
59 continue;
61 }
62 };
63
64 if state.graph.contains(&ref_val) {
65 state.graph.update(&ref_val, row.clone()).map_err(|e| {
67 HaystackError::internal(format!("update failed for {ref_val}: {e}"))
68 })?;
69 } else {
70 state
72 .graph
73 .add(row.clone())
74 .map_err(|e| HaystackError::internal(format!("add failed for {ref_val}: {e}")))?;
75 }
76
77 count += 1;
78 }
79
80 let mut row = HDict::new();
82 row.set("count", Kind::Number(Number::new(count as f64, None)));
83
84 let cols = vec![HCol::new("count")];
85 let result_grid = HGrid::from_parts(HDict::new(), cols, vec![row]);
86
87 let (encoded, ct) = content::encode_response_grid(&result_grid, accept)
88 .map_err(|e| HaystackError::internal(format!("encoding error: {e}")))?;
89
90 Ok(([(axum::http::header::CONTENT_TYPE, ct)], encoded).into_response())
91}