Skip to main content

reinhardt_admin/server/
export.rs

1//! Export operation Server Function
2//!
3//! Provides export operations for admin models.
4
5use crate::adapters::{AdminDatabase, AdminRecord, AdminSite, ExportFormat, ExportResponse};
6use reinhardt_pages::server_fn::{ServerFnError, server_fn};
7use std::sync::Arc;
8
9#[cfg(not(target_arch = "wasm32"))]
10use super::error::MapServerFnError;
11
12/// Export model data in various formats
13///
14/// Exports all records from a model table in the specified format (JSON, CSV, TSV).
15/// Returns the exported data as binary content with appropriate content type and filename.
16///
17/// # Server Function
18///
19/// This function is automatically exposed as an HTTP endpoint by the `#[server_fn]` macro.
20/// AdminSite and AdminDatabase dependencies are automatically injected via the DI system.
21///
22/// # Example
23///
24/// ```ignore
25/// use reinhardt_admin::server::export_data;
26/// use reinhardt_admin::types::ExportFormat;
27///
28/// // Client-side usage (automatically generates HTTP request)
29/// let response = export_data("User".to_string(), ExportFormat::JSON).await?;
30/// println!("Downloaded {}", response.filename);
31/// ```
32#[server_fn(use_inject = true)]
33pub async fn export_data(
34	model_name: String,
35	format: ExportFormat,
36	#[inject] site: Arc<AdminSite>,
37	#[inject] db: Arc<AdminDatabase>,
38) -> Result<ExportResponse, ServerFnError> {
39	let model_admin = site.get_model_admin(&model_name).map_server_fn_error()?;
40	let table_name = model_admin.table_name();
41
42	// Fetch all records (no pagination for export)
43	let results = db
44		.list::<AdminRecord>(table_name, vec![], 0, u64::MAX)
45		.await
46		.map_server_fn_error()?;
47
48	// Serialize based on format
49	let (data, filename, content_type) = match format {
50		ExportFormat::JSON => {
51			let json = serde_json::to_vec_pretty(&results).map_err(|e| {
52				ServerFnError::serialization(format!("JSON serialization failed: {}", e))
53			})?;
54			(
55				json,
56				format!("{}.json", model_name.to_lowercase()),
57				"application/json",
58			)
59		}
60		ExportFormat::CSV => {
61			let mut wtr = csv::Writer::from_writer(vec![]);
62
63			// Write records to CSV
64			for record in results {
65				wtr.serialize(record).map_err(|e| {
66					ServerFnError::serialization(format!("CSV serialization failed: {}", e))
67				})?;
68			}
69
70			let data = wtr
71				.into_inner()
72				.map_err(|e| ServerFnError::serialization(format!("CSV write failed: {}", e)))?;
73
74			(
75				data,
76				format!("{}.csv", model_name.to_lowercase()),
77				"text/csv",
78			)
79		}
80		ExportFormat::TSV => {
81			let mut wtr = csv::WriterBuilder::new()
82				.delimiter(b'\t')
83				.from_writer(vec![]);
84
85			// Write records to TSV
86			for record in results {
87				wtr.serialize(record).map_err(|e| {
88					ServerFnError::serialization(format!("TSV serialization failed: {}", e))
89				})?;
90			}
91
92			let data = wtr
93				.into_inner()
94				.map_err(|e| ServerFnError::serialization(format!("TSV write failed: {}", e)))?;
95
96			(
97				data,
98				format!("{}.tsv", model_name.to_lowercase()),
99				"text/tab-separated-values",
100			)
101		}
102		ExportFormat::Excel => {
103			unimplemented!("Excel export is not yet implemented")
104		}
105		ExportFormat::XML => {
106			unimplemented!("XML export is not yet implemented")
107		}
108	};
109
110	Ok(ExportResponse {
111		data,
112		filename,
113		content_type: content_type.to_string(),
114	})
115}